Improvements to media pickers/crop handling and URL generation (#10529)
This commit is contained in:
@@ -1,15 +1,86 @@
|
||||
using System;
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
using Umbraco.Core.PropertyEditors.ValueConverters;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// Model used in Razor Views for rendering
|
||||
/// Represents a media item with local crops.
|
||||
/// </summary>
|
||||
public class MediaWithCrops
|
||||
/// <seealso cref="Umbraco.Core.Models.PublishedContent.PublishedContentWrapped" />
|
||||
public class MediaWithCrops : PublishedContentWrapped
|
||||
{
|
||||
public IPublishedContent MediaItem { get; set; }
|
||||
/// <summary>
|
||||
/// Gets the media item.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The media item.
|
||||
/// </value>
|
||||
[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; }
|
||||
/// <summary>
|
||||
/// Gets the content/media item.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The content/media item.
|
||||
/// </value>
|
||||
public IPublishedContent Content => Unwrap();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the local crops.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The local crops.
|
||||
/// </value>
|
||||
public ImageCropperValue LocalCrops { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="MediaWithCrops" /> class.
|
||||
/// </summary>
|
||||
/// <param name="content">The content.</param>
|
||||
/// <param name="localCrops">The local crops.</param>
|
||||
public MediaWithCrops(IPublishedContent content, ImageCropperValue localCrops)
|
||||
: base(content)
|
||||
{
|
||||
LocalCrops = localCrops;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a media item with local crops.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the media item.</typeparam>
|
||||
/// <seealso cref="Umbraco.Core.Models.PublishedContent.PublishedContentWrapped" />
|
||||
public class MediaWithCrops<T> : MediaWithCrops
|
||||
where T : IPublishedContent
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the media item.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The media item.
|
||||
/// </value>
|
||||
public new T Content { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="MediaWithCrops{T}" /> class.
|
||||
/// </summary>
|
||||
/// <param name="content">The content.</param>
|
||||
/// <param name="localCrops">The local crops.</param>
|
||||
public MediaWithCrops(T content, ImageCropperValue localCrops)
|
||||
: base(content, localCrops)
|
||||
{
|
||||
Content = content;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs an implicit conversion from <see cref="MediaWithCrops{T}" /> to <see cref="T" />.
|
||||
/// </summary>
|
||||
/// <param name="mediaWithCrops">The media with crops.</param>
|
||||
/// <returns>
|
||||
/// The result of the conversion.
|
||||
/// </returns>
|
||||
public static implicit operator T(MediaWithCrops<T> mediaWithCrops) => mediaWithCrops.Content;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 @@ namespace Umbraco.Core.PropertyEditors
|
||||
public int Height { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
internal static class ImageCropperConfigurationExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Applies the configuration to ensure only valid crops are kept and have the correct width/height.
|
||||
/// </summary>
|
||||
/// <param name="configuration">The configuration.</param>
|
||||
public static void ApplyConfiguration(this ImageCropperValue imageCropperValue, ImageCropperConfiguration configuration)
|
||||
{
|
||||
var crops = new List<ImageCropperCrop>();
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,7 +140,7 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
|
||||
/// Determines whether the value has a specified crop.
|
||||
/// </summary>
|
||||
public bool HasCrop(string alias)
|
||||
=> Crops.Any(x => x.Alias == alias);
|
||||
=> Crops != null && Crops.Any(x => x.Alias == alias);
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the value has a source image.
|
||||
@@ -148,46 +148,35 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
|
||||
public bool HasImage()
|
||||
=> !string.IsNullOrWhiteSpace(Src);
|
||||
|
||||
/// <summary>
|
||||
/// Applies a configuration.
|
||||
/// </summary>
|
||||
/// <remarks>Ensures that all crops defined in the configuration exists in the value.</remarks>
|
||||
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<ImageCropperCrop>();
|
||||
|
||||
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)
|
||||
{
|
||||
Alias = configuredCrop.Alias,
|
||||
Width = configuredCrop.Width,
|
||||
Height = configuredCrop.Height
|
||||
});
|
||||
// Add incoming crop
|
||||
crops.Add(incomingCrop);
|
||||
}
|
||||
else if (crop.Coordinates == null)
|
||||
{
|
||||
// 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
|
||||
|
||||
@@ -82,8 +82,20 @@ namespace Umbraco.Tests.PropertyEditors
|
||||
|
||||
var mediaFileSystem = new MediaFileSystem(Mock.Of<IFileSystem>(), 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<ILogger>(), mediaFileSystem, Mock.Of<IContentSection>(), Mock.Of<IDataTypeService>())) { Id = 1 });
|
||||
new DataType(new ImageCropperPropertyEditor(Mock.Of<ILogger>(), mediaFileSystem, Mock.Of<IContentSection>(), Mock.Of<IDataTypeService>())) { Id = 1, Configuration = imageCropperConfiguration });
|
||||
|
||||
var factory = new PublishedContentTypeFactory(Mock.Of<IPublishedModelFactory>(), new PropertyValueConverterCollection(Array.Empty<IPropertyValueConverter>()), dataTypeService);
|
||||
|
||||
|
||||
@@ -28,9 +28,30 @@ namespace Umbraco.Web
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the crop URL by using only the specified <paramref name="imageCropperValue" />.
|
||||
/// </summary>
|
||||
/// <param name="mediaItem">The media item.</param>
|
||||
/// <param name="imageCropperValue">The image cropper value.</param>
|
||||
/// <param name="cropAlias">The crop alias.</param>
|
||||
/// <param name="imageUrlGenerator">The image URL generator.</param>
|
||||
/// <returns>
|
||||
/// The image crop URL.
|
||||
/// </returns>
|
||||
public static string GetCropUrl(this IPublishedContent mediaItem, ImageCropperValue imageCropperValue, string cropAlias, IImageUrlGenerator imageUrlGenerator)
|
||||
{
|
||||
return mediaItem.GetCropUrl(imageUrlGenerator, imageCropperValue, true, cropAlias: cropAlias, useCropDimensions: true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -53,6 +74,11 @@ namespace Umbraco.Web
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the ImageProcessor URL from the IPublishedContent item.
|
||||
/// </summary>
|
||||
@@ -123,7 +149,51 @@ namespace Umbraco.Web
|
||||
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 @@ namespace Umbraco.Web
|
||||
|
||||
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);
|
||||
|
||||
var mediaCrops = cropperValue as ImageCropperValue;
|
||||
|
||||
if (mediaCrops == null && cropperValue is JObject jobj)
|
||||
{
|
||||
mediaCrops = jobj.ToObject<ImageCropperValue>();
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
//this shouldn't be the case but we'll check
|
||||
var jobj = cropperValue as JObject;
|
||||
if (jobj != null)
|
||||
{
|
||||
stronglyTyped = jobj.ToObject<ImageCropperValue>();
|
||||
return GetCropUrl(
|
||||
mediaItemUrl, imageUrlGenerator, stronglyTyped, width, height, cropAlias, quality, imageCropMode, imageCropAnchor, preferFocalPoint, useCropDimensions,
|
||||
cacheBusterValue, furtherOptions, ratioMode, upScale);
|
||||
}
|
||||
|
||||
//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 @@ namespace Umbraco.Web
|
||||
{
|
||||
cropDataSet = imageCropperValue.DeserializeImageCropperValue();
|
||||
}
|
||||
|
||||
return GetCropUrl(
|
||||
imageUrl, imageUrlGenerator, cropDataSet, width, height, cropAlias, quality, imageCropMode,
|
||||
imageCropAnchor, preferFocalPoint, useCropDimensions, cacheBusterValue, furtherOptions, ratioMode, upScale);
|
||||
@@ -381,10 +459,10 @@ namespace Umbraco.Web
|
||||
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);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,21 @@ namespace Umbraco.Web
|
||||
/// </returns>
|
||||
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);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the crop URL by using only the specified <paramref name="imageCropperValue" />.
|
||||
/// </summary>
|
||||
/// <param name="mediaItem">The media item.</param>
|
||||
/// <param name="imageCropperValue">The image cropper value.</param>
|
||||
/// <param name="cropAlias">The crop alias.</param>
|
||||
/// <returns>
|
||||
/// The image crop URL.
|
||||
/// </returns>
|
||||
public static string GetCropUrl(this IPublishedContent mediaItem, ImageCropperValue imageCropperValue, string cropAlias) => ImageCropperTemplateCoreExtensions.GetCropUrl(mediaItem, imageCropperValue, cropAlias, Current.ImageUrlGenerator);
|
||||
|
||||
/// <summary>
|
||||
/// 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 @@ namespace Umbraco.Web
|
||||
/// </returns>
|
||||
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);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the ImageProcessor URL from the IPublishedContent item.
|
||||
/// </summary>
|
||||
@@ -118,12 +134,21 @@ namespace Umbraco.Web
|
||||
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);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the ImageProcessor URL from the image path.
|
||||
@@ -261,6 +286,12 @@ namespace Umbraco.Web
|
||||
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,
|
||||
|
||||
@@ -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 @@ namespace Umbraco.Web.PropertyEditors
|
||||
public int Height { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
internal static class MediaPicker3ConfigurationExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Applies the configuration to ensure only valid crops are kept and have the correct width/height.
|
||||
/// </summary>
|
||||
/// <param name="configuration">The configuration.</param>
|
||||
public static void ApplyConfiguration(this ImageCropperValue imageCropperValue, MediaPicker3Configuration configuration)
|
||||
{
|
||||
var crops = new List<ImageCropperCrop>();
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,6 +120,7 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters
|
||||
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);
|
||||
|
||||
|
||||
@@ -51,22 +51,27 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters
|
||||
|
||||
var mediaItems = new List<MediaWithCrops>();
|
||||
var dtos = MediaPicker3PropertyEditor.MediaPicker3PropertyValueEditor.Deserialize(inter);
|
||||
var configuration = propertyType.DataType.ConfigurationAs<MediaPicker3Configuration>();
|
||||
|
||||
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)
|
||||
{
|
||||
|
||||
@@ -4,6 +4,7 @@ using System.Linq;
|
||||
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
|
||||
/// </summary>
|
||||
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
|
||||
|
||||
/// <summary>
|
||||
@@ -42,7 +44,17 @@ namespace Umbraco.Web
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -70,7 +82,17 @@ namespace Umbraco.Web
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -150,10 +172,33 @@ namespace Umbraco.Web
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -231,10 +276,18 @@ namespace Umbraco.Web
|
||||
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)
|
||||
{
|
||||
if (imageCropperValue == null || string.IsNullOrEmpty(imageCropperValue.Src)) return EmptyHtmlString;
|
||||
|
||||
var url = imageCropperValue.Src.GetCropUrl(imageCropperValue, cropAlias: cropAlias, useCropDimensions: true);
|
||||
|
||||
return CreateHtmlString(url, htmlEncode);
|
||||
}
|
||||
|
||||
public static IHtmlString GetCropUrl(this UrlHelper urlHelper,
|
||||
@@ -253,41 +306,13 @@ namespace Umbraco.Web
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
/// <summary>
|
||||
|
||||
Reference in New Issue
Block a user