diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/umbeditor.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/umbeditor.directive.js index ca56279414..255ebf1e27 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/umbeditor.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/umbeditor.directive.js @@ -10,7 +10,7 @@ angular.module("umbraco.directives") scope: { view: "@", alias: "@", - config: "@", + config: "=", value: "=" }, restrict: 'E', diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/umbproperty.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/umbproperty.directive.js index a0c44a0222..7b34cd3761 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/umbproperty.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/umbproperty.directive.js @@ -7,17 +7,15 @@ angular.module("umbraco.directives") .directive('umbProperty', function (umbPropEditorHelper) { return { scope: { - alias: "@", - label: "@", - description: "@", - hidelabel: "@" + property: "=" }, transclude: true, restrict: 'E', replace: true, templateUrl: 'views/directives/umb-property.html', link: function (scope, element, attrs, ctrl) { - + } + }; }); \ 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 ffc06eb446..aabe7a7ce4 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 @@ -8,16 +8,16 @@ * We will listen for server side validation changes * and when an error is detected for this property we'll show the error message **/ -function valPropertyMsg(serverValidationManager) { +function valPropertyMsg(serverValidationManager) { return { scope: { - currentProperty: "=property" + property: "=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}}
", + /** Our directive requries a reference to a form controller which gets passed in to this parameter @@ -25,8 +25,8 @@ function valPropertyMsg(serverValidationManager) { link: function (scope, element, attrs, formCtrl) { //assign the form control to our isolated scope so we can watch it's values - scope.formCtrl = formCtrl; - + scope.formCtrl = formCtrl; + //if there's any remaining errors in the server validation service then we should show them. var showValidation = serverValidationManager.items.length > 0; var hasError = false; @@ -53,7 +53,7 @@ function valPropertyMsg(serverValidationManager) { hasError = true; //update the validation message if we don't already have one assigned. if (showValidation && scope.errorMsg === "") { - var err = serverValidationManager.getPropertyError(scope.currentProperty, ""); + var err = serverValidationManager.getPropertyError(scope.property.alias, ""); scope.errorMsg = err ? err.errorMsg : "Property has errors"; } } @@ -72,7 +72,7 @@ function valPropertyMsg(serverValidationManager) { scope.$on("saving", function (ev, args) { showValidation = true; if (hasError && scope.errorMsg === "") { - var err = serverValidationManager.getPropertyError(scope.currentProperty, ""); + var err = serverValidationManager.getPropertyError(scope.property.alias, ""); scope.errorMsg = err ? err.errorMsg : "Property has errors"; } else if (!hasError) { @@ -93,7 +93,7 @@ function valPropertyMsg(serverValidationManager) { // 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) { + scope.$watch("property.value", function (newValue) { if (formCtrl.$invalid) { scope.errorMsg = ""; formCtrl.$setValidity('valPropertyMsg', true); @@ -107,7 +107,7 @@ function valPropertyMsg(serverValidationManager) { // It's important to note that we need to subscribe to server validation changes here because we always must // indicate that a content property is invalid at the property level since developers may not actually implement // the correct field validation in their property editors. - serverValidationManager.subscribe(scope.currentProperty, "", function (isValid, propertyErrors, allErrors) { + serverValidationManager.subscribe(scope.property.alias, "", function (isValid, propertyErrors, allErrors) { hasError = !isValid; if (hasError) { //set the error message to the server message @@ -126,7 +126,7 @@ function valPropertyMsg(serverValidationManager) { // 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 () { - serverValidationManager.unsubscribe(scope.currentProperty, ""); + serverValidationManager.unsubscribe(scope.property.alias, ""); }); } }; diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/valregex.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/valregex.directive.js index dbe751ec23..c3b832f17e 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/valregex.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/valregex.directive.js @@ -11,7 +11,14 @@ function valRegex() { restrict: "A", link: function (scope, elm, attrs, ctrl) { - var regex = new RegExp(scope.$eval(attrs.valRegex)); + var regex; + if (scope[attrs.valRegex]) { + regex = new RegExp(scope.$eval(attrs.valRegex)); + } + else { + regex = new RegExp(attrs.valRegex); + } + var patternValidator = function (viewValue) { //NOTE: we don't validate on empty values, use required validator for that 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 2d4733c9f7..fa98ccc572 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 @@ -36,7 +36,7 @@ function valServer(serverValidationManager) { }); //subscribe to the server validation changes - serverValidationManager.subscribe(currentProperty, fieldName, function (isValid, propertyErrors, allErrors) { + serverValidationManager.subscribe(currentProperty.alias, fieldName, function (isValid, propertyErrors, allErrors) { if (!isValid) { ctrl.$setValidity('valServer', false); //assign an error msg property to the current validator @@ -53,7 +53,7 @@ function valServer(serverValidationManager) { // 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 () { - serverValidationManager.unsubscribe(currentProperty, fieldName); + serverValidationManager.unsubscribe(currentProperty.alias, fieldName); }); } }; diff --git a/src/Umbraco.Web.UI.Client/src/common/mocks/resources/_utils.js b/src/Umbraco.Web.UI.Client/src/common/mocks/resources/_utils.js index 38f10fd419..f08acf8cbe 100644 --- a/src/Umbraco.Web.UI.Client/src/common/mocks/resources/_utils.js +++ b/src/Umbraco.Web.UI.Client/src/common/mocks/resources/_utils.js @@ -23,16 +23,17 @@ tabs: [ { label: "Child documents", - id: 1, + id: 1, active: true, - properties: [ - { alias: "list", label: "List", view: "listview", value: "", hideLabel: true } + properties: [ + { alias: "list", label: "List", view: "listview", value: "", hideLabel: true } ] }, { label: "Content", id: 2, properties: [ + { alias: "valTest", label: "Validation test", view: "validationtest", value: "" }, { alias: "bodyText", label: "Body Text", description: "Here you enter the primary article contents", view: "rte", value: "

askjdkasj lasjd

" }, { alias: "textarea", label: "textarea", view: "textarea", value: "ajsdka sdjkds", config: { rows: 4 } }, { alias: "map", label: "Map", view: "googlemaps", value: "37.4419,-122.1419", config: { mapType: "ROADMAP", zoom: 4 } }, diff --git a/src/Umbraco.Web.UI.Client/src/common/services/contenteditinghelper.service.js b/src/Umbraco.Web.UI.Client/src/common/services/contenteditinghelper.service.js index 393c7a1a67..26fe726c0e 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/contenteditinghelper.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/contenteditinghelper.service.js @@ -102,11 +102,11 @@ function contentEditingHelper($location, $routeParams, notificationsService, ser //if it contains 2 '.' then we will wire it up to a property's field if (parts.length > 2) { //add an error with a reference to the field for which the validation belongs too - serverValidationManager.addPropertyError(contentProperty, parts[2], modelState[e][0]); + serverValidationManager.addPropertyError(contentProperty.alias, parts[2], modelState[e][0]); } else { //add a generic error for the property, no reference to a specific field - serverValidationManager.addPropertyError(contentProperty, "", modelState[e][0]); + serverValidationManager.addPropertyError(contentProperty.alias, "", modelState[e][0]); } } } diff --git a/src/Umbraco.Web.UI.Client/src/common/services/servervalidationmgr.service.js b/src/Umbraco.Web.UI.Client/src/common/services/servervalidationmgr.service.js index dac58b58e8..fa3d1e764d 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/servervalidationmgr.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/servervalidationmgr.service.js @@ -28,10 +28,10 @@ function serverValidationManager($timeout) { }); } - function getPropertyErrors(self, contentProperty, fieldName) { + function getPropertyErrors(self, propertyAlias, fieldName) { //find all errors for this property return _.filter(self.items, function (item) { - return (item.propertyAlias === contentProperty.alias && (item.fieldName === fieldName || (fieldName === undefined || fieldName === ""))); + return (item.propertyAlias === propertyAlias && (item.fieldName === fieldName || (fieldName === undefined || fieldName === ""))); }); } @@ -88,14 +88,14 @@ function serverValidationManager($timeout) { * a particular field, otherwise we can only pinpoint that there is an error for a content property, not the * property's specific field. This is used with the val-server directive in which the directive specifies the * field alias to listen for. - * If contentProperty is null, then this subscription is for a field property (not a user defined property). + * If propertyAlias is null, then this subscription is for a field property (not a user defined property). */ - subscribe: function (contentProperty, fieldName, callback) { + subscribe: function (propertyAlias, fieldName, callback) { if (!callback) { return; } - if (contentProperty === null) { + if (propertyAlias === null) { //don't add it if it already exists var exists1 = _.find(callbacks, function (item) { return item.propertyAlias === null && item.fieldName === fieldName; @@ -104,20 +104,20 @@ function serverValidationManager($timeout) { callbacks.push({ propertyAlias: null, fieldName: fieldName, callback: callback }); } } - else if (contentProperty !== undefined) { + else if (propertyAlias !== undefined) { //don't add it if it already exists var exists2 = _.find(callbacks, function (item) { - return item.propertyAlias === contentProperty.alias && item.fieldName === fieldName; + return item.propertyAlias === propertyAlias && item.fieldName === fieldName; }); if (!exists2) { - callbacks.push({ propertyAlias: contentProperty.alias, fieldName: fieldName, callback: callback }); + callbacks.push({ propertyAlias: propertyAlias, fieldName: fieldName, callback: callback }); } } }, - unsubscribe: function(contentProperty, fieldName) { + unsubscribe: function (propertyAlias, fieldName) { - if (contentProperty === null) { + if (propertyAlias === null) { //remove all callbacks for the content field callbacks = _.reject(callbacks, function (item) { @@ -125,11 +125,11 @@ function serverValidationManager($timeout) { }); } - else if (contentProperty !== undefined) { + else if (propertyAlias !== undefined) { //remove all callbacks for the content property callbacks = _.reject(callbacks, function (item) { - return item.propertyAlias === contentProperty.alias && + return item.propertyAlias === propertyAlias && (item.fieldName === fieldName || ((item.fieldName === undefined || item.fieldName === "") && (fieldName === undefined || fieldName === ""))); }); @@ -146,14 +146,14 @@ function serverValidationManager($timeout) { * @function * * @description - * Gets all callbacks that has been registered using the subscribe method for the contentProperty + fieldName combo. + * Gets all callbacks that has been registered using the subscribe method for the propertyAlias + fieldName combo. * This will always return any callbacks registered for just the property (i.e. field name is empty) and for ones with an * explicit field name set. */ - getPropertyCallbacks: function (contentProperty, fieldName) { + getPropertyCallbacks: function (propertyAlias, fieldName) { var found = _.filter(callbacks, function (item) { //returns any callback that have been registered directly against the field and for only the property - return (item.propertyAlias === contentProperty.alias && (item.fieldName === fieldName || (item.fieldName === undefined || item.fieldName === ""))); + return (item.propertyAlias === propertyAlias && (item.fieldName === fieldName || (item.fieldName === undefined || item.fieldName === ""))); }); return found; }, @@ -217,24 +217,24 @@ function serverValidationManager($timeout) { * @description * Adds an error message for the content property */ - addPropertyError: function (contentProperty, fieldName, errorMsg) { - if (!contentProperty) { + addPropertyError: function (propertyAlias, fieldName, errorMsg) { + if (!propertyAlias) { return; } //only add the item if it doesn't exist - if (!this.hasPropertyError(contentProperty, fieldName)) { + if (!this.hasPropertyError(propertyAlias, fieldName)) { this.items.push({ - propertyAlias: contentProperty.alias, + propertyAlias: propertyAlias, fieldName: fieldName, errorMsg: errorMsg }); } //find all errors for this item - var errorsForCallback = getPropertyErrors(this, contentProperty, fieldName); + var errorsForCallback = getPropertyErrors(this, propertyAlias, fieldName); //we should now call all of the call backs registered for this error - var cbs = this.getPropertyCallbacks(contentProperty, fieldName); + var cbs = this.getPropertyCallbacks(propertyAlias, fieldName); //call each callback for this error for (var cb in cbs) { executeCallback(this, errorsForCallback, cbs[cb].callback); @@ -250,14 +250,14 @@ function serverValidationManager($timeout) { * @description * Removes an error message for the content property */ - removePropertyError: function (contentProperty, fieldName) { + removePropertyError: function (propertyAlias, fieldName) { - if (!contentProperty) { + if (!propertyAlias) { return; } //remove the item this.items = _.reject(this.items, function (item) { - return (item.propertyAlias === contentProperty.alias && (item.fieldName === fieldName || (fieldName === undefined || fieldName === ""))); + return (item.propertyAlias === propertyAlias && (item.fieldName === fieldName || (fieldName === undefined || fieldName === ""))); }); }, @@ -302,10 +302,10 @@ function serverValidationManager($timeout) { * @description * Gets the error message for the content property */ - getPropertyError: function (contentProperty, fieldName) { + getPropertyError: function (propertyAlias, fieldName) { var err = _.find(this.items, function (item) { //return true if the property alias matches and if an empty field name is specified or the field name matches - return (item.propertyAlias === contentProperty.alias && (item.fieldName === fieldName || (fieldName === undefined || fieldName === ""))); + return (item.propertyAlias === propertyAlias && (item.fieldName === fieldName || (fieldName === undefined || fieldName === ""))); }); return err; }, @@ -336,10 +336,10 @@ function serverValidationManager($timeout) { * @description * Checks if the content property + field name combo has an error */ - hasPropertyError: function (contentProperty, fieldName) { + hasPropertyError: function (propertyAlias, fieldName) { var err = _.find(this.items, function (item) { //return true if the property alias matches and if an empty field name is specified or the field name matches - return (item.propertyAlias === contentProperty.alias && (item.fieldName === fieldName || (fieldName === undefined || fieldName === ""))); + return (item.propertyAlias === propertyAlias && (item.fieldName === fieldName || (fieldName === undefined || fieldName === ""))); }); return err ? true : false; }, diff --git a/src/Umbraco.Web.UI.Client/src/views/content/content.edit.controller.js b/src/Umbraco.Web.UI.Client/src/views/content/content.edit.controller.js index ad0f47a034..5c99e75dd4 100644 --- a/src/Umbraco.Web.UI.Client/src/views/content/content.edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/content/content.edit.controller.js @@ -8,13 +8,36 @@ */ function ContentEditController($scope, $routeParams, $location, contentResource, notificationsService, angularHelper, serverValidationManager, contentEditingHelper) { + /** adds the custom controls to the generic props tab above the user props */ + function configureGenericPropertiesTab(genericPropsTab, content) { + + genericPropsTab.properties.splice(0, 0, + { + label: 'Created', + description: 'Time this document was created', + value: content.createDate, + view: "readonlyvalue", + config: { filter: 'date', format: 'medium' }, + alias: "umb_createdate" //can't overlap with user defined props!! important for validation. + }, + { + label: 'Updated', + description: 'Time this document was last updated', + value: content.updateDate, + view: "readonlyvalue", + config: { filter: 'date', format: 'medium' }, + alias: "umb_updatedate" //can't overlap with user defined props!! important for validation. + }); + } + if ($routeParams.create) { //we are creating so get an empty content item contentResource.getScaffold($routeParams.id, $routeParams.doctype) .then(function(data) { $scope.contentLoaded = true; $scope.content = data; - $scope.genericPropertiesTab = $.grep($scope.content.tabs, function(e){ return e.id === 0; })[0]; + $scope.genericPropertiesTab = $.grep($scope.content.tabs, function (e) { return e.id === 0; })[0]; + configureGenericPropertiesTab($scope.genericPropertiesTab, $scope.content); }); } else { @@ -24,6 +47,7 @@ function ContentEditController($scope, $routeParams, $location, contentResource, $scope.contentLoaded = true; $scope.content = data; $scope.genericPropertiesTab = $.grep($scope.content.tabs, function(e){ return e.id === 0; })[0]; + configureGenericPropertiesTab($scope.genericPropertiesTab, $scope.content); //in one particular special case, after we've created a new item we redirect back to the edit // route but there might be server validation errors in the collection which we need to display // after the redirect, so we will bind all subscriptions which will show the server validation errors @@ -88,7 +112,7 @@ function ContentEditController($scope, $routeParams, $location, contentResource, }; - $scope.exludeLastTab = function(item) { + $scope.exludeLastTab = function(item, args) { return item.id !== 0; }; } diff --git a/src/Umbraco.Web.UI.Client/src/views/content/edit.html b/src/Umbraco.Web.UI.Client/src/views/content/edit.html index 4b3e1b3f82..32efa8d5bb 100644 --- a/src/Umbraco.Web.UI.Client/src/views/content/edit.html +++ b/src/Umbraco.Web.UI.Client/src/views/content/edit.html @@ -1,97 +1,70 @@ - + - + - - + + -
-
- +
+
+ - -
- + +
+
+
+
- - - + + + + + + - - + + - - + + + + + + - + - - - - + + - - - - - - - - - - - - - - - - -
+
diff --git a/src/Umbraco.Web.UI.Client/src/views/directives/umb-editor.html b/src/Umbraco.Web.UI.Client/src/views/directives/umb-editor.html index cdc2197cfa..168bd5a69a 100644 --- a/src/Umbraco.Web.UI.Client/src/views/directives/umb-editor.html +++ b/src/Umbraco.Web.UI.Client/src/views/directives/umb-editor.html @@ -1,4 +1,3 @@ -
- - +
+
\ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/views/directives/umb-property.html b/src/Umbraco.Web.UI.Client/src/views/directives/umb-property.html index f4d5facb2c..34de8b5807 100644 --- a/src/Umbraco.Web.UI.Client/src/views/directives/umb-property.html +++ b/src/Umbraco.Web.UI.Client/src/views/directives/umb-property.html @@ -1,11 +1,13 @@
-
- +
+ + +
-