diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/validation/valpropertymsg.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/validation/valpropertymsg.directive.js index a34c4aa0cc..181d204336 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/validation/valpropertymsg.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/validation/valpropertymsg.directive.js @@ -288,7 +288,7 @@ function valPropertyMsg(serverValidationManager, localizationService, angularHel "", serverValidationManagerCallback, currentSegment, - { matchPrefix: true } // match property validation path prefix + { matchType: "suffix" } // match property validation path prefix )); } @@ -298,9 +298,7 @@ function valPropertyMsg(serverValidationManager, localizationService, angularHel //when the scope is disposed we need to unsubscribe scope.$on('$destroy', function () { stopWatch(); - for (var u in unsubscribe) { - unsubscribe[u](); - } + unsubscribe.forEach(u => u()); }); onInit(); diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/validation/valserver.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/validation/valserver.directive.js index b9b9b98174..ea6087d4e9 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/validation/valserver.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/validation/valserver.directive.js @@ -13,14 +13,14 @@ function valServer(serverValidationManager) { link: function (scope, element, attr, ctrls) { var modelCtrl = ctrls[0]; - var umbPropCtrl = ctrls.length > 1 ? ctrls[1] : null; + var umbPropCtrl = ctrls[1]; if (!umbPropCtrl) { //we cannot proceed, this validator will be disabled return; } // optional reference to the varaint-content-controller, needed to avoid validation when the field is invariant on non-default languages. - var umbVariantCtrl = ctrls.length > 2 ? ctrls[2] : null; + var umbVariantCtrl = ctrls[2]; var currentProperty = umbPropCtrl.property; var currentCulture = currentProperty.culture; @@ -121,9 +121,7 @@ function valServer(serverValidationManager) { scope.$on('$destroy', function () { stopWatch(); - for (var u in unsubscribe) { - unsubscribe[u](); - } + unsubscribe.forEach(u => u()); }); } }; diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/validation/valservermatch.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/validation/valservermatch.directive.js new file mode 100644 index 0000000000..766f3f6755 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/common/directives/validation/valservermatch.directive.js @@ -0,0 +1,89 @@ + +function valServerMatch(serverValidationManager) { + return { + require: ['form', '^^umbProperty', '?^^umbVariantContent'], + restrict: "A", + scope: { + valServerMatch: "=" + }, + link: function (scope, element, attr, ctrls) { + + var formCtrl = ctrls[0]; + var umbPropCtrl = ctrls[1]; + if (!umbPropCtrl) { + //we cannot proceed, this validator will be disabled + return; + } + + // optional reference to the varaint-content-controller, needed to avoid validation when the field is invariant on non-default languages. + var umbVariantCtrl = ctrls[2]; + + var currentProperty = umbPropCtrl.property; + var currentCulture = currentProperty.culture; + var currentSegment = currentProperty.segment; + + if (umbVariantCtrl) { + //if we are inside of an umbVariantContent directive + + var currentVariant = umbVariantCtrl.editor.content; + + // Lets check if we have variants and we are on the default language then ... + if (umbVariantCtrl.content.variants.length > 1 && (!currentVariant.language || !currentVariant.language.isDefault) && !currentCulture && !currentSegment && !currentProperty.unlockInvariantValue) { + //This property is locked cause its a invariant property shown on a non-default language. + //Therefor do not validate this field. + return; + } + } + + // if we have reached this part, and there is no culture, then lets fallback to invariant. To get the validation feedback for invariant language. + currentCulture = currentCulture || "invariant"; + + var unsubscribe = []; + + //subscribe to the server validation changes + function serverValidationManagerCallback(isValid, propertyErrors, allErrors) { + if (!isValid) { + formCtrl.$setValidity('valServerMatch', false, formCtrl); + } + else { + formCtrl.$setValidity('valServerMatch', true, formCtrl); + } + } + + if (Utilities.isObject(scope.valServerMatch)) { + var allowedKeys = ["contains", "prefix", "suffix"]; + Object.keys(scope.valServerMatch).forEach(k => { + if (allowedKeys.indexOf(k) === -1) { + throw "valServerMatch dictionary keys must be one of " + allowedKeys.join(); + } + + unsubscribe.push(serverValidationManager.subscribe( + scope.valServerMatch[k], + currentCulture, + "", + serverValidationManagerCallback, + currentSegment, + { matchType: k } // specify the match type + )); + + }); + } + else if (Utilities.isString(scope.valServerMatch)) { + unsubscribe.push(serverValidationManager.subscribe( + scope.valServerMatch, + currentCulture, + "", + serverValidationManagerCallback, + currentSegment)); + } + else { + throw "valServerMatch value must be a string or a dictionary"; + } + + scope.$on('$destroy', function () { + unsubscribe.forEach(u => u()); + }); + } + }; +} +angular.module('umbraco.directives.validation').directive("valServerMatch", valServerMatch); diff --git a/src/Umbraco.Web.UI.Client/src/common/services/blockeditormodelobject.service.js b/src/Umbraco.Web.UI.Client/src/common/services/blockeditormodelobject.service.js index 4cd2720216..9259e4bf64 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/blockeditormodelobject.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/blockeditormodelobject.service.js @@ -129,9 +129,9 @@ var prop = tab.properties[p]; // Watch value of property since this is the only value we want to keep synced. - // Do notice that it is not performing a deep watch, meaning that we are only watching primatives and changes directly to the object of property-value. - // But we like to sync non-primative values as well! Yes, and this does happen, just not through this code, but through the nature of JavaScript. - // Non-primative values act as references to the same data and are therefor synced. + // Do notice that it is not performing a deep watch, meaning that we are only watching primitive and changes directly to the object of property-value. + // But we like to sync non-primitive values as well! Yes, and this does happen, just not through this code, but through the nature of JavaScript. + // Non-primitive values act as references to the same data and are therefor synced. blockObject.__watchers.push(isolatedScope.$watch("blockObjects._" + blockObject.key + "." + field + ".variants[0].tabs[" + t + "].properties[" + p + "].value", watcherCreator(blockObject, prop))); // We also like to watch our data model to be able to capture changes coming from other places. diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/blockeditor/blockeditor.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/blockeditor/blockeditor.controller.js index a62b632d38..daded4d9a9 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/blockeditor/blockeditor.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/blockeditor/blockeditor.controller.js @@ -63,8 +63,20 @@ angular.module("umbraco") } } - vm.close = function() { + vm.close = function () { if (vm.model && vm.model.close) { + // TODO: At this stage there could very well have been server errors that have been cleared + // but if we 'close' we are basically cancelling the value changes which means we'd want to cancel + // all of the server errors just cleared. It would be possible to do that but also quite annoying. + // The rudimentary way would be to: + // * Track all cleared server errors here by subscribing to the prefix validation of controls contained here + // * If this is closed, re-add all of those server validation errors + // A more robust way to do this would be to: + // * Add functionality to the serverValidationManager whereby we can remove validation errors and it will + // maintain a copy of the original errors + // * It would have a 'commit' method to commit the removed errors - which we would call in the formHelper.submitForm when it's successful + // * It would have a 'rollback' method to reset the removed errors - which we would call here + // TODO: check if content/settings has changed and ask user if they are sure. vm.model.close(vm.model); } diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/blocklistentryeditors/labelblock/labelblock.editor.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/blocklistentryeditors/labelblock/labelblock.editor.html index 91c8468d2d..90d0f4bcb4 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/blocklistentryeditors/labelblock/labelblock.editor.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/blocklistentryeditors/labelblock/labelblock.editor.html @@ -1,7 +1,10 @@ - + + + diff --git a/src/Umbraco.Web.UI.Client/test/unit/common/services/block-editor-service.spec.js b/src/Umbraco.Web.UI.Client/test/unit/common/services/block-editor-service.spec.js index e0cd2d0c93..7f69f0594e 100644 --- a/src/Umbraco.Web.UI.Client/test/unit/common/services/block-editor-service.spec.js +++ b/src/Umbraco.Web.UI.Client/test/unit/common/services/block-editor-service.spec.js @@ -119,7 +119,7 @@ }); - it('getBlockObject syncs primative values', function (done) { + it('getBlockObject syncs primitive values', function (done) { var propertyModel = angular.copy(propertyModelMock);