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