Temp8 validation fixing (#2699)

* Showing notifications if any for any response with status 400 >= x < 500.

* fixes valFormManager

* Updates logic for the valpropertymsg.directive to simplify it and so that it doesn't need to query the DOM which was causing issues with timing.

* commits package-lock

* fixes some issues with the securityinterceptor, properly nests promises in contentEditingHelper, fixes errors occuring when not handling promise rejections due to validation problems,

* another unhandled potential validation problem

* Merge branch 'temp-U4-7757' of https://github.com/lars-erik/Umbraco-CMS into lars-erik-temp-U4-7757

# Conflicts:
#	src/Umbraco.Web.UI.Client/src/common/services/umbrequesthelper.service.js

* cleans up the interceptor objects and puts them in appropriate modules and files, centralizes the logic to show notifications so that only happens in one place.

* Fixes more places where notifications were manually shown.

* Fixes validation with the variant publishing overlay and html descrepencies
This commit is contained in:
Shannon Deminick
2018-06-15 10:33:16 +10:00
committed by GitHub
parent 4708293b18
commit 80c585c21e
61 changed files with 4852 additions and 1714 deletions

View File

@@ -79,7 +79,7 @@ var sources = {
filters: { files: ["src/common/filters/**/*.js"], out: "umbraco.filters.js" },
resources: { files: ["src/common/resources/**/*.js"], out: "umbraco.resources.js" },
services: { files: ["src/common/services/**/*.js"], out: "umbraco.services.js" },
security: { files: ["src/common/security/**/*.js"], out: "umbraco.security.js" }
security: { files: ["src/common/interceptors/**/*.js"], out: "umbraco.interceptors.js" }
},
//selectors for copying all views into the build
@@ -406,4 +406,4 @@ gulp.task('test:e2e', function() {
keepalive: true
})
.start();
});
});

File diff suppressed because it is too large Load Diff

View File

@@ -7,7 +7,7 @@ LazyLoad.js([
'../js/app.js',
'../js/umbraco.resources.js',
'../js/umbraco.services.js',
'../js/umbraco.security.js',
'../js/umbraco.interceptors.js',
'../ServerVariables',
'../lib/signalr/jquery.signalR.js',
'/umbraco/BackOffice/signalr/hubs',

View File

@@ -286,7 +286,7 @@
contentResource.unPublish($scope.content.id, culture)
.then(function (data) {
formHelper.resetForm({ scope: $scope, notifications: data.notifications });
formHelper.resetForm({ scope: $scope });
contentEditingHelper.handleSuccessfulSave({
scope: $scope,
@@ -301,7 +301,6 @@
$scope.page.buttonGroupState = "success";
}, function (err) {
formHelper.showNotifications(err.data);
$scope.page.buttonGroupState = 'error';
});
}
@@ -367,12 +366,12 @@
}
}
else {
return performSave({ saveMethod: contentResource.publish, action: "publish" });
return performSave({ saveMethod: contentResource.publish, action: "publish" }).catch(angular.noop);;
}
};
$scope.save = function () {
return performSave({ saveMethod: $scope.saveMethod(), action: "save" });
return performSave({ saveMethod: $scope.saveMethod(), action: "save" }).catch(angular.noop);
};
$scope.preview = function (content) {
@@ -396,7 +395,7 @@
else {
$scope.save().then(function (data) {
previewWindow.location.href = redirect;
});
}).catch(angular.noop);
}
}
};

View File

@@ -14,7 +14,7 @@ angular.module("umbraco.directives.html")
labelFor: "@",
required: "@?"
},
require: '?^form',
require: '?^^form',
transclude: true,
restrict: 'E',
replace: true,

View File

@@ -15,7 +15,7 @@ var _umbPropertyEditor = function (umbPropEditorHelper) {
preview: "@"
},
require: "^form",
require: "^^form",
restrict: 'E',
replace: true,
templateUrl: 'views/components/property/umb-property-editor.html',
@@ -37,4 +37,4 @@ var _umbPropertyEditor = function (umbPropEditorHelper) {
};
};
angular.module("umbraco.directives").directive('umbPropertyEditor', _umbPropertyEditor);
angular.module("umbraco.directives").directive('umbPropertyEditor', _umbPropertyEditor);

View File

@@ -25,7 +25,7 @@
}
var directive = {
require: "^form",
require: "^^form",
restrict: 'A',
link: link
};

View File

@@ -1,7 +1,7 @@
angular.module('umbraco.directives.validation')
.directive('valCompare',function () {
return {
require: ["ngModel", "^form"],
require: ["ngModel", "^^form"],
link: function (scope, elem, attrs, ctrls) {
var ctrl = ctrls[0];
@@ -23,4 +23,4 @@ angular.module('umbraco.directives.validation')
});
}
};
});
});

View File

@@ -13,6 +13,11 @@
* be marked with the 'error' css class. This ensures that labels included in that control group are styled correctly.
**/
function valFormManager(serverValidationManager, $rootScope, $log, $timeout, notificationsService, eventsService, $routeParams) {
var SHOW_VALIDATION_CLASS_NAME = "show-validation";
var SAVING_EVENT_NAME = "formSubmitting";
var SAVED_EVENT_NAME = "formSubmitted";
return {
require: "form",
restrict: "A",
@@ -39,14 +44,22 @@ function valFormManager(serverValidationManager, $rootScope, $log, $timeout, not
},
link: function (scope, element, attr, formCtrl) {
/*
FIXME: This is commented out because it caused this error
http://uixdk.com/angular/docs/error/ng/cpws
resulting in an endless digest loop for all editors
//watch the list of validation errors to notify the application of any validation changes
scope.$watch(function () {
return formCtrl.$error;
//the validators are in the $error collection: https://docs.angularjs.org/api/ng/type/form.FormController#$error
//since each key is the validator name (i.e. 'required') we can't just watch the number of keys, we need to watch
//the sum of the items inside of each key
//get the lengths of each array for each key in the $error collection
var validatorLengths = _.map(formCtrl.$error, function (val, key) {
return val.length;
});
//sum up all numbers in the resulting array
var sum = _.reduce(validatorLengths, function (memo, num) {
return memo + num;
}, 0);
//this is the value we watch to notify of any validation changes on the form
return sum;
}, function (e) {
scope.$broadcast("valStatusChanged", { form: formCtrl });
@@ -58,11 +71,7 @@ function valFormManager(serverValidationManager, $rootScope, $log, $timeout, not
var noInError = element.find(".control-group .ng-valid").closest(".control-group").not(inError);
noInError.removeClass("error");
}, true);
var className = attr.valShowValidation ? attr.valShowValidation : "show-validation";
var savingEventName = attr.savingEvent ? attr.savingEvent : "formSubmitting";
var savedEvent = attr.savedEvent ? attr.savingEvent : "formSubmitted";
});
//This tracks if the user is currently saving a new item, we use this to determine
// if we should display the warning dialog that they are leaving the page - if a new item
@@ -72,23 +81,23 @@ function valFormManager(serverValidationManager, $rootScope, $log, $timeout, not
//we should show validation if there are any msgs in the server validation collection
if (serverValidationManager.items.length > 0) {
element.addClass(className);
element.addClass(SHOW_VALIDATION_CLASS_NAME);
}
var unsubscribe = [];
//listen for the forms saving event
unsubscribe.push(scope.$on(savingEventName, function(ev, args) {
element.addClass(className);
unsubscribe.push(scope.$on(SAVING_EVENT_NAME, function(ev, args) {
element.addClass(SHOW_VALIDATION_CLASS_NAME);
//set the flag so we can check to see if we should display the error.
isSavingNewItem = $routeParams.create;
}));
//listen for the forms saved event
unsubscribe.push(scope.$on(savedEvent, function(ev, args) {
unsubscribe.push(scope.$on(SAVED_EVENT_NAME, function(ev, args) {
//remove validation class
element.removeClass(className);
element.removeClass(SHOW_VALIDATION_CLASS_NAME);
//clear form state as at this point we retrieve new data from the server
//and all validation will have cleared at this point
@@ -133,8 +142,8 @@ function valFormManager(serverValidationManager, $rootScope, $log, $timeout, not
$timeout(function(){
formCtrl.$setPristine();
}, 1000);
*/
}
};
}
angular.module('umbraco.directives.validation').directive("valFormManager", valFormManager);
angular.module('umbraco.directives.validation').directive("valFormManager", valFormManager);

View File

@@ -7,7 +7,7 @@
* @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.
* In order for this directive to work, the valStatusChanged directive must be placed on the containing form.
* In order for this directive to work, the valFormManager directive must be placed on the containing form.
**/
function valPropertyMsg(serverValidationManager) {
@@ -15,16 +15,18 @@ function valPropertyMsg(serverValidationManager) {
scope: {
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
require: ['^^form', '^^valFormManager'],
replace: true,
restrict: "E",
template: "<div ng-show=\"errorMsg != ''\" class='alert alert-error property-error' >{{errorMsg}}</div>",
/**
Our directive requries a reference to a form controller
which gets passed in to this parameter
*/
link: function (scope, element, attrs, formCtrl) {
link: function (scope, element, attrs, ctrl) {
//the property form controller api
var formCtrl = ctrl[0];
//the valFormManager controller api
var valFormManager = ctrl[1];
var watcher = null;
@@ -39,10 +41,12 @@ function valPropertyMsg(serverValidationManager) {
return err.errorMsg;
}
else {
//TODO: localize
return scope.property.propertyErrorMessage ? scope.property.propertyErrorMessage : "Property has errors";
}
}
//TODO: localize
return "Property has errors";
}
@@ -98,18 +102,19 @@ function valPropertyMsg(serverValidationManager) {
var unsubscribe = [];
//listen for form error changes
unsubscribe.push(scope.$on("valStatusChanged", function(evt, args) {
if (args.form.$invalid) {
//listen for form validation changes.
//The alternative is to add a watch to formCtrl.$invalid but that would lead to many more watches then
// subscribing to this single watch.
valFormManager.onValidationStatusChanged(function (evt, args) {
if (formCtrl.$invalid) {
//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 serverValidationManager.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
//if there are any errors in the current property form that are not valPropertyMsg
else if (_.without(_.keys(formCtrl.$error), "valPropertyMsg").length > 0) {
hasError = true;
//update the validation message if we don't already have one assigned.
if (showValidation && scope.errorMsg === "") {
@@ -125,7 +130,7 @@ function valPropertyMsg(serverValidationManager) {
hasError = false;
scope.errorMsg = "";
}
}, true));
});
//listen for the forms saving event
unsubscribe.push(scope.$on("formSubmitting", function(ev, args) {
@@ -193,4 +198,4 @@ function valPropertyMsg(serverValidationManager) {
};
}
angular.module('umbraco.directives.validation').directive("valPropertyMsg", valPropertyMsg);
angular.module('umbraco.directives.validation').directive("valPropertyMsg", valPropertyMsg);

View File

@@ -2,8 +2,9 @@
* @ngdoc directive
* @name umbraco.directives.directive:valServerField
* @restrict A
* @description This directive is used to associate a content field (not user defined) with a server-side validation response
* @description This directive is used to associate a field with a server-side validation response
* so that the validators in angular are updated based on server-side feedback.
* (For validation of user defined content properties on content/media/members, the valServer directive is used)
**/
function valServerField(serverValidationManager) {
return {

View File

@@ -41,7 +41,7 @@
}
var directive = {
require: ['?^form', '?^valFormManager'],
require: ['?^^form', '?^^valFormManager'],
restrict: "A",
link: link
};

View File

@@ -8,7 +8,7 @@
**/
function valTab() {
return {
require: ['^form', '^valFormManager'],
require: ['^^form', '^^valFormManager'],
restrict: "A",
link: function (scope, element, attr, ctrs) {
@@ -35,4 +35,4 @@ function valTab() {
}
};
}
angular.module('umbraco.directives.validation').directive("valTab", valTab);
angular.module('umbraco.directives.validation').directive("valTab", valTab);

View File

@@ -1,6 +1,6 @@
function valToggleMsg(serverValidationManager) {
return {
require: "^form",
require: "^^form",
restrict: "A",
/**
@@ -87,4 +87,4 @@ function valToggleMsg(serverValidationManager) {
* @requires formController
* @description This directive will show/hide an error based on: is the value + the given validator invalid? AND, has the form been submitted ?
**/
angular.module('umbraco.directives.validation').directive("valToggleMsg", valToggleMsg);
angular.module('umbraco.directives.validation').directive("valToggleMsg", valToggleMsg);

View File

@@ -0,0 +1,9 @@
angular.module('umbraco.interceptors', [])
// We have to add the interceptor to the queue as a string because the interceptor depends upon service instances that are not available in the config block.
.config(['$httpProvider', function($httpProvider) {
$httpProvider.defaults.xsrfHeaderName = 'X-UMB-XSRF-TOKEN';
$httpProvider.defaults.xsrfCookieName = 'UMB-XSRF-TOKEN';
$httpProvider.interceptors.push('securityInterceptor');
$httpProvider.interceptors.push('debugRequestInterceptor');
}]);

View File

@@ -0,0 +1,25 @@
(function() {
'use strict';
/**
* Used to set debug headers on all requests where necessary
* @param {any} $q
* @param {any} urlHelper
*/
function debugRequestInterceptor($q, urlHelper) {
return {
//dealing with requests:
'request': function(config) {
var queryStrings = urlHelper.getQueryStringParams();
if (queryStrings.umbDebug === "true" || queryStrings.umbdebug === "true") {
config.headers["X-UMB-DEBUG"] = "true";
}
return config;
}
};
}
angular.module('umbraco.interceptors').factory('debugRequestInterceptor', debugRequestInterceptor);
})();

View File

@@ -0,0 +1,11 @@
(function() {
'use strict';
/** Used to filter the request interceptor */
function requestInterceptorFilter() {
return ["www.gravatar.com"];
}
angular.module('umbraco.interceptors').value('requestInterceptorFilter', requestInterceptorFilter);
})();

View File

@@ -1,9 +1,19 @@
angular.module('umbraco.security.interceptor')
// This http interceptor listens for authentication successes and failures
.factory('securityInterceptor', ['$injector', 'securityRetryQueue', 'notificationsService', 'eventsService', 'requestInterceptorFilter', function ($injector, queue, notifications, eventsService, requestInterceptorFilter) {
return {
(function () {
'use strict';
'response': function(response) {
/**
* This http interceptor listens for authentication successes and failures
* @param {any} $q
* @param {any} $injector
* @param {any} requestRetryQueue
* @param {any} notificationsService
* @param {any} eventsService
* @param {any} requestInterceptorFilter
*/
function securityInterceptor($q, $injector, requestRetryQueue, notificationsService, eventsService, requestInterceptorFilter) {
return {
'response': function (response) {
// Intercept successful requests
//Here we'll check if our custom header is in the response which indicates how many seconds the user's session has before it
//expires. Then we'll update the user in the user service accordingly.
@@ -14,7 +24,7 @@ angular.module('umbraco.security.interceptor')
var userService = $injector.get('userService');
userService.setUserTimeout(headers["x-umb-user-seconds"]);
}
//this checks if the user's values have changed, in which case we need to update the user details throughout
//the back office similar to how we do when a user logs in
if (headers["x-umb-user-modified"]) {
@@ -23,8 +33,8 @@ angular.module('umbraco.security.interceptor')
return response;
},
'responseError': function(rejection) {
'responseError': function (rejection) {
// Intercept failed requests
// Make sure we have the configuration of the request (don't we always?)
@@ -36,13 +46,13 @@ angular.module('umbraco.security.interceptor')
//Here we'll check if we should ignore the error (either based on the original header set or the request configuration)
if (headers["x-umb-ignore-error"] === "ignore" || config.umbIgnoreErrors === true || (angular.isArray(config.umbIgnoreStatus) && config.umbIgnoreStatus.indexOf(rejection.status) !== -1)) {
//exit/ignore
return promise;
return $q.reject(rejection);
}
var filtered = _.find(requestInterceptorFilter(), function (val) {
return config.url.indexOf(val) > 0;
});
if (filtered) {
return promise;
return $q.reject(rejection);
}
//A 401 means that the user is not logged in
@@ -51,11 +61,11 @@ angular.module('umbraco.security.interceptor')
var userService = $injector.get('userService'); // see above
//Associate the user name with the retry to ensure we retry for the right user
promise = userService.getCurrentUser()
return userService.getCurrentUser()
.then(function (user) {
var userName = user ? user.name : null;
//The request bounced because it was not authorized - add a new request to the retry queue
return queue.pushRetryFn('unauthorized-server', userName, function retryRequest() {
return requestRetryQueue.pushRetryFn('unauthorized-server', userName, function retryRequest() {
// We must use $injector to get the $http service to prevent circular dependency
return $injector.get('$http')(rejection.config);
});
@@ -74,9 +84,9 @@ angular.module('umbraco.security.interceptor')
errMsg += "<br/> with data: <br/><i>" + angular.toJson(rejection.config.data) + "</i><br/>Contact your administrator for information.";
}
notifications.error(
notificationsService.error(
"Request error",
errMsg);
errMsg);
}
else if (rejection.status === 403) {
@@ -94,35 +104,15 @@ angular.module('umbraco.security.interceptor')
msg += "<br/> with data: <br/><i>" + angular.toJson(rejection.config.data) + "</i><br/>Contact your administrator for information.";
}
notifications.error("Authorization error", msg);
notificationsService.error("Authorization error", msg);
}
return $q.reject(rejection);
}
};
}])
//used to set headers on all requests where necessary
.factory('umbracoRequestInterceptor', function ($q, urlHelper) {
return {
//dealing with requests:
'request': function (config) {
var queryStrings = urlHelper.getQueryStringParams();
if (queryStrings.umbDebug === "true" || queryStrings.umbdebug === "true") {
config.headers["X-UMB-DEBUG"] = "true";
}
return config;
}
};
})
.value('requestInterceptorFilter', function () {
return ["www.gravatar.com"];
})
}
// We have to add the interceptor to the queue as a string because the interceptor depends upon service instances that are not available in the config block.
.config(['$httpProvider', function ($httpProvider) {
$httpProvider.defaults.xsrfHeaderName = 'X-UMB-XSRF-TOKEN';
$httpProvider.defaults.xsrfCookieName = 'UMB-XSRF-TOKEN';
angular.module('umbraco.interceptors').factory('securityInterceptor', securityInterceptor);
$httpProvider.interceptors.push('securityInterceptor');
$httpProvider.interceptors.push('umbracoRequestInterceptor');
}]);
})();

View File

@@ -1,4 +0,0 @@
//TODO: This is silly and unecessary to have a separate module for this
angular.module('umbraco.security.retryQueue', []);
angular.module('umbraco.security.interceptor', ['umbraco.security.retryQueue']);
angular.module('umbraco.security', ['umbraco.security.retryQueue', 'umbraco.security.interceptor']);

View File

@@ -1,90 +0,0 @@
//TODO: This is silly and unecessary to have a separate module for this
angular.module('umbraco.security.retryQueue', [])
// This is a generic retry queue for security failures. Each item is expected to expose two functions: retry and cancel.
.factory('securityRetryQueue', ['$q', '$log', function ($q, $log) {
var retryQueue = [];
var retryUser = null;
var service = {
// The security service puts its own handler in here!
onItemAddedCallbacks: [],
hasMore: function() {
return retryQueue.length > 0;
},
push: function(retryItem) {
retryQueue.push(retryItem);
// Call all the onItemAdded callbacks
angular.forEach(service.onItemAddedCallbacks, function(cb) {
try {
cb(retryItem);
} catch(e) {
$log.error('securityRetryQueue.push(retryItem): callback threw an error' + e);
}
});
},
pushRetryFn: function(reason, userName, retryFn) {
// The reason parameter is optional
if ( arguments.length === 2) {
retryFn = userName;
userName = reason;
reason = undefined;
}
if ((retryUser && retryUser !== userName) || userName === null) {
throw new Error('invalid user');
}
retryUser = userName;
// The deferred object that will be resolved or rejected by calling retry or cancel
var deferred = $q.defer();
var retryItem = {
reason: reason,
retry: function() {
// Wrap the result of the retryFn into a promise if it is not already
$q.when(retryFn()).then(function(value) {
// If it was successful then resolve our deferred
deferred.resolve(value);
}, function(value) {
// Othewise reject it
deferred.reject(value);
});
},
cancel: function() {
// Give up on retrying and reject our deferred
deferred.reject();
}
};
service.push(retryItem);
return deferred.promise;
},
retryReason: function() {
return service.hasMore() && retryQueue[0].reason;
},
cancelAll: function() {
while(service.hasMore()) {
retryQueue.shift().cancel();
}
retryUser = null;
},
retryAll: function (userName) {
if (retryUser == null) {
return;
}
if (retryUser !== userName) {
service.cancelAll();
return;
}
while(service.hasMore()) {
retryQueue.shift().retry();
}
}
};
return service;
}]);

View File

@@ -1 +1 @@
angular.module("umbraco.services", ["umbraco.security", "umbraco.resources"]);
angular.module("umbraco.services", ["umbraco.interceptors", "umbraco.resources"]);

View File

@@ -54,7 +54,7 @@ function angularHelper($log, $q) {
* This checks if a digest/apply is already occuring, if not it will force an apply call
*/
safeApply: function (scope, fn) {
if (scope.$$phase || scope.$root.$$phase) {
if (scope.$$phase || (scope.$root && scope.$root.$$phase)) {
if (angular.isFunction(fn)) {
fn();
}

View File

@@ -29,7 +29,8 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, notifica
return {
/** Used by the content editor and mini content editor to perform saving operations */
//TODO: Make this a more helpful/reusable method for other form operations! we can simplify this form most forms
//TODO: Make this a more helpful/reusable method for other form operations! we can simplify this form most forms
// = this is already done in the formhelper service
contentEditorPerformSave: function (args) {
if (!angular.isObject(args)) {
throw "args must be an object";
@@ -59,7 +60,7 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, notifica
return args.saveMethod(args.content, $routeParams.create, fileManager.getFiles())
.then(function (data) {
formHelper.resetForm({ scope: args.scope, notifications: data.notifications });
formHelper.resetForm({ scope: args.scope });
self.handleSuccessfulSave({
scope: args.scope,
@@ -71,7 +72,7 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, notifica
});
args.scope.busy = false;
return $q.when(data);
return $q.resolve(data);
}, function (err) {
self.handleSaveError({
@@ -81,12 +82,7 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, notifica
rebindCallback.apply(self, [args.content, err.data]);
}
});
//show any notifications
if (angular.isArray(err.data.notifications)) {
for (var i = 0; i < err.data.notifications.length; i++) {
notificationsService.showNotification(err.data.notifications[i]);
}
}
args.scope.busy = false;
return $q.reject(err);
});

View File

@@ -7,7 +7,7 @@
* A utility class used to streamline how forms are developed, to ensure that validation is check and displayed consistently and to ensure that the correct events
* fire when they need to.
*/
function formHelper(angularHelper, serverValidationManager, $timeout, notificationsService, dialogService, localizationService) {
function formHelper(angularHelper, serverValidationManager, $timeout, notificationsService, dialogService) {
return {
/**
@@ -64,8 +64,7 @@ function formHelper(angularHelper, serverValidationManager, $timeout, notificati
* @function
*
* @description
* Called by controllers when a form has been successfully submitted. the correct events execute
* and that the notifications are displayed if there are any.
* Called by controllers when a form has been successfully submitted, this ensures the correct events are raised.
*
* @param {object} args An object containing arguments for form submission
*/
@@ -77,8 +76,6 @@ function formHelper(angularHelper, serverValidationManager, $timeout, notificati
throw "args.scope cannot be null";
}
this.showNotifications(args);
args.scope.$broadcast("formSubmitted", { scope: args.scope });
},

View File

@@ -0,0 +1,97 @@
(function () {
'use strict';
/**
* A service normally used to recover from session expiry
* @param {any} $q
* @param {any} $log
*/
function requestRetryQueue($q, $log) {
var retryQueue = [];
var retryUser = null;
var service = {
// The security service puts its own handler in here!
onItemAddedCallbacks: [],
hasMore: function () {
return retryQueue.length > 0;
},
push: function (retryItem) {
retryQueue.push(retryItem);
// Call all the onItemAdded callbacks
angular.forEach(service.onItemAddedCallbacks, function (cb) {
try {
cb(retryItem);
} catch (e) {
$log.error('requestRetryQueue.push(retryItem): callback threw an error' + e);
}
});
},
pushRetryFn: function (reason, userName, retryFn) {
// The reason parameter is optional
if (arguments.length === 2) {
retryFn = userName;
userName = reason;
reason = undefined;
}
if ((retryUser && retryUser !== userName) || userName === null) {
throw new Error('invalid user');
}
retryUser = userName;
// The deferred object that will be resolved or rejected by calling retry or cancel
var deferred = $q.defer();
var retryItem = {
reason: reason,
retry: function () {
// Wrap the result of the retryFn into a promise if it is not already
$q.when(retryFn()).then(function (value) {
// If it was successful then resolve our deferred
deferred.resolve(value);
}, function (value) {
// Othewise reject it
deferred.reject(value);
});
},
cancel: function () {
// Give up on retrying and reject our deferred
deferred.reject();
}
};
service.push(retryItem);
return deferred.promise;
},
retryReason: function () {
return service.hasMore() && retryQueue[0].reason;
},
cancelAll: function () {
while (service.hasMore()) {
retryQueue.shift().cancel();
}
retryUser = null;
},
retryAll: function (userName) {
if (retryUser == null) {
return;
}
if (retryUser !== userName) {
service.cancelAll();
return;
}
while (service.hasMore()) {
retryQueue.shift().retry();
}
}
};
return service;
}
angular.module('umbraco.services').factory('requestRetryQueue', requestRetryQueue);
})();

View File

@@ -3,7 +3,8 @@
* @name umbraco.services.umbRequestHelper
* @description A helper object used for sending requests to the server
**/
function umbRequestHelper($http, $q, umbDataFormatter, angularHelper, dialogService, notificationsService, eventsService) {
function umbRequestHelper($http, $q, umbDataFormatter, angularHelper, dialogService, notificationsService, eventsService, formHelper) {
return {
/**
@@ -24,7 +25,7 @@ function umbRequestHelper($http, $q, umbDataFormatter, angularHelper, dialogServ
if (!virtualPath.startsWith("~/")) {
throw "The path " + virtualPath + " is not a virtual path";
}
if (!Umbraco.Sys.ServerVariables.application.applicationPath) {
if (!Umbraco.Sys.ServerVariables.application.applicationPath) {
throw "No applicationPath defined in Umbraco.ServerVariables.application.applicationPath";
}
return Umbraco.Sys.ServerVariables.application.applicationPath + virtualPath.trimStart("~/");
@@ -42,7 +43,7 @@ function umbRequestHelper($http, $q, umbDataFormatter, angularHelper, dialogServ
* @param {Array} queryStrings An array of key/value pairs
*/
dictionaryToQueryString: function (queryStrings) {
if (angular.isArray(queryStrings)) {
return _.map(queryStrings, function (item) {
var key = null;
@@ -63,7 +64,7 @@ function umbRequestHelper($http, $q, umbDataFormatter, angularHelper, dialogServ
//this allows for a normal object to be passed in (ie. a dictionary)
return decodeURIComponent($.param(queryStrings));
}
throw "The queryString parameter is not an array or object of key value pairs";
},
@@ -116,12 +117,10 @@ function umbRequestHelper($http, $q, umbDataFormatter, angularHelper, dialogServ
* The error callback must return an object containing: {errorMsg: errorMessage, data: originalData, status: status }
*/
resourcePromise: function (httpPromise, opts) {
var deferred = $q.defer();
/** The default success callback used if one is not supplied in the opts */
function defaultSuccess(data, status, headers, config) {
//when it's successful, just return the data
console.log("succes promise", data);
return data;
}
@@ -141,13 +140,15 @@ function umbRequestHelper($http, $q, umbDataFormatter, angularHelper, dialogServ
error: ((!opts || !opts.error) ? defaultError : opts.error)
};
httpPromise.then(function (response) {
return httpPromise.then(function (response) {
//invoke the callback
var result = callbacks.success.apply(this, [response.data, response.status, response.headers, response.config]);
formHelper.showNotifications(response.data);
//when it's successful, just return the data
deferred.resolve(result);
return $q.resolve(result);
}, function (response) {
@@ -169,24 +170,23 @@ function umbRequestHelper($http, $q, umbDataFormatter, angularHelper, dialogServ
//show a simple error notification
notificationsService.error("Server error", "Contact administrator, see log for full details.<br/><i>" + result.errorMsg + "</i>");
}
}
else {
formHelper.showNotifications(result.data);
}
//return an error object including the error message for UI
deferred.reject({
return $q.reject({
errorMsg: result.errorMsg,
data: result.data,
status: result.status
});
})
});
return deferred.promise;
},
/** Used for saving media/content specifically */
/** Used for saving content/media/members specifically */
postSaveContent: function (args) {
if (!args.restApiUrl) {
@@ -204,10 +204,7 @@ function umbRequestHelper($http, $q, umbDataFormatter, angularHelper, dialogServ
if (!args.dataFormatter) {
throw "args.dataFormatter is a required argument";
}
var deferred = $q.defer();
//save the active tab id so we can set it when the data is returned.
var activeTab = _.find(args.content.tabs, function (item) {
return item.active;
@@ -215,9 +212,10 @@ function umbRequestHelper($http, $q, umbDataFormatter, angularHelper, dialogServ
var activeTabIndex = (activeTab === undefined ? 0 : _.indexOf(args.content.tabs, activeTab));
//save the data
this.postMultiPartRequest(
return this.postMultiPartRequest(
args.restApiUrl,
{ key: "contentItem", value: args.dataFormatter(args.content, args.action) },
//data transform callback:
function (data, formData) {
//now add all of the assigned files
for (var f in args.files) {
@@ -225,64 +223,63 @@ function umbRequestHelper($http, $q, umbDataFormatter, angularHelper, dialogServ
// so we know which property it belongs to on the server side
formData.append("file_" + args.files[f].alias, args.files[f].file);
}
},
function (data, status, headers, config) {
}).then(function (response) {
//success callback
//reset the tabs and set the active one
if(data.tabs && data.tabs.length > 0) {
_.each(data.tabs, function (item) {
if (response.data.tabs && response.data.tabs.length > 0) {
_.each(response.data.tabs, function (item) {
item.active = false;
});
data.tabs[activeTabIndex].active = true;
response.data.tabs[activeTabIndex].active = true;
}
formHelper.showNotifications(response.data);
//the data returned is the up-to-date data so the UI will refresh
deferred.resolve(data);
},
function (data, status, headers, config) {
return $q.resolve(response.data);
}, function (response) {
//failure callback
//when there's a 500 (unhandled) error show a YSOD overlay if debugging is enabled.
if (status >= 500 && status < 600) {
if (response.status >= 500 && response.status < 600) {
//This is a bit of a hack to check if the error is due to a file being uploaded that is too large,
// we have to just check for the existence of a string value but currently that is the best way to
// do this since it's very hacky/difficult to catch this on the server
if (typeof data !== "undefined" && typeof data.indexOf === "function" && data.indexOf("Maximum request length exceeded") >= 0) {
if (typeof response.data !== "undefined" && typeof response.data.indexOf === "function" && response.data.indexOf("Maximum request length exceeded") >= 0) {
notificationsService.error("Server error", "The uploaded file was too large, check with your site administrator to adjust the maximum size allowed");
}
}
else if (Umbraco.Sys.ServerVariables["isDebuggingEnabled"] === true) {
//show a ysod dialog
eventsService.emit('app.ysod',
{
errorMsg: 'An error occured',
data: data
data: response.data
});
}
else {
//show a simple error notification
notificationsService.error("Server error", "Contact administrator, see log for full details.<br/><i>" + data.ExceptionMessage + "</i>");
notificationsService.error("Server error", "Contact administrator, see log for full details.<br/><i>" + response.data.ExceptionMessage + "</i>");
}
}
else {
formHelper.showNotifications(response.data);
}
//return an error object including the error message for UI
deferred.reject({
return $q.reject({
errorMsg: 'An error occurred',
data: data,
status: status
data: response.data,
status: response.status
});
});
return deferred.promise;
},
/** Posts a multi-part mime request to the server */
postMultiPartRequest: function (url, jsonData, transformCallback, successCallback, failureCallback) {
postMultiPartRequest: function (url, jsonData, transformCallback) {
//validate input, jsonData can be an array of key/value pairs or just one key/value pair.
if (!jsonData) { throw "jsonData cannot be null"; }
@@ -293,9 +290,8 @@ function umbRequestHelper($http, $q, umbDataFormatter, angularHelper, dialogServ
});
}
else if (!jsonData.key || !jsonData.value) { throw "jsonData object must have both a key and a value property"; }
$http({
return $http({
method: 'POST',
url: url,
//IMPORTANT!!! You might think this should be set to 'multipart/form-data' but this is not true because when we are sending up files
@@ -303,11 +299,11 @@ function umbRequestHelper($http, $q, umbDataFormatter, angularHelper, dialogServ
// and setting the Content-type manually will not set this boundary parameter. For whatever reason, setting the Content-type to 'undefined'
// will force the request to automatically populate the headers properly including the boundary parameter.
headers: { 'Content-Type': undefined },
transformRequest: function (data) {
transformRequest: function(data) {
var formData = new FormData();
//add the json data
if (angular.isArray(data)) {
_.each(data, function (item) {
_.each(data, function(item) {
formData.append(item.key, !angular.isString(item.value) ? angular.toJson(item.value) : item.value);
});
}
@@ -323,16 +319,10 @@ function umbRequestHelper($http, $q, umbDataFormatter, angularHelper, dialogServ
return formData;
},
data: jsonData
}).
then(function (response) {
if (successCallback) {
successCallback.apply(this, [response.data, response.status, response.headers, response.config]);
}
}).
catch(function (response) {
if (failureCallback) {
failureCallback.apply(this, [response.data, response.status, response.headers, response.config]);
}
}).then(function(response) {
return $q.resolve(response);
}, function(response) {
return $q.reject(response);
});
},
@@ -343,17 +333,15 @@ function umbRequestHelper($http, $q, umbDataFormatter, angularHelper, dialogServ
*/
downloadFile : function (httpPath) {
var deferred = $q.defer();
// Use an arraybuffer
$http.get(httpPath, { responseType: 'arraybuffer' })
.success(function (data, status, headers) {
return $http.get(httpPath, { responseType: 'arraybuffer' })
.then(function (response) {
var octetStreamMime = 'application/octet-stream';
var success = false;
// Get the headers
headers = headers();
var headers = response.headers();
// Get the filename from the x-filename header or default to "download.bin"
var filename = headers['x-filename'] || 'download.bin';
@@ -363,8 +351,7 @@ function umbRequestHelper($http, $q, umbDataFormatter, angularHelper, dialogServ
try {
// Try using msSaveBlob if supported
console.log("Trying saveBlob method ...");
var blob = new Blob([data], { type: contentType });
var blob = new Blob([response.data], { type: contentType });
if (navigator.msSaveBlob)
navigator.msSaveBlob(blob, filename);
else {
@@ -373,7 +360,6 @@ function umbRequestHelper($http, $q, umbDataFormatter, angularHelper, dialogServ
if (saveBlob === undefined) throw "Not supported";
saveBlob(blob, filename);
}
console.log("saveBlob succeeded");
success = true;
} catch (ex) {
console.log("saveBlob method failed with the following exception:");
@@ -390,8 +376,7 @@ function umbRequestHelper($http, $q, umbDataFormatter, angularHelper, dialogServ
// Try to simulate a click
try {
// Prepare a blob URL
console.log("Trying download link method with simulated click ...");
var blob = new Blob([data], { type: contentType });
var blob = new Blob([response.data], { type: contentType });
var url = urlCreator.createObjectURL(blob);
link.setAttribute('href', url);
@@ -402,7 +387,6 @@ function umbRequestHelper($http, $q, umbDataFormatter, angularHelper, dialogServ
var event = document.createEvent('MouseEvents');
event.initMouseEvent('click', true, true, window, 1, 0, 0, 0, 0, false, false, false, false, 0, null);
link.dispatchEvent(event);
console.log("Download link method with simulated click succeeded");
success = true;
} catch (ex) {
@@ -416,11 +400,9 @@ function umbRequestHelper($http, $q, umbDataFormatter, angularHelper, dialogServ
try {
// Prepare a blob URL
// Use application/octet-stream when using window.location to force download
console.log("Trying download link method with window.location ...");
var blob = new Blob([data], { type: octetStreamMime });
var blob = new Blob([response.data], { type: octetStreamMime });
var url = urlCreator.createObjectURL(blob);
window.location = url;
console.log("Download link method with window.location succeeded");
success = true;
} catch (ex) {
console.log("Download link method with window.location failed with the following exception:");
@@ -433,23 +415,19 @@ function umbRequestHelper($http, $q, umbDataFormatter, angularHelper, dialogServ
if (!success) {
// Fallback to window.open method
console.log("No methods worked for saving the arraybuffer, using last resort window.open");
window.open(httpPath, '_blank', '');
}
deferred.resolve();
})
.error(function (data, status) {
console.log("Request failed with status: " + status);
return $q.resolve();
deferred.reject({
}, function (response) {
return $q.reject({
errorMsg: "An error occurred downloading the file",
data: data,
status: status
data: response.data,
status: response.status
});
});
return deferred.promise;
}
};
}

View File

@@ -1,5 +1,5 @@
angular.module('umbraco.services')
.factory('userService', function ($rootScope, eventsService, $q, $location, $log, securityRetryQueue, authResource, dialogService, $timeout, angularHelper, $http) {
.factory('userService', function ($rootScope, eventsService, $q, $location, $log, requestRetryQueue, authResource, dialogService, $timeout, angularHelper, $http) {
var currentUser = null;
var lastUserId = null;
@@ -32,10 +32,10 @@ angular.module('umbraco.services')
loginDialog = null;
if (success) {
securityRetryQueue.retryAll(currentUser.name);
requestRetryQueue.retryAll(currentUser.name);
}
else {
securityRetryQueue.cancelAll();
requestRetryQueue.cancelAll();
$location.path('/');
}
}
@@ -172,8 +172,8 @@ angular.module('umbraco.services')
}
// Register a handler for when an item is added to the retry queue
securityRetryQueue.onItemAddedCallbacks.push(function (retryItem) {
if (securityRetryQueue.hasMore()) {
requestRetryQueue.onItemAddedCallbacks.push(function (retryItem) {
if (requestRetryQueue.hasMore()) {
userAuthExpired();
}
});
@@ -260,10 +260,10 @@ angular.module('umbraco.services')
}
setCurrentUser(data);
return $q.when(currentUser);
}, function () {
//it failed, so they are not logged in
//it failed, so they are not logged in
return $q.reject(currentUser);
});

View File

@@ -35,7 +35,7 @@ LazyLoad.js(
'js/umbraco.filters.js',
'js/umbraco.resources.js',
'js/umbraco.services.js',
'js/umbraco.security.js',
'js/umbraco.interceptors.js',
'js/umbraco.controllers.js',
'js/routes.js',
'js/init.js'
@@ -46,4 +46,4 @@ LazyLoad.js(
angular.bootstrap(document, ['umbraco']);
});
}
);
);

View File

@@ -144,7 +144,7 @@
.then(function (data) {
//success
formHelper.resetForm({ scope: $scope, notifications: data.notifications });
formHelper.resetForm({ scope: $scope });
$scope.invitedUserPasswordModel.buttonState = "success";
//set the user and set them as logged in
$scope.invitedUser = data;

View File

@@ -10,9 +10,9 @@
<div class="umb-list umb-list--condensed" ng-if="!vm.loading">
<div class="umb-list-item" ng-repeat="variant in vm.variants | filter:vm.dirtyVariantFilter">
<div class="umb-list-item" ng-repeat="variant in vm.variants | filter:vm.dirtyVariantFilter track by variant.compositeId">
<ng-form name="publishVariantSelectorForm">
<label class="flex" for="{{variant.htmlId}}">
<div class="flex">
<input id="{{variant.htmlId}}"
name="publishVariantSelector"
type="checkbox"
@@ -22,14 +22,16 @@
style="margin-right: 8px;"
val-server-field="{{variant.htmlId}}" />
<div>
<div ng-class="{'bold': variant.published}" style="margin-bottom: 2px;">{{ variant.language.name }}</div>
<div class="umb-permission__description" ng-if="!variant.validationError && variant.isEdited && variant.state === 'Published'"><localize key="content_publishedPendingChanges"></localize></div>
<div class="umb-permission__description" ng-if="!variant.validationError && variant.isEdited && variant.state === 'Unpublished'"><localize key="content_unpublishedPendingChanges"></localize></div>
<div class="umb-permission__description" ng-if="!variant.validationError && variant.isEdited === false">{{ variant.state }}</div>
<label for="{{variant.htmlId}}">
<span ng-class="{'bold': variant.published}" style="margin-bottom: 2px;">{{ variant.language.name }}</span>
</label>
<div class="umb-permission__description" ng-if="!publishVariantSelectorForm.publishVariantSelector.$invalid && variant.isEdited && variant.state === 'Published'"><localize key="content_publishedPendingChanges"></localize></div>
<div class="umb-permission__description" ng-if="!publishVariantSelectorForm.publishVariantSelector.$invalid && variant.isEdited && variant.state === 'Unpublished'"><localize key="content_unpublishedPendingChanges"></localize></div>
<div class="umb-permission__description" ng-if="!publishVariantSelectorForm.publishVariantSelector.$invalid && variant.isEdited === false">{{ variant.state }}</div>
<div class="umb-permission__description" style="color: #F02E28;" val-msg-for="publishVariantSelector" val-toggle-msg="valServerField"></div>
</div>
</label>
</div>
</ng-form>
</div>
<br/>

View File

@@ -147,7 +147,7 @@ angular.module("umbraco")
$scope.changePasswordModel.value.generatedPassword = data.value;
}
formHelper.resetForm({ scope: $scope, notifications: data.notifications });
formHelper.resetForm({ scope: $scope });
$scope.changePasswordButtonState = "success";
$timeout(function() {

View File

@@ -100,13 +100,7 @@ angular.module("umbraco").controller("Umbraco.Editors.Content.CopyController",
}, function (err) {
$scope.success = false;
$scope.error = err;
$scope.busy = false;
//show any notifications
if (angular.isArray(err.data.notifications)) {
for (var i = 0; i < err.data.notifications.length; i++) {
notificationsService.showNotification(err.data.notifications[i]);
}
}
$scope.busy = false;
});
};

View File

@@ -33,7 +33,7 @@
contentResource.createBlueprintFromContent($scope.currentNode.id, $scope.message.name)
.then(function(data) {
formHelper.resetForm({ scope: $scope, notifications: data.notifications });
formHelper.resetForm({ scope: $scope });
navigationService.hideMenu();
},

View File

@@ -54,12 +54,6 @@ function ContentDeleteController($scope, contentResource, treeService, navigatio
if (err.status && err.status >= 500) {
dialogService.ysodDialog(err);
}
if (err.data && angular.isArray(err.data.notifications)) {
for (var i = 0; i < err.data.notifications.length; i++) {
notificationsService.showNotification(err.data.notifications[i]);
}
}
});
};

View File

@@ -20,14 +20,7 @@ function ContentEmptyRecycleBinController($scope, contentResource, treeService,
$scope.busy = false;
$scope.currentNode.loading = false;
//show any notifications
if (angular.isArray(result.notifications)) {
for (var i = 0; i < result.notifications.length; i++) {
notificationsService.showNotification(result.notifications[i]);
}
}
treeService.removeChildNodes($scope.currentNode);
navigationService.hideMenu();

View File

@@ -102,12 +102,7 @@ angular.module("umbraco").controller("Umbraco.Editors.Content.MoveController",
$scope.success = false;
$scope.error = err;
$scope.busy = false;
//show any notifications
if (angular.isArray(err.data.notifications)) {
for (var i = 0; i < err.data.notifications.length; i++) {
notificationsService.showNotification(err.data.notifications[i]);
}
}
});
};

View File

@@ -143,7 +143,7 @@ function DataTypeEditController($scope, $routeParams, $location, appState, navig
dataTypeResource.save($scope.content, $scope.preValues, $routeParams.create)
.then(function(data) {
formHelper.resetForm({ scope: $scope, notifications: data.notifications });
formHelper.resetForm({ scope: $scope });
contentEditingHelper.handleSuccessfulSave({
scope: $scope,

View File

@@ -51,12 +51,7 @@ angular.module("umbraco")
$scope.success = false;
$scope.error = err;
$scope.busy = false;
//show any notifications
if (angular.isArray(err.data.notifications)) {
for (var i = 0; i < err.data.notifications.length; i++) {
notificationsService.showNotification(err.data.notifications[i]);
}
}
});
};

View File

@@ -46,12 +46,7 @@ angular.module("umbraco")
$scope.success = false;
$scope.error = err;
$scope.busy = false;
//show any notifications
if (angular.isArray(err.data.notifications)) {
for (var i = 0; i < err.data.notifications.length; i++) {
notificationsService.showNotification(err.data.notifications[i]);
}
}
});
};

View File

@@ -40,9 +40,7 @@ function DocumentTypesCreateController($scope, $location, navigationService, con
activate: true
});
formHelper.resetForm({
scope: $scope
});
formHelper.resetForm({ scope: $scope });
var section = appState.getSectionState("currentSection");
@@ -50,12 +48,6 @@ function DocumentTypesCreateController($scope, $location, navigationService, con
$scope.error = err;
//show any notifications
if (angular.isArray(err.data.notifications)) {
for (var i = 0; i < err.data.notifications.length; i++) {
notificationsService.showNotification(err.data.notifications[i]);
}
}
});
}
};

View File

@@ -51,12 +51,7 @@ angular.module("umbraco")
$scope.success = false;
$scope.error = err;
$scope.busy = false;
//show any notifications
if (angular.isArray(err.data.notifications)) {
for (var i = 0; i < err.data.notifications.length; i++) {
notificationsService.showNotification(err.data.notifications[i]);
}
}
});
};

View File

@@ -1,12 +1,6 @@
angular.module("umbraco")
.controller("Umbraco.Editors.ContentTypeContainers.RenameController",
[
"$scope",
"$injector",
"navigationService",
"notificationsService",
"localizationService",
function (scope, injector, navigationService, notificationsService, localizationService) {
function(scope, injector, navigationService, notificationsService, localizationService) {
var notificationHeader;
function reportSuccessAndClose(treeName) {
@@ -25,7 +19,7 @@
localizationService.localize(
"renamecontainer_folderWasRenamed",
[scope.currentNode.name, scope.model.folderName])
.then(function (msg) {
.then(function(msg) {
notificationsService.showNotification({
type: 0,
header: notificationHeader,
@@ -37,27 +31,21 @@
}
localizationService.localize("renamecontainer_renamed")
.then(function (s) { notificationHeader = s; });
.then(function(s) { notificationHeader = s; });
scope.model = {
folderName: scope.currentNode.name
}
scope.renameContainer = function (resourceKey, treeName) {
scope.renameContainer = function(resourceKey, treeName) {
var resource = injector.get(resourceKey);
resource.renameContainer(scope.currentNode.id, scope.model.folderName)
.then(function () {
.then(function() {
reportSuccessAndClose(treeName);
}, function (err) {
}, function(err) {
scope.error = err;
if (angular.isArray(err.data.notifications)) {
for (var i = 0; i < err.data.notifications.length; i++) {
notificationsService.showNotification(err.data.notifications[i]);
}
}
});
}
}
]);
);

View File

@@ -85,9 +85,7 @@
languageResource.save(vm.language).then(function (lang) {
formHelper.resetForm({
scope: $scope
});
formHelper.resetForm({ scope: $scope });
vm.language = lang;
vm.page.saveButtonState = "success";
@@ -108,12 +106,6 @@
formHelper.handleError(err);
//show any notifications
if (angular.isArray(err.data.notifications)) {
for (var i = 0; i < err.data.notifications.length; i++) {
notificationsService.showNotification(err.data.notifications[i]);
}
}
});
}

View File

@@ -70,12 +70,6 @@
}, function (err) {
language.deleteButtonState = "error";
//show any notifications
if (angular.isArray(err.data.notifications)) {
for (var i = 0; i < err.data.notifications.length; i++) {
notificationsService.showNotification(err.data.notifications[i]);
}
}
});
}

View File

@@ -56,11 +56,6 @@ function MediaDeleteController($scope, mediaResource, treeService, navigationSer
dialogService.ysodDialog(err);
}
if (err.data && angular.isArray(err.data.notifications)) {
for (var i = 0; i < err.data.notifications.length; i++) {
notificationsService.showNotification(err.data.notifications[i]);
}
}
});
};

View File

@@ -191,7 +191,7 @@ function mediaEditController($scope, $routeParams, appState, mediaResource, enti
mediaResource.save($scope.content, create, fileManager.getFiles())
.then(function(data) {
formHelper.resetForm({ scope: $scope, notifications: data.notifications });
formHelper.resetForm({ scope: $scope });
contentEditingHelper.handleSuccessfulSave({
scope: $scope,
@@ -226,13 +226,6 @@ function mediaEditController($scope, $routeParams, appState, mediaResource, enti
rebindCallback: contentEditingHelper.reBindChangedProperties($scope.content, err.data)
});
//show any notifications
if (angular.isArray(err.data.notifications)) {
for (var i = 0; i < err.data.notifications.length; i++) {
notificationsService.showNotification(err.data.notifications[i]);
}
}
editorState.set($scope.content);
$scope.busy = false;
$scope.page.saveButtonState = "error";

View File

@@ -21,13 +21,6 @@ function MediaEmptyRecycleBinController($scope, mediaResource, treeService, navi
$scope.busy = false;
$scope.currentNode.loading = false;
//show any notifications
if (angular.isArray(result.notifications)) {
for (var i = 0; i < result.notifications.length; i++) {
notificationsService.showNotification(result.notifications[i]);
}
}
treeService.removeChildNodes($scope.currentNode);
navigationService.hideMenu();

View File

@@ -46,12 +46,7 @@ angular.module("umbraco")
$scope.success = false;
$scope.error = err;
$scope.busy = false;
//show any notifications
if (angular.isArray(err.data.notifications)) {
for (var i = 0; i < err.data.notifications.length; i++) {
notificationsService.showNotification(err.data.notifications[i]);
}
}
});
};

View File

@@ -52,12 +52,7 @@ angular.module("umbraco")
$scope.success = false;
$scope.error = err;
$scope.busy = false;
//show any notifications
if (angular.isArray(err.data.notifications)) {
for (var i = 0; i < err.data.notifications.length; i++) {
notificationsService.showNotification(err.data.notifications[i]);
}
}
});
};

View File

@@ -134,7 +134,7 @@ function MemberEditController($scope, $routeParams, $location, $q, $window, appS
memberResource.save($scope.content, $routeParams.create, fileManager.getFiles())
.then(function(data) {
formHelper.resetForm({ scope: $scope, notifications: data.notifications });
formHelper.resetForm({ scope: $scope });
contentEditingHelper.handleSuccessfulSave({
scope: $scope,

View File

@@ -67,7 +67,7 @@ function MemberGroupsEditController($scope, $routeParams, appState, navigationSe
memberGroupResource.save($scope.content, $scope.preValues, $routeParams.create)
.then(function (data) {
formHelper.resetForm({ scope: $scope, notifications: data.notifications });
formHelper.resetForm({ scope: $scope });
contentEditingHelper.handleSuccessfulSave({
scope: $scope,

View File

@@ -45,18 +45,14 @@
activate: true
});
formHelper.resetForm({
scope: $scope
});
formHelper.resetForm({ scope: $scope });
var section = appState.getSectionState("currentSection");
}, function (err) {
vm.createFolderError = err;
//show any notifications
formHelper.showNotifications(err.data);
});
}
}

View File

@@ -71,11 +71,7 @@
if($routeParams.create && $routeParams.nomacro !== "true") {
macroResource.createPartialViewMacroWithFile(saved.virtualPath, saved.name).then(function(created) {
completeSave(saved);
}, function(err) {
//show any notifications
formHelper.showNotifications(err.data);
});
}, angular.noop);
} else {
completeSave(saved);
}

View File

@@ -55,17 +55,13 @@
activate: true
});
formHelper.resetForm({
scope: $scope
});
formHelper.resetForm({ scope: $scope });
var section = appState.getSectionState("currentSection");
}, function(err) {
vm.createFolderError = err;
formHelper.showNotifications(err.data);
});
}
}

View File

@@ -216,12 +216,8 @@ function listViewController($rootScope, $scope, $routeParams, $injector, notific
if (reload === true) {
$scope.reloadView($scope.contentId, true);
}
if (err.data && angular.isArray(err.data.notifications)) {
for (var i = 0; i < err.data.notifications.length; i++) {
notificationsService.showNotification(err.data.notifications[i]);
}
} else if (successMsg) {
if (successMsg) {
localizationService.localize("bulk_done")
.then(function(v) {
notificationsService.success(v, successMsg);

View File

@@ -39,16 +39,13 @@
activate: true
});
formHelper.resetForm({
scope: $scope
});
formHelper.resetForm({ scope: $scope });
var section = appState.getSectionState("currentSection");
}, function(err) {
vm.createFolderError = err;
formHelper.showNotifications(err.data);
});
}

View File

@@ -138,11 +138,8 @@
//if the user saved, then try to execute all extended save options
extendedSave(saved).then(function(result) {
//if all is good, then reset the form
formHelper.resetForm({ scope: $scope, notifications: saved.notifications });
}, function(err) {
//otherwise show the notifications for the user being saved
formHelper.showNotifications(saved);
});
formHelper.resetForm({ scope: $scope });
}, angular.noop);
vm.user = _.omit(saved, "navigation");
//restore
@@ -162,10 +159,7 @@
redirectOnFailure: false,
err: err
});
//show any notifications
if (err.data) {
formHelper.showNotifications(err.data);
}
vm.page.saveButtonState = "error";
});
}
@@ -319,10 +313,10 @@
vm.user.userState = 1;
setUserDisplayState();
vm.disableUserButtonState = "success";
formHelper.showNotifications(data);
}, function (error) {
vm.disableUserButtonState = "error";
formHelper.showNotifications(error.data);
});
}
@@ -332,10 +326,8 @@
vm.user.userState = 0;
setUserDisplayState();
vm.enableUserButtonState = "success";
formHelper.showNotifications(data);
}, function (error) {
vm.enableUserButtonState = "error";
formHelper.showNotifications(error.data);
});
}
@@ -345,10 +337,8 @@
vm.user.userState = 0;
setUserDisplayState();
vm.unlockUserButtonState = "success";
formHelper.showNotifications(data);
}, function (error) {
vm.unlockUserButtonState = "error";
formHelper.showNotifications(error.data);
});
}

View File

@@ -96,10 +96,7 @@
userGroupsResource.deleteUserGroups(vm.selection).then(function (data) {
clearSelection();
onInit();
formHelper.showNotifications(data);
}, function(error) {
formHelper.showNotifications(error.data);
});
}, angular.noop);
}
});

View File

@@ -250,14 +250,11 @@
// show the correct badges
setUserDisplayState(vm.users);
formHelper.showNotifications(data);
vm.disableUserButtonState = "init";
clearSelection();
}, function (error) {
vm.disableUserButtonState = "error";
formHelper.showNotifications(error.data);
});
}
@@ -273,13 +270,10 @@
});
// show the correct badges
setUserDisplayState(vm.users);
// show notification
formHelper.showNotifications(data);
vm.enableUserButtonState = "init";
clearSelection();
}, function (error) {
vm.enableUserButtonState = "error";
formHelper.showNotifications(error.data);
});
}
@@ -295,13 +289,10 @@
});
// show the correct badges
setUserDisplayState(vm.users);
// show notification
formHelper.showNotifications(data);
vm.unlockUserButtonState = "init";
clearSelection();
}, function (error) {
vm.unlockUserButtonState = "error";
formHelper.showNotifications(error.data);
});
}
@@ -334,11 +325,8 @@
vm.selectedBulkUserGroups = [];
vm.userGroupPicker.show = false;
vm.userGroupPicker = null;
formHelper.showNotifications(data);
clearSelection();
}, function (error) {
formHelper.showNotifications(error.data);
});
}, angular.noop);
},
close: function (oldModel) {
vm.selectedBulkUserGroups = [];

View File

@@ -4,11 +4,11 @@ var app = angular.module('umbraco', [
'umbraco.resources',
'umbraco.services',
'umbraco.mocks',
'umbraco.security',
'umbraco.interceptors',
'ngCookies',
'LocalStorageModule'
]);
/* For Angular 1.2: we need to load in Routing separately
'ngRoute'
*/
*/

View File

@@ -38,7 +38,7 @@
'js/umbraco.directives.js',
'js/umbraco.filters.js',
'js/umbraco.services.js',
'js/umbraco.security.js',
'js/umbraco.interceptors.js',
'js/umbraco.controllers.js',
'js/routes.js',
'js/init.js'