diff --git a/src/Umbraco.Core/Models/MediaWithCrops.cs b/src/Umbraco.Core/Models/MediaWithCrops.cs
index ef3205bd9436..fefb4e6b806e 100644
--- a/src/Umbraco.Core/Models/MediaWithCrops.cs
+++ b/src/Umbraco.Core/Models/MediaWithCrops.cs
@@ -1,15 +1,86 @@
+using System;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.PropertyEditors.ValueConverters;
namespace Umbraco.Core.Models
{
///
- /// Model used in Razor Views for rendering
+ /// Represents a media item with local crops.
///
- public class MediaWithCrops
+ ///
+ public class MediaWithCrops : PublishedContentWrapped
{
- public IPublishedContent MediaItem { get; set; }
+ ///
+ /// Gets the media item.
+ ///
+ ///
+ /// The media item.
+ ///
+ [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;
- public ImageCropperValue LocalCrops { get; set; }
+ ///
+ /// Gets the content/media item.
+ ///
+ ///
+ /// The content/media item.
+ ///
+ public IPublishedContent Content => 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 Content { get; }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The content.
+ /// The local crops.
+ public MediaWithCrops(T content, ImageCropperValue localCrops)
+ : base(content, localCrops)
+ {
+ Content = content;
+ }
+
+ ///
+ /// Performs an implicit conversion from to .
+ ///
+ /// The media with crops.
+ ///
+ /// The result of the conversion.
+ ///
+ public static implicit operator T(MediaWithCrops mediaWithCrops) => mediaWithCrops.Content;
}
}
diff --git a/src/Umbraco.Core/PropertyEditors/ImageCropperConfiguration.cs b/src/Umbraco.Core/PropertyEditors/ImageCropperConfiguration.cs
index 2ce6e2ec04b1..855ec76a5a8d 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 2c6ec9b8aa88..f2151778d9ce 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.
@@ -148,46 +148,35 @@ 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)
+ internal ImageCropperValue Merge(ImageCropperValue imageCropperValue)
{
- // 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 incomingCrops = imageCropperValue?.Crops;
+ if (incomingCrops != null)
{
- var crop = crops.FirstOrDefault(x => x.Alias == configuredCrop.Alias);
- if (crop != null)
+ foreach (var incomingCrop in incomingCrops)
{
- // found, apply the height & width
- crop.Width = configuredCrop.Width;
- crop.Height = configuredCrop.Height;
- }
- else
- {
- // not found, add
- crops.Add(new ImageCropperCrop
+ var crop = crops.FirstOrDefault(x => x.Alias == incomingCrop.Alias);
+ if (crop == null)
+ {
+ // Add incoming crop
+ crops.Add(incomingCrop);
+ }
+ else if (crop.Coordinates == null)
{
- Alias = configuredCrop.Alias,
- Width = configuredCrop.Width,
- Height = configuredCrop.Height
- });
+ // Use incoming crop coordinates
+ crop.Coordinates = incomingCrop.Coordinates;
+ }
}
}
- // assume we don't have to remove the crops in value, that
- // are not part of configuration anymore?
-
- Crops = crops;
+ return new ImageCropperValue()
+ {
+ Src = !string.IsNullOrWhiteSpace(Src) ? Src : imageCropperValue?.Src,
+ Crops = crops,
+ FocalPoint = FocalPoint ?? imageCropperValue?.FocalPoint
+ };
}
#region IEquatable
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);
diff --git a/src/Umbraco.Web/ImageCropperTemplateCoreExtensions.cs b/src/Umbraco.Web/ImageCropperTemplateCoreExtensions.cs
index 766cb1e99f91..8773f1bb3990 100644
--- a/src/Umbraco.Web/ImageCropperTemplateCoreExtensions.cs
+++ b/src/Umbraco.Web/ImageCropperTemplateCoreExtensions.cs
@@ -28,9 +28,30 @@ 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("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);
}
///
@@ -53,6 +74,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.
///
@@ -123,7 +149,51 @@ public static string GetCropUrl(
ImageCropRatioMode? ratioMode = null,
bool upScale = true)
{
- if (mediaItem == null) throw new ArgumentNullException("mediaItem");
+ return mediaItem.GetCropUrl(imageUrlGenerator, null, false, 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)
+ {
+ 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,
+ 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(nameof(mediaItem));
var cacheBusterValue = cacheBuster ? mediaItem.UpdateDate.ToFileTimeUtc().ToString(CultureInfo.InvariantCulture) : null;
@@ -132,31 +202,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 from media when required and used
+ if (localCropsOnly == false && (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 +314,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 +459,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..d9218a897410 100644
--- a/src/Umbraco.Web/ImageCropperTemplateExtensions.cs
+++ b/src/Umbraco.Web/ImageCropperTemplateExtensions.cs
@@ -30,7 +30,21 @@ public static class ImageCropperTemplateExtensions
///
public static string GetCropUrl(this IPublishedContent mediaItem, string cropAlias) => ImageCropperTemplateCoreExtensions.GetCropUrl(mediaItem, cropAlias, Current.ImageUrlGenerator);
- public static string GetCropUrl(this IPublishedContent mediaItem, string cropAlias, ImageCropperValue imageCropperValue) => ImageCropperTemplateCoreExtensions.GetCropUrl(mediaItem, cropAlias, Current.ImageUrlGenerator, imageCropperValue);
+ public static string GetCropUrl(this MediaWithCrops mediaWithCrops, string cropAlias) => ImageCropperTemplateCoreExtensions.GetCropUrl(mediaWithCrops, cropAlias, Current.ImageUrlGenerator);
+
+ [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.
@@ -49,6 +63,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 +134,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 +286,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,
diff --git a/src/Umbraco.Web/PropertyEditors/MediaPicker3Configuration.cs b/src/Umbraco.Web/PropertyEditors/MediaPicker3Configuration.cs
index 4c3c6564a5da..1a6a1cde0bbf 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,40 @@ 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;
+
+ if (configuration?.EnableLocalFocalPoint == false)
+ {
+ imageCropperValue.FocalPoint = null;
+ }
+ }
+ }
}
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 f2f055d69821..17907e854689 100644
--- a/src/Umbraco.Web/PropertyEditors/ValueConverters/MediaPickerWithCropsValueConverter.cs
+++ b/src/Umbraco.Web/PropertyEditors/ValueConverters/MediaPickerWithCropsValueConverter.cs
@@ -51,22 +51,27 @@ 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)
{
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()
+ };
+
+ localCrops.ApplyConfiguration(configuration);
+
+ // 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)
{
diff --git a/src/Umbraco.Web/UrlHelperRenderExtensions.cs b/src/Umbraco.Web/UrlHelperRenderExtensions.cs
index 592c88945bae..2c547c841e0e 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,62 +276,42 @@ 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,
- int? width = null,
- int? height = null,
- string cropAlias = null,
- int? quality = null,
- ImageCropMode? imageCropMode = null,
- ImageCropAnchor? imageCropAnchor = null,
- bool preferFocalPoint = false,
- bool useCropDimensions = false,
- string cacheBusterValue = null,
- string furtherOptions = null,
- ImageCropRatioMode? ratioMode = null,
- bool upScale = true,
- bool htmlEncode = true)
+ 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 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, cropAlias: cropAlias, useCropDimensions: true);
+
+ return CreateHtmlString(url, htmlEncode);
}
public static IHtmlString GetCropUrl(this UrlHelper urlHelper,
ImageCropperValue imageCropperValue,
- string cropAlias,
int? width = null,
int? height = null,
+ string cropAlias = null,
int? quality = null,
ImageCropMode? imageCropMode = null,
ImageCropAnchor? imageCropAnchor = null,
bool preferFocalPoint = false,
- bool useCropDimensions = true,
+ bool useCropDimensions = false,
string cacheBusterValue = null,
string furtherOptions = null,
ImageCropRatioMode? ratioMode = null,
bool upScale = true,
bool htmlEncode = true)
{
- if (imageCropperValue == null) return EmptyHtmlString;
+ if (imageCropperValue == null || string.IsNullOrEmpty(imageCropperValue.Src)) 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