diff --git a/src/Umbraco.Core/PropertyEditors/TextboxConfigurationEditor.cs b/src/Umbraco.Core/PropertyEditors/TextboxConfigurationEditor.cs index f9cfcf01dd8c..e9b2d5ee7f81 100644 --- a/src/Umbraco.Core/PropertyEditors/TextboxConfigurationEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/TextboxConfigurationEditor.cs @@ -1,7 +1,8 @@ -// Copyright (c) Umbraco. +// Copyright (c) Umbraco. // See LICENSE for more details. using Umbraco.Cms.Core.IO; +using Umbraco.Cms.Core.PropertyEditors.Validators; namespace Umbraco.Cms.Core.PropertyEditors; @@ -10,8 +11,17 @@ namespace Umbraco.Cms.Core.PropertyEditors; /// public class TextboxConfigurationEditor : ConfigurationEditor { + /// + /// Initializes a new instance of the class. + /// public TextboxConfigurationEditor(IIOHelper ioHelper) : base(ioHelper) { + const int MinChars = 1; + const int MaxChars = 512; + Fields.Add(new ConfigurationField(new IntegerValidator(MinChars, MaxChars)) + { + Key = "maxChars", + }); } } diff --git a/src/Umbraco.Core/PropertyEditors/Validators/IntegerValidator.cs b/src/Umbraco.Core/PropertyEditors/Validators/IntegerValidator.cs index 5027bd69ef07..1bc20377bc53 100644 --- a/src/Umbraco.Core/PropertyEditors/Validators/IntegerValidator.cs +++ b/src/Umbraco.Core/PropertyEditors/Validators/IntegerValidator.cs @@ -5,19 +5,52 @@ namespace Umbraco.Cms.Core.PropertyEditors.Validators; /// -/// A validator that validates that the value is a valid integer +/// A validator that validates that the value is a valid integer. /// public sealed class IntegerValidator : IValueValidator { + private readonly int? _minValue; + private readonly int? _maxValue; + + /// + /// Initializes a new instance of the class. + /// + public IntegerValidator() + { + } + + /// + /// Initializes a new instance of the class with minimum and/or maximum values. + /// + public IntegerValidator(int? minValue, int? maxValue) + { + _minValue = minValue; + _maxValue = maxValue; + } + /// public IEnumerable Validate(object? value, string? valueType, object? dataTypeConfiguration, PropertyValidationContext validationContext) { - if (value != null && value.ToString() != string.Empty) + if (value == null || value.ToString() == string.Empty) { - Attempt result = value.TryConvertTo(); - if (result.Success == false) + yield break; + } + + Attempt result = value.TryConvertTo(); + if (result.Success == false) + { + yield return new ValidationResult("The value " + value + " is not a valid integer", ["value"]); + } + else + { + if (_minValue.HasValue && result.Result < _minValue.Value) + { + yield return new ValidationResult("The value " + value + " is less than the minimum allowed value of " + _minValue.Value, ["value"]); + } + + if (_maxValue.HasValue && result.Result > _maxValue.Value) { - yield return new ValidationResult("The value " + value + " is not a valid integer", new[] { "value" }); + yield return new ValidationResult("The value " + value + " is greater than the maximum allowed value of " + _maxValue.Value, ["value"]); } } } diff --git a/src/Umbraco.Web.UI.Client/src/packages/property-editors/text-box/Umbraco.TextBox.ts b/src/Umbraco.Web.UI.Client/src/packages/property-editors/text-box/Umbraco.TextBox.ts index c67d1a6cf2b1..66766ff4f45c 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/property-editors/text-box/Umbraco.TextBox.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/property-editors/text-box/Umbraco.TextBox.ts @@ -11,8 +11,12 @@ export const manifest: ManifestPropertyEditorSchema = { { alias: 'maxChars', label: 'Maximum allowed characters', - description: 'If empty, 512 character limit', propertyEditorUiAlias: 'Umb.PropertyEditorUi.Integer', + config: [ + { alias: 'min', value: 1 }, + { alias: 'max', value: 512 }, + { alias: 'placeholder', value: '512' }, + ], }, ], defaultData: [ diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/Validators/IntegerValidatorTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/Validators/IntegerValidatorTests.cs new file mode 100644 index 000000000000..c8ba552e897f --- /dev/null +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/Validators/IntegerValidatorTests.cs @@ -0,0 +1,74 @@ +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using NUnit.Framework; +using Umbraco.Cms.Core.Models.Validation; +using Umbraco.Cms.Core.PropertyEditors; +using Umbraco.Cms.Core.PropertyEditors.Validators; + +namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.PropertyEditors.Validators; + +[TestFixture] +public class IntegerValidatorTests +{ + [TestCase(null, true)] + [TestCase("", true)] + [TestCase(" ", false)] + [TestCase("x", false)] + [TestCase("99", true)] + public void Validates_Integer(object? value, bool expectedSuccess) + { + var validator = CreateValidator(); + var result = validator.Validate(value, ValueTypes.Integer, null, PropertyValidationContext.Empty()); + if (expectedSuccess) + { + Assert.IsEmpty(result); + } + else + { + Assert.AreEqual(1, result.Count()); + + var validationResult = result.First(); + Assert.IsTrue(validationResult.ErrorMessage.Contains("is not a valid integer")); + } + } + + public enum RangeResult + { + Success, + BelowMin, + AboveMax, + } + + [TestCase("5", RangeResult.BelowMin)] + [TestCase("10", RangeResult.Success)] + [TestCase("15", RangeResult.Success)] + [TestCase("20", RangeResult.Success)] + [TestCase("25", RangeResult.AboveMax)] + public void Validates_Integer_Within_Range(object? value, RangeResult expectedResult) + { + var validator = CreateValidator(10, 20); + var result = validator.Validate(value, ValueTypes.Integer, null, PropertyValidationContext.Empty()); + if (expectedResult == RangeResult.Success) + { + Assert.IsEmpty(result); + } + else + { + Assert.AreEqual(1, result.Count()); + + var validationResult = result.First(); + if (expectedResult == RangeResult.BelowMin) + { + Assert.IsTrue(validationResult.ErrorMessage.Contains("less than the minimum allowed value")); + } + else if (expectedResult == RangeResult.AboveMax) + { + Assert.IsTrue(validationResult.ErrorMessage.Contains("greater than the maximum allowed value")); + } + } + } + + private static IntegerValidator CreateValidator(int? min = null, int? max = null) => + min.HasValue is false && max.HasValue is false ? new IntegerValidator() : new IntegerValidator(min, max); +}