Color Picker: Validate uniqueness of selected colors (#20431)
* Added unique color checker to color picker. * Added Unittest for duplicates * optimized for codescene * removed the bump and simplified the function * Fixed behaviour for duplicate checks so unit test passes. A little refactoring. * Adds continue so invalid colors aren't checked for duplicates. --------- Co-authored-by: Andy Butland <abutland73@gmail.com>
This commit is contained in:
@@ -10,8 +10,11 @@ using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Cms.Core.PropertyEditors;
|
||||
|
||||
internal sealed class ColorPickerConfigurationEditor : ConfigurationEditor<ColorPickerConfiguration>
|
||||
internal sealed partial class ColorPickerConfigurationEditor : ConfigurationEditor<ColorPickerConfiguration>
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ColorPickerConfigurationEditor"/> class.
|
||||
/// </summary>
|
||||
public ColorPickerConfigurationEditor(IIOHelper ioHelper, IConfigurationEditorJsonSerializer configurationEditorJsonSerializer)
|
||||
: base(ioHelper)
|
||||
{
|
||||
@@ -19,13 +22,17 @@ internal sealed class ColorPickerConfigurationEditor : ConfigurationEditor<Color
|
||||
items.Validators.Add(new ColorListValidator(configurationEditorJsonSerializer));
|
||||
}
|
||||
|
||||
internal sealed class ColorListValidator : IValueValidator
|
||||
internal sealed partial class ColorListValidator : IValueValidator
|
||||
{
|
||||
private readonly IConfigurationEditorJsonSerializer _configurationEditorJsonSerializer;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ColorListValidator"/> class.
|
||||
/// </summary>
|
||||
public ColorListValidator(IConfigurationEditorJsonSerializer configurationEditorJsonSerializer)
|
||||
=> _configurationEditorJsonSerializer = configurationEditorJsonSerializer;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IEnumerable<ValidationResult> Validate(object? value, string? valueType, object? dataTypeConfiguration, PropertyValidationContext validationContext)
|
||||
{
|
||||
var stringValue = value?.ToString();
|
||||
@@ -46,17 +53,53 @@ internal sealed class ColorPickerConfigurationEditor : ConfigurationEditor<Color
|
||||
|
||||
if (items is null)
|
||||
{
|
||||
yield return new ValidationResult($"The configuration value {stringValue} is not a valid color picker configuration", new[] { "items" });
|
||||
yield return new ValidationResult($"The configuration value {stringValue} is not a valid color picker configuration", ["items"]);
|
||||
yield break;
|
||||
}
|
||||
|
||||
var seen = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||
var duplicates = new List<string>();
|
||||
foreach (ColorPickerConfiguration.ColorPickerItem item in items)
|
||||
{
|
||||
if (Regex.IsMatch(item.Value, "^([0-9a-f]{3}|[0-9a-f]{6})$", RegexOptions.IgnoreCase) == false)
|
||||
if (ColorPattern().IsMatch(item.Value) == false)
|
||||
{
|
||||
yield return new ValidationResult($"The value {item.Value} is not a valid hex color", new[] { "items" });
|
||||
yield return new ValidationResult($"The value {item.Value} is not a valid hex color", ["items"]);
|
||||
continue;
|
||||
}
|
||||
|
||||
var normalized = Normalize(item.Value);
|
||||
if (seen.Add(normalized) is false)
|
||||
{
|
||||
duplicates.Add(normalized);
|
||||
}
|
||||
}
|
||||
|
||||
if (duplicates.Count > 0)
|
||||
{
|
||||
yield return new ValidationResult(
|
||||
$"Duplicate color values are not allowed: {string.Join(", ", duplicates)}",
|
||||
["items"]);
|
||||
}
|
||||
}
|
||||
|
||||
private static string Normalize(string? value)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(value))
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
var normalizedValue = value.Trim().ToLowerInvariant();
|
||||
|
||||
if (normalizedValue.Length == 3)
|
||||
{
|
||||
normalizedValue = $"{normalizedValue[0]}{normalizedValue[0]}{normalizedValue[1]}{normalizedValue[1]}{normalizedValue[2]}{normalizedValue[2]}";
|
||||
}
|
||||
|
||||
return normalizedValue;
|
||||
}
|
||||
|
||||
[GeneratedRegex("^([0-9a-f]{3}|[0-9a-f]{6})$", RegexOptions.IgnoreCase, "en-GB")]
|
||||
private static partial Regex ColorPattern();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,4 +58,24 @@ public class ColorListValidatorTest
|
||||
PropertyValidationContext.Empty());
|
||||
Assert.AreEqual(2, result.Count());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Validates_Color_Vals_Are_Unique()
|
||||
{
|
||||
var validator = new ColorPickerConfigurationEditor.ColorListValidator(ConfigurationEditorJsonSerializer());
|
||||
var result =
|
||||
validator.Validate(
|
||||
new JsonArray(
|
||||
JsonNode.Parse("""{"value": "FFFFFF", "label": "One"}"""),
|
||||
JsonNode.Parse("""{"value": "000000", "label": "Two"}"""),
|
||||
JsonNode.Parse("""{"value": "FF00AA", "label": "Three"}"""),
|
||||
JsonNode.Parse("""{"value": "fff", "label": "Four"}"""),
|
||||
JsonNode.Parse("""{"value": "000000", "label": "Five"}"""),
|
||||
JsonNode.Parse("""{"value": "F0A", "label": "Six"}""")),
|
||||
null,
|
||||
null,
|
||||
PropertyValidationContext.Empty());
|
||||
Assert.AreEqual(1, result.Count());
|
||||
Assert.IsTrue(result.First().ErrorMessage.Contains("ffffff, 000000, ff00aa"));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user