From a07783693644cf085e0ed6e1ad02ff108c049e18 Mon Sep 17 00:00:00 2001 From: Shannon Date: Fri, 28 Jun 2013 12:23:15 +1000 Subject: [PATCH] Implemented the required/regex validation that is applied to PropertyType's on a Document type (this might be temporary if we get around to implementing pre-value overrides). Changed the name from ManifestValueValidator to just ValueValidator and allows for property editors to override the defaults if they need to change how the regex/required validation is processed against the property's value. Have streamlined all of the validation directives to require an FormController which we then listen to. Have removed valBubble as we don't actually need that functionality anymore and this simplfies input elements too. --- .../DelimitedValueValidator.cs | 2 +- .../PropertyEditors/ManifestValidator.cs | 6 +- .../PropertyEditors/RegexValueValidator.cs | 2 +- .../PropertyEditors/RequiredValueValidator.cs | 2 +- .../PropertyEditors/ValidatorsResolver.cs | 6 +- .../PropertyEditors/ValueEditor.cs | 28 ++++++ .../ValueTypeValueValidator.cs | 2 +- ...estValueValidator.cs => ValueValidator.cs} | 82 ++++++++--------- src/Umbraco.Core/Umbraco.Core.csproj | 2 +- .../common/directives/valbubble.directive.js | 37 -------- .../directives/valpropertymsg.directive.js | 89 +++++++++++-------- .../common/directives/valserver.directive.js | 16 ++-- .../common/directives/valsummary.directive.js | 74 --------------- .../directives/valtogglemsg.directive.js | 2 +- .../PropertyEditors/Views/CsvEditor.html | 1 - .../PropertyEditors/Views/PostcodeEditor.html | 3 +- .../PropertyEditors/Views/RegexEditor.html | 3 +- src/Umbraco.Web.UI/umbraco/js/guiFunctions.js | 45 +--------- .../ContentEditing/ContentPropertyDto.cs | 3 +- .../Models/Mapping/BaseContentModelMapper.cs | 2 + .../ContentItemValidationFilterAttribute.cs | 22 ++++- 21 files changed, 168 insertions(+), 261 deletions(-) rename src/Umbraco.Core/PropertyEditors/{ManifestValueValidator.cs => ValueValidator.cs} (93%) delete mode 100644 src/Umbraco.Web.UI.Client/src/common/directives/valbubble.directive.js delete mode 100644 src/Umbraco.Web.UI.Client/src/common/directives/valsummary.directive.js diff --git a/src/Umbraco.Core/PropertyEditors/DelimitedValueValidator.cs b/src/Umbraco.Core/PropertyEditors/DelimitedValueValidator.cs index 411c7c3abe..459038829d 100644 --- a/src/Umbraco.Core/PropertyEditors/DelimitedValueValidator.cs +++ b/src/Umbraco.Core/PropertyEditors/DelimitedValueValidator.cs @@ -11,7 +11,7 @@ namespace Umbraco.Core.PropertyEditors /// A validator that validates a delimited set of values against a common regex /// [ValueValidator("Delimited")] - internal sealed class DelimitedValueValidator : ManifestValueValidator + internal sealed class DelimitedValueValidator : ValueValidator { /// /// Performs the validation diff --git a/src/Umbraco.Core/PropertyEditors/ManifestValidator.cs b/src/Umbraco.Core/PropertyEditors/ManifestValidator.cs index 6fcc86318c..0252bd9abf 100644 --- a/src/Umbraco.Core/PropertyEditors/ManifestValidator.cs +++ b/src/Umbraco.Core/PropertyEditors/ManifestValidator.cs @@ -27,12 +27,12 @@ namespace Umbraco.Core.PropertyEditors [JsonConverter(typeof(JsonToStringConverter))] public string Config { get; set; } - private ManifestValueValidator _validatorInstance; + private ValueValidator _validatorInstance; /// /// Gets the ValueValidator instance /// - internal ManifestValueValidator ValidatorInstance + internal ValueValidator ValidatorInstance { get { @@ -41,7 +41,7 @@ namespace Umbraco.Core.PropertyEditors var val = ValidatorsResolver.Current.GetValidator(Type); if (val == null) { - throw new InvalidOperationException("No " + typeof(ManifestValueValidator) + " could be found for the type name of " + Type); + throw new InvalidOperationException("No " + typeof(ValueValidator) + " could be found for the type name of " + Type); } _validatorInstance = val; } diff --git a/src/Umbraco.Core/PropertyEditors/RegexValueValidator.cs b/src/Umbraco.Core/PropertyEditors/RegexValueValidator.cs index 840a76670b..705db74e84 100644 --- a/src/Umbraco.Core/PropertyEditors/RegexValueValidator.cs +++ b/src/Umbraco.Core/PropertyEditors/RegexValueValidator.cs @@ -9,7 +9,7 @@ namespace Umbraco.Core.PropertyEditors /// A validator that validates that the value against a Regex expression /// [ValueValidator("Regex")] - internal sealed class RegexValueValidator : ManifestValueValidator + internal sealed class RegexValueValidator : ValueValidator { public override IEnumerable Validate(string value, string config, string preValues, PropertyEditor editor) { diff --git a/src/Umbraco.Core/PropertyEditors/RequiredValueValidator.cs b/src/Umbraco.Core/PropertyEditors/RequiredValueValidator.cs index 41fa14d927..7990998d9e 100644 --- a/src/Umbraco.Core/PropertyEditors/RequiredValueValidator.cs +++ b/src/Umbraco.Core/PropertyEditors/RequiredValueValidator.cs @@ -7,7 +7,7 @@ namespace Umbraco.Core.PropertyEditors /// A validator that validates that the value is not null or empty (if it is a string) /// [ValueValidator("Required")] - internal sealed class RequiredValueValidator : ManifestValueValidator + internal sealed class RequiredValueValidator : ValueValidator { public override IEnumerable Validate(string value, string config, string preValues, PropertyEditor editor) { diff --git a/src/Umbraco.Core/PropertyEditors/ValidatorsResolver.cs b/src/Umbraco.Core/PropertyEditors/ValidatorsResolver.cs index 4b1f0b7c28..a23c6a3c2c 100644 --- a/src/Umbraco.Core/PropertyEditors/ValidatorsResolver.cs +++ b/src/Umbraco.Core/PropertyEditors/ValidatorsResolver.cs @@ -8,7 +8,7 @@ namespace Umbraco.Core.PropertyEditors /// /// A resolver to resolve all registered validators /// - internal class ValidatorsResolver : LazyManyObjectsResolverBase + internal class ValidatorsResolver : LazyManyObjectsResolverBase { public ValidatorsResolver(IEnumerable> lazyTypeList) : base(lazyTypeList, ObjectLifetimeScope.Application) @@ -18,7 +18,7 @@ namespace Umbraco.Core.PropertyEditors /// /// Returns the validators /// - public IEnumerable Validators + public IEnumerable Validators { get { return Values; } } @@ -28,7 +28,7 @@ namespace Umbraco.Core.PropertyEditors /// /// /// - public ManifestValueValidator GetValidator(string name) + public ValueValidator GetValidator(string name) { return Values.FirstOrDefault(x => x.TypeName == name); } diff --git a/src/Umbraco.Core/PropertyEditors/ValueEditor.cs b/src/Umbraco.Core/PropertyEditors/ValueEditor.cs index 8bd0434deb..258444ba69 100644 --- a/src/Umbraco.Core/PropertyEditors/ValueEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/ValueEditor.cs @@ -50,6 +50,34 @@ namespace Umbraco.Core.PropertyEditors [JsonProperty("validation")] public IEnumerable Validators { get; set; } + /// + /// Returns the validator used for the required field validation which is specified on the PropertyType + /// + /// + /// This will become legacy as soon as we implement overridable pre-values. + /// + /// The default validator used is the RequiredValueValidator but this can be overridden by property editors + /// if they need to do some custom validation, or if the value being validated is a json object. + /// + internal virtual ValueValidator RequiredValidator + { + get { return new RequiredValueValidator(); } + } + + /// + /// Returns the validator used for the regular expression field validation which is specified on the PropertyType + /// + /// + /// This will become legacy as soon as we implement overridable pre-values. + /// + /// The default validator used is the RegexValueValidator but this can be overridden by property editors + /// if they need to do some custom validation, or if the value being validated is a json object. + /// + internal virtual ValueValidator RegexValidator + { + get { return new RegexValueValidator(); } + } + /// /// Returns the true DataTypeDatabaseType from the string representation ValueType /// diff --git a/src/Umbraco.Core/PropertyEditors/ValueTypeValueValidator.cs b/src/Umbraco.Core/PropertyEditors/ValueTypeValueValidator.cs index 5295b6b92a..5b50ba3ccf 100644 --- a/src/Umbraco.Core/PropertyEditors/ValueTypeValueValidator.cs +++ b/src/Umbraco.Core/PropertyEditors/ValueTypeValueValidator.cs @@ -12,7 +12,7 @@ namespace Umbraco.Core.PropertyEditors /// This is a special validator type that is executed against all property editors no matter if they've defined this validator or not. /// [ValueValidator("ValueType")] - internal sealed class ValueTypeValueValidator : ManifestValueValidator + internal sealed class ValueTypeValueValidator : ValueValidator { public override IEnumerable Validate(string value, string config, string preValues, PropertyEditor editor) { diff --git a/src/Umbraco.Core/PropertyEditors/ManifestValueValidator.cs b/src/Umbraco.Core/PropertyEditors/ValueValidator.cs similarity index 93% rename from src/Umbraco.Core/PropertyEditors/ManifestValueValidator.cs rename to src/Umbraco.Core/PropertyEditors/ValueValidator.cs index e734992501..adc8f90da5 100644 --- a/src/Umbraco.Core/PropertyEditors/ManifestValueValidator.cs +++ b/src/Umbraco.Core/PropertyEditors/ValueValidator.cs @@ -1,42 +1,42 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; - -namespace Umbraco.Core.PropertyEditors -{ - /// - /// A validator used to validate a value based on a validator name defined in a package manifest - /// - internal abstract class ManifestValueValidator - { - protected ManifestValueValidator() - { - var att = this.GetType().GetCustomAttribute(false); - if (att == null) - { - throw new InvalidOperationException("The class " + GetType() + " is not attributed with the " + typeof(ValueValidatorAttribute) + " attribute"); - } - TypeName = att.TypeName; - } - - public string TypeName { get; private set; } - - /// - /// Performs the validation against the value - /// - /// - /// - /// An object that is used to configure the validator. An example could be a regex - /// expression if the validator was a regex validator. This is defined in the manifest along with - /// the definition of the validator. - /// - /// The current pre-values stored for the data type - /// The property editor instance that is being validated - /// - /// Returns a list of validation results. If a result does not have a field name applied to it then then we assume that - /// the validation message applies to the entire property type being validated. If there is a field name applied to a - /// validation result we will try to match that field name up with a field name on the item itself. - /// - public abstract IEnumerable Validate(string value, string config, string preValues, PropertyEditor editor); - } +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; + +namespace Umbraco.Core.PropertyEditors +{ + /// + /// A validator used to validate a value based on a validator name defined in a package manifest + /// + internal abstract class ValueValidator + { + protected ValueValidator() + { + var att = this.GetType().GetCustomAttribute(false); + if (att == null) + { + throw new InvalidOperationException("The class " + GetType() + " is not attributed with the " + typeof(ValueValidatorAttribute) + " attribute"); + } + TypeName = att.TypeName; + } + + public string TypeName { get; private set; } + + /// + /// Performs the validation against the value + /// + /// + /// + /// An object that is used to configure the validator. An example could be a regex + /// expression if the validator was a regex validator. This is defined in the manifest along with + /// the definition of the validator. + /// + /// The current pre-values stored for the data type + /// The property editor instance that is being validated + /// + /// Returns a list of validation results. If a result does not have a field name applied to it then then we assume that + /// the validation message applies to the entire property type being validated. If there is a field name applied to a + /// validation result we will try to match that field name up with a field name on the item itself. + /// + public abstract IEnumerable Validate(string value, string config, string preValues, PropertyEditor editor); + } } \ No newline at end of file diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 1b714f48ad..3581d15a00 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -547,7 +547,7 @@ - + diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/valbubble.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/valbubble.directive.js deleted file mode 100644 index 8068009be2..0000000000 --- a/src/Umbraco.Web.UI.Client/src/common/directives/valbubble.directive.js +++ /dev/null @@ -1,37 +0,0 @@ -/** -* @ngdoc directive -* @name umbraco.directive:valBubble -* @restrict A -* @description This directive will bubble up a notification via an emit event (upwards) - describing the state of the validation element. This is useful for - parent elements to know about child element validation state. -**/ -function valBubble() { - return { - require: ['ngModel', '^form'], - link: function (scope, element, attr, ctrls) { - - if (!attr.name) { - throw "valBubble must be set on an input element that has a 'name' attribute"; - } - - var modelCtrl = ctrls[0]; - var formCtrl = ctrls[1]; - - //watch the current form's validation for the current field name - scope.$watch(formCtrl.$name + "." + modelCtrl.$name + ".$valid", function (isValid, lastValue) { - if (isValid !== undefined) { - //emit an event upwards - scope.$emit("valBubble", { - isValid: isValid, // if the field is valid - element: element, // the element that the validation applies to - expression: this.exp, // the expression that was watched to check validity - scope: scope, // the current scope - formCtrl: formCtrl // the current form controller - }); - } - }); - } - }; -} -angular.module('umbraco.directives').directive("valBubble", valBubble); \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/valpropertymsg.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/valpropertymsg.directive.js index c5dca948b2..3e55b7e762 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/valpropertymsg.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/valpropertymsg.directive.js @@ -4,15 +4,17 @@ * @restrict A * @description This directive is used to control the display of the property level validation message. * We will listen for server side validation changes - * and when an error is detected for this property we'll show the error message and then we need - * to emit the valBubble event so that any parent listening can update it's UI (like the validation summary) + * and when an error is detected for this property we'll show the error message **/ function valPropertyMsg(serverValidationService) { - return { + return { + scope: { + currentProperty: "=property" + }, require: "^form", //require that this directive is contained within an ngForm replace: true, //replace the element with the template restrict: "E", //restrict to element - template: "
{{errorMsg}}
", + template: "
{{errorMsg}}
", /** * @ngdoc function @@ -26,11 +28,9 @@ function valPropertyMsg(serverValidationService) { * @param formCtrl {FormController} Our directive requries a reference to a form controller which gets passed in to this parameter */ link: function (scope, element, attrs, formCtrl) { - - if (!attrs.property) { - throw "the valPropertyMsg requires an attribute 'property' set which equals the current content property object"; - } - var currentProperty = scope.$eval(attrs.property); + + //assign the form control to our isolated scope so we can watch it's values + scope.formCtrl = formCtrl; //flags for use in the below closures var showValidation = false; @@ -39,19 +39,26 @@ function valPropertyMsg(serverValidationService) { //create properties on our custom scope so we can use it in our template scope.errorMsg = ""; - //listen for form validation - scope.$watch(formCtrl.$name + ".$valid", function (isValid, oldValue) { - if (isValid === undefined) { + //listen for error changes + scope.$watch("formCtrl.$error", function () { + if (formCtrl.$valid === undefined) { return; } - if (!isValid) { - //check if it's one of the properties that is invalid in the current content property - if (element.closest(".umb-control-group").find(".ng-invalid").length > 0) { + if (!formCtrl.$valid) { + + //first we need to check if the valPropertyMsg validity is invalid + if (formCtrl.$error.valPropertyMsg && formCtrl.$error.valPropertyMsg.length > 0) { + //since we already have an error we'll just return since this means we've already set the + // hasError and errorMsg properties which occurs below in the serverValidationService.subscribe + return; + } + else if (element.closest(".umb-control-group").find(".ng-invalid").length > 0) { + //check if it's one of the properties that is invalid in the current content property hasError = true; - if (showValidation && scope.errorMsg === "") { - //update the validation message - scope.errorMsg = serverValidationService.getError(currentProperty, ""); + //update the validation message if we don't already have one assigned. + if (showValidation && scope.errorMsg === "") { + scope.errorMsg = serverValidationService.getError(scope.currentProperty, ""); } } else { @@ -63,13 +70,13 @@ function valPropertyMsg(serverValidationService) { hasError = false; scope.errorMsg = ""; } - }); + }, true); //listen for the forms saving event scope.$on("saving", function (ev, args) { showValidation = true; if (hasError && scope.errorMsg === "") { - scope.errorMsg = serverValidationService.getError(currentProperty, ""); + scope.errorMsg = serverValidationService.getError(scope.currentProperty, ""); } else if (!hasError) { scope.errorMsg = ""; @@ -80,45 +87,51 @@ function valPropertyMsg(serverValidationService) { scope.$on("saved", function (ev, args) { showValidation = false; scope.errorMsg = ""; + formCtrl.$setValidity('valPropertyMsg', true); }); + //We need to subscribe to any changes to our model (based on user input) + // This is required because when we have a server error we actually invalidate + // the form which means it cannot be resubmitted. + // So once a field is changed that has a server error assigned to it + // we need to re-validate it for the server side validator so the user can resubmit + // the form. Of course normal client-side validators will continue to execute. + scope.$watch("currentProperty.value", function(newValue) { + if (formCtrl.$invalid) { + scope.errorMsg = ""; + formCtrl.$setValidity('valPropertyMsg', true); + } + }); + //listen for server validation changes // NOTE: we pass in "" in order to listen for all validation changes to the content property, not for // validation changes to fields in the property this is because some server side validators may not // return the field name for which the error belongs too, just the property for which it belongs. - serverValidationService.subscribe(currentProperty, "", function (isValid, propertyErrors, allErrors) { + serverValidationService.subscribe(scope.currentProperty, "", function (isValid, propertyErrors, allErrors) { hasError = !isValid; if (hasError) { //set the error message to the server message - scope.errorMsg = propertyErrors[0].errorMsg; + scope.errorMsg = propertyErrors[0].errorMsg; //now that we've used the server validation message, we need to remove it from the //error collection... it is a 'one-time' usage so that when the field is invalidated //again, the message we display is the client side message. //NOTE: 'this' in the subscribe callback context is the validation manager object. - this.removeError(scope.model); - //emit an event upwards - scope.$emit("valBubble", { - isValid: false, // it is INVALID - element: element, // the element that the validation applies to - scope: scope, // the scope - formCtrl: formCtrl // the current form controller - }); + this.removeError(scope.currentProperty); + //flag that the current validator is invalid + formCtrl.$setValidity('valPropertyMsg', false); } else { scope.errorMsg = ""; - //emit an event upwards - scope.$emit("valBubble", { - isValid: true, // it is VALID - element: element, // the element that the validation applies to - scope: scope, // the scope - formCtrl: formCtrl // the current form controller - }); + //flag that the current validator is valid + formCtrl.$setValidity('valPropertyMsg', true); } }); //when the element is disposed we need to unsubscribe! + // NOTE: this is very important otherwise when this controller re-binds the previous subscriptsion will remain + // but they are a different callback instance than the above. element.bind('$destroy', function () { - serverValidationService.unsubscribe(currentProperty, ""); + serverValidationService.unsubscribe(scope.currentProperty, ""); }); } }; diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/valserver.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/valserver.directive.js index edfb151397..0d8c36f41c 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/valserver.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/valserver.directive.js @@ -22,23 +22,19 @@ function valServer(serverValidationService) { fieldName = attr.valServer; } - //subscribe to the changed event of the element. This is required because when we + //subscribe to the changed event of the view model. This is required because when we // have a server error we actually invalidate the form which means it cannot be // resubmitted. So once a field is changed that has a server error assigned to it // we need to re-validate it for the server side validator so the user can resubmit // the form. Of course normal client-side validators will continue to execute. - element.keydown(function () { + ctrl.$viewChangeListeners.push(function () { if (ctrl.$invalid) { ctrl.$setValidity('valServer', true); + //emit the event upwards + scope.$emit("serverRevalidated", { modelCtrl: ctrl }); } }); - element.change(function () { - if (ctrl.$invalid) { - ctrl.$setValidity('valServer', true); - } - }); - //TODO: DO we need to watch for other changes on the element ? - + //subscribe to the server validation changes serverValidationService.subscribe(currentProperty, fieldName, function (isValid, propertyErrors, allErrors) { if (!isValid) { @@ -54,6 +50,8 @@ function valServer(serverValidationService) { }); //when the element is disposed we need to unsubscribe! + // NOTE: this is very important otherwise when this controller re-binds the previous subscriptsion will remain + // but they are a different callback instance than the above. element.bind('$destroy', function () { serverValidationService.unsubscribe(currentProperty, fieldName); }); diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/valsummary.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/valsummary.directive.js deleted file mode 100644 index 30628cd37f..0000000000 --- a/src/Umbraco.Web.UI.Client/src/common/directives/valsummary.directive.js +++ /dev/null @@ -1,74 +0,0 @@ -/** - * @ngdoc directive - * @name umbraco.directive:valSummary - * @restrict E - * @description This directive will display a validation summary for the current form based on the - content properties of the current content item. - **/ -function valSummary() { - return { - scope: true, // create a new scope for this directive - replace: true, // replace the html element with the template - restrict: "E", // restrict to an element - template: '
  • {{model}}
', - link: function (scope, element, attr, ctrl) { - - //create properties on our custom scope so we can use it in our template - scope.validationSummary = []; - - //create a flag for us to be able to reference in the below closures for watching. - var showValidation = false; - - //add a watch to update our waitingOnValidation flag for use in the below closures - scope.$watch("$parent.ui.waitingOnValidation", function (isWaiting, oldValue) { - showValidation = isWaiting; - if (scope.validationSummary.length > 0 && showValidation) { - element.show(); - } - else { - element.hide(); - } - }); - - //if we are to show field property based errors. - //this requires listening for bubbled events from valBubble directive. - - scope.$parent.$on("valBubble", function (evt, args) { - var msg = "The value assigned for the property " + args.scope.model.label + " is invalid"; - var exists = _.contains(scope.validationSummary, msg); - - //we need to check if the entire property is valid, even though the args says this field is valid there - // may be multiple values attached to a content property. The easiest way to do this is check the DOM - // just like we are doing for the property level validation message. - var propertyHasErrors = args.element.closest(".content-property").find(".ng-invalid").length > 0; - - if (args.isValid && exists && !propertyHasErrors) { - //it is valid but we have a val msg for it so we'll need to remove the message - scope.validationSummary = _.reject(scope.validationSummary, function (item) { - return item === msg; - }); - } - else if (!args.isValid && !exists) { - //it is invalid and we don't have a msg for it already - scope.validationSummary.push(msg); - } - - //show the summary if there are errors and the form has been submitted - if (showValidation && scope.validationSummary.length > 0) { - element.show(); - } - }); - //listen for form invalidation so we know when to hide it - scope.$watch("contentForm.$error", function (errors) { - //check if there is an error and hide the summary if not - var hasError = _.find(errors, function (err) { - return (err.length && err.length > 0); - }); - if (!hasError) { - element.hide(); - } - }, true); - } - }; -} -angular.module('umbraco.directives').directive("valSummary", valSummary); \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/valtogglemsg.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/valtogglemsg.directive.js index a449bc1bb8..7b00bb670e 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/valtogglemsg.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/valtogglemsg.directive.js @@ -12,7 +12,7 @@ function valToggleMsg() { /** * @ngdoc function * @name link - * @methodOf valPropertyMsg + * @methodOf valServer * @function * * @description diff --git a/src/Umbraco.Web.UI/App_Plugins/MyPackage/PropertyEditors/Views/CsvEditor.html b/src/Umbraco.Web.UI/App_Plugins/MyPackage/PropertyEditors/Views/CsvEditor.html index 8ff6a74615..a301800a4d 100644 --- a/src/Umbraco.Web.UI/App_Plugins/MyPackage/PropertyEditors/Views/CsvEditor.html +++ b/src/Umbraco.Web.UI/App_Plugins/MyPackage/PropertyEditors/Views/CsvEditor.html @@ -3,7 +3,6 @@
{{multiFormVal.myPackage_multiVal.errorMsg}} diff --git a/src/Umbraco.Web.UI/App_Plugins/MyPackage/PropertyEditors/Views/PostcodeEditor.html b/src/Umbraco.Web.UI/App_Plugins/MyPackage/PropertyEditors/Views/PostcodeEditor.html index 9a5a5f05b8..93aecdfa1e 100644 --- a/src/Umbraco.Web.UI/App_Plugins/MyPackage/PropertyEditors/Views/PostcodeEditor.html +++ b/src/Umbraco.Web.UI/App_Plugins/MyPackage/PropertyEditors/Views/PostcodeEditor.html @@ -4,8 +4,7 @@

+ val-postcode="model.config.country"/> {{propertyForm.myPackage_postcode.errorMsg}} {{propertyForm.myPackage_postcode.errorMsg}} diff --git a/src/Umbraco.Web.UI/App_Plugins/MyPackage/PropertyEditors/Views/RegexEditor.html b/src/Umbraco.Web.UI/App_Plugins/MyPackage/PropertyEditors/Views/RegexEditor.html index 6397d5dab4..8e4304fbc2 100644 --- a/src/Umbraco.Web.UI/App_Plugins/MyPackage/PropertyEditors/Views/RegexEditor.html +++ b/src/Umbraco.Web.UI/App_Plugins/MyPackage/PropertyEditors/Views/RegexEditor.html @@ -7,8 +7,7 @@ type="text" ng-model="model.value" required val-regex="model.config" - val-server="value" - val-bubble /> + val-server="value" /> Required! {{propertyForm.regex.errorMsg}} diff --git a/src/Umbraco.Web.UI/umbraco/js/guiFunctions.js b/src/Umbraco.Web.UI/umbraco/js/guiFunctions.js index 60a5acf497..2a802dce31 100644 --- a/src/Umbraco.Web.UI/umbraco/js/guiFunctions.js +++ b/src/Umbraco.Web.UI/umbraco/js/guiFunctions.js @@ -23,7 +23,6 @@ function toggleTree(sender) { } function resizePage(sender) { -// alert(jQuery(window) + ", " + sender); var dashboard = jQuery("#rightDIV"); var dashboardFrame = jQuery("#right"); var tree = jQuery("#leftDIV"); @@ -63,51 +62,11 @@ function resizePage(sender) { treeToggle.show(); uiArea.show(); } - - /* - var dashboard = document.getElementById("rightDIV"); - var dashboardFrame = document.getElementById("right"); - var tree = document.getElementById("leftDIV"); - var appIcons = document.getElementById("PlaceHolderAppIcons"); - var uiArea = document.getElementById("uiArea"); - - var clientHeight = getViewportHeight() - 48; - var clientWidth = getViewportWidth(); - - var leftWidth = parseInt(clientWidth * 0.25); - var rightWidth = clientWidth - leftWidth - 35; // parseInt(clientWidth*0.65); - - - // check if appdock is present - var treeHeight = parseInt(clientHeight-5); - - if (appIcons != null) { - treeHeight = treeHeight - 135; - resizeGuiWindow("PlaceHolderAppIcons", leftWidth, 140); - } - - resizeGuiWindow("treeWindow", leftWidth, treeHeight) - - if (tree.style.display == "none") { - var frameWidth = getViewportWidth() - 24; - dashboard.style.width = frameWidth + "px"; - } else if (rightWidth > 0) { - dashboard.style.width = rightWidth + "px"; - } - if (clientHeight > 0) { - dashboard.style.height = (clientHeight) + "px"; - //dashboardFrame.style.height = (clientHeight) + "px"; - - document.getElementById('treeToggle').style.height = (clientHeight) + "px"; - } - document.getElementById('treeToggle').style.visibility = "visible"; - - uiArea.style.visibility = "visible"; - */ + } function resizeGuiWindow(windowName, newWidth, newHeight, window) { - resizePanelTo(windowName, false, newWidth, newHeight); + //This no longer does anything and shouldn't be used. } function resizeGuiWindowWithTabs(windowName, newWidth, newHeight) { diff --git a/src/Umbraco.Web/Models/ContentEditing/ContentPropertyDto.cs b/src/Umbraco.Web/Models/ContentEditing/ContentPropertyDto.cs index e16cbb3d2f..42782b1b14 100644 --- a/src/Umbraco.Web/Models/ContentEditing/ContentPropertyDto.cs +++ b/src/Umbraco.Web/Models/ContentEditing/ContentPropertyDto.cs @@ -11,8 +11,9 @@ namespace Umbraco.Web.Models.ContentEditing { public IDataTypeDefinition DataType { get; set; } public string Label { get; set; } - public string Alias { get; set; } public string Description { get; set; } public PropertyEditor PropertyEditor { get; set; } + public bool IsRequired { get; set; } + public string ValidationRegExp { get; set; } } } \ No newline at end of file diff --git a/src/Umbraco.Web/Models/Mapping/BaseContentModelMapper.cs b/src/Umbraco.Web/Models/Mapping/BaseContentModelMapper.cs index add6c5a15b..f870871e87 100644 --- a/src/Umbraco.Web/Models/Mapping/BaseContentModelMapper.cs +++ b/src/Umbraco.Web/Models/Mapping/BaseContentModelMapper.cs @@ -25,6 +25,8 @@ namespace Umbraco.Web.Models.Mapping { return CreateContent, ContentPropertyDto, TPersisted>(content, null, (propertyDto, originalProperty, propEditor) => { + propertyDto.IsRequired = originalProperty.PropertyType.Mandatory; + propertyDto.ValidationRegExp = originalProperty.PropertyType.ValidationRegExp; propertyDto.Alias = originalProperty.Alias; propertyDto.Description = originalProperty.PropertyType.Description; propertyDto.Label = originalProperty.PropertyType.Name; diff --git a/src/Umbraco.Web/WebApi/Filters/ContentItemValidationFilterAttribute.cs b/src/Umbraco.Web/WebApi/Filters/ContentItemValidationFilterAttribute.cs index 9f05e58cc0..58a8c7a275 100644 --- a/src/Umbraco.Web/WebApi/Filters/ContentItemValidationFilterAttribute.cs +++ b/src/Umbraco.Web/WebApi/Filters/ContentItemValidationFilterAttribute.cs @@ -5,6 +5,7 @@ using System.Net; using System.Net.Http; using System.Web.Http.Controllers; using System.Web.Http.Filters; +using System.Web.UI; using Umbraco.Core; using Umbraco.Core.Logging; using Umbraco.Core.Models; @@ -88,7 +89,6 @@ namespace Umbraco.Web.WebApi.Filters return true; } - //TODO: Validate the property type data private bool ValidateData(ContentItemBasic postedItem, HttpActionContext actionContext) { foreach (var p in postedItem.ContentDto.Properties) @@ -135,6 +135,26 @@ namespace Umbraco.Web.WebApi.Filters } } } + + //Now we need to validate the property based on the PropertyType validation (i.e. regex and required) + // NOTE: These will become legacy once we have pre-value overrides. + if (p.IsRequired) + { + foreach (var result in p.PropertyEditor.ValueEditor.RequiredValidator.Validate(postedValue, "", preValues, editor)) + { + //add a model state error for the entire property + actionContext.ModelState.AddModelError(p.Alias, result.ErrorMessage); + } + } + + if (!p.ValidationRegExp.IsNullOrWhiteSpace()) + { + foreach (var result in p.PropertyEditor.ValueEditor.RegexValidator.Validate(postedValue, p.ValidationRegExp, preValues, editor)) + { + //add a model state error for the entire property + actionContext.ModelState.AddModelError(p.Alias, result.ErrorMessage); + } + } } //create the response if there any errors