diff --git a/UI/Templates/ContactsUI/UIxContactFoldersView.wox b/UI/Templates/ContactsUI/UIxContactFoldersView.wox
index 52ea63e17..c87523a3e 100644
--- a/UI/Templates/ContactsUI/UIxContactFoldersView.wox
+++ b/UI/Templates/ContactsUI/UIxContactFoldersView.wox
@@ -390,6 +390,7 @@
diff --git a/UI/Templates/MailerUI/UIxMailFolderTemplate.wox b/UI/Templates/MailerUI/UIxMailFolderTemplate.wox
index be57d012b..3e58bcb2d 100644
--- a/UI/Templates/MailerUI/UIxMailFolderTemplate.wox
+++ b/UI/Templates/MailerUI/UIxMailFolderTemplate.wox
@@ -226,7 +226,7 @@
ng-switch="currentMessage.selected">
diff --git a/UI/WebServerResources/js/Common/Common.app.js b/UI/WebServerResources/js/Common/Common.app.js
index 9ce0d1bd0..26dccc6cc 100644
--- a/UI/WebServerResources/js/Common/Common.app.js
+++ b/UI/WebServerResources/js/Common/Common.app.js
@@ -230,7 +230,7 @@
return {
response: function(response) {
// When expecting JSON but receiving HTML, assume session has expired and reload page
- if (/^application\/json/.test(response.config.headers.Accept) &&
+ if (response && /^application\/json/.test(response.config.headers.Accept) &&
/^/.test(response.data)) {
$window.location.reload(true);
return $q.reject();
@@ -247,8 +247,10 @@
function ErrorInterceptor($rootScope, $q) {
return {
responseError: function(rejection) {
- // Broadcast the response error
- $rootScope.$broadcast('http:Error', rejection);
+ if (/^application\/json/.test(rejection.config.headers.Accept)) {
+ // Broadcast the response error
+ $rootScope.$broadcast('http:Error', rejection);
+ }
return $q.reject(rejection);
}
};
diff --git a/UI/WebServerResources/js/Common/navController.js b/UI/WebServerResources/js/Common/navController.js
index a0d2cc098..a6f78b5d8 100644
--- a/UI/WebServerResources/js/Common/navController.js
+++ b/UI/WebServerResources/js/Common/navController.js
@@ -66,23 +66,26 @@
function onHttpError(event, response) {
var message;
- if (response.data.message)
+ if (response.data && response.data.message)
message = response.data.message;
- else
+ else if (response.status)
message = response.statusText;
- $mdToast.show({
- template: [
- '',
- ' ',
- ' error_outline',
- ' ' + l(message) + '',
- '
',
- ''
- ].join(''),
- hideDelay: 5000,
- position: 'top right'
- });
+ if (message)
+ $mdToast.show({
+ template: [
+ '',
+ ' ',
+ ' error_outline',
+ ' ' + l(message) + '',
+ '
',
+ ''
+ ].join(''),
+ hideDelay: 5000,
+ position: 'top right'
+ });
+ else
+ console.debug('untrap error');
}
// Listen to HTTP errors broadcasted from HTTP interceptor
diff --git a/UI/WebServerResources/js/Common/sgAvatarImage.directive.js b/UI/WebServerResources/js/Common/sgAvatarImage.directive.js
index 13efe3fb9..c29cab748 100644
--- a/UI/WebServerResources/js/Common/sgAvatarImage.directive.js
+++ b/UI/WebServerResources/js/Common/sgAvatarImage.directive.js
@@ -6,7 +6,7 @@
/**
* sgAvatarImage - An avatar directive that returns un img element with either a local URL (if sg-src is specified)
- * or a Gravatar URL built from the Gravatar factory.
+ * or a Gravatar URL built from the Gravatar factory (using sg-email).
* Based on http://blog.lingohub.com/2014/08/better-ux-with-angularjs-directives/.
* @memberof SOGo.Common
* @example:
@@ -15,60 +15,54 @@
function sgAvatarImage() {
return {
restrict: 'AE',
- scope: {
+ scope: {},
+ bindToController: {
size: '@',
email: '=sgEmail',
src: '=sgSrc'
},
- template: '
',
+ template: [
+ 'person', // the generic icon
+ '
' // the gravatar or local image
+ ].join(''),
link: link,
- bindToController: true,
controller: 'sgAvatarImageController',
controllerAs: 'vm'
};
}
function link(scope, element, attrs, controller) {
- var el = element[0],
- className = el.className,
- imgElement = element.find('img'),
- img = imgElement[0];
+ var imgElement = element.find('img'),
+ mdIconElement = element.find('md-icon');
if (attrs.size) {
imgElement.attr('width', attrs.size);
imgElement.attr('height', attrs.size);
}
- imgElement.bind('error', function() {
- // Error while loading external link; insert a generic avatar
- controller.insertGenericAvatar(img);
- });
+ controller.img = imgElement;
+ controller.genericImg = mdIconElement;
}
/**
* @ngInject
*/
- sgAvatarImageController.$inject = ['$scope', '$element', 'Preferences', 'Gravatar'];
- function sgAvatarImageController($scope, $element, Preferences, Gravatar) {
- var vm = this;
+ sgAvatarImageController.$inject = ['$scope', '$element', '$http', '$q', 'Preferences', 'Gravatar'];
+ function sgAvatarImageController($scope, $element, $http, $q, Preferences, Gravatar) {
+ var vm;
- $scope.$watch('vm.email', function(email) {
+ vm = this;
- Preferences.ready().then(function() {
- var img = $element.find('img')[0];
- if (!email && !vm.genericAvatar) {
- // If no email is specified, insert a generic avatar
- vm.insertGenericAvatar(img);
- }
- else if (email && !vm.url) {
- if (vm.genericAvatar) {
- // Remove generic avatar and restore visibility of image
- vm.genericAvatar.parentNode.removeChild(vm.genericAvatar);
- delete vm.genericAvatar;
- img.classList.remove('ng-hide');
- }
- vm.url = Gravatar(email, vm.size, Preferences.defaults.SOGoAlternateAvatar);
+ // Wait on user's defaults
+ Preferences.ready().then(function() {
+ $scope.$watch('vm.email', function(email, old) {
+ if (email && vm.urlEmail != email) {
+ // Email has changed or doesn't match the current URL (this happens when using md-virtual-repeat)
+ showGenericAvatar();
+ getGravatar(email);
}
+ else if (!email)
+ showGenericAvatar();
});
});
@@ -76,21 +70,44 @@
if ('sg-src' in $element[0].attributes) {
$scope.$watch('vm.src', function(src) {
if (src) {
+ // Set image URL and save the associated email address
vm.url = src;
+ vm.urlEmail = '' + vm.email;
+ hideGenericAvatar();
}
});
}
- vm.insertGenericAvatar = function(img) {
- var avatar;
+ function getGravatar(email) {
+ var url = Gravatar(email, vm.size, Preferences.defaults.SOGoAlternateAvatar);
+ $http({
+ method: 'GET',
+ url: url,
+ cache: true,
+ headers: { Accept: 'image/*' }
+ }).then(function successCallback() {
+ if (!vm.url) {
+ // Set image URL and save the associated email address
+ vm.url = url;
+ vm.urlEmail = email;
+ hideGenericAvatar();
+ }
+ }, function errorCallback() {
+ showGenericAvatar();
+ });
+ }
- if (!vm.genericAvatar) {
- avatar = document.createElement('md-icon');
- avatar.className = 'material-icons icon-person';
- img.classList.add('ng-hide');
- vm.genericAvatar = img.parentNode.insertBefore(avatar, img);
- }
- };
+ function showGenericAvatar() {
+ vm.url = null;
+ vm.urlEmail = null;
+ vm.img.addClass('ng-hide');
+ vm.genericImg.removeClass('ng-hide');
+ }
+
+ function hideGenericAvatar() {
+ vm.genericImg.addClass('ng-hide');
+ vm.img.removeClass('ng-hide');
+ }
}
angular
diff --git a/UI/WebServerResources/scss/components/virtualRepeat/virtual-repeat.scss b/UI/WebServerResources/scss/components/virtualRepeat/virtual-repeat.scss
index 168aed8eb..52719c083 100644
--- a/UI/WebServerResources/scss/components/virtualRepeat/virtual-repeat.scss
+++ b/UI/WebServerResources/scss/components/virtualRepeat/virtual-repeat.scss
@@ -6,5 +6,6 @@ md-virtual-repeat-container {
// Fix weird scroll behavior when reaching bottom of list
// See https://github.com/angular/material/issues/4169
padding-top: 0;
+ padding-bottom: 0;
}
}
\ No newline at end of file