From 51b5897d88dd110684fc578b21f233a82f0f6fff Mon Sep 17 00:00:00 2001 From: Juanfran Date: Tue, 19 Jul 2016 15:02:00 +0200 Subject: [PATCH] new user avatar directive --- CHANGELOG.md | 3 +- app/coffee/modules/admin/memberships.coffee | 9 +- app/coffee/modules/common/components.coffee | 62 +++++++----- app/coffee/modules/common/lightboxes.coffee | 13 ++- app/coffee/modules/issues/list.coffee | 13 ++- app/coffee/modules/kanban/main.coffee | 16 +-- app/coffee/modules/related-tasks.coffee | 14 ++- app/coffee/modules/taskboard/main.coffee | 10 +- app/coffee/modules/wiki/main.coffee | 10 +- app/images/user-avatars/user-avatar-01.png | Bin 0 -> 1088 bytes app/images/user-avatars/user-avatar-02.png | Bin 0 -> 1005 bytes app/images/user-avatars/user-avatar-03.png | Bin 0 -> 1335 bytes app/images/user-avatars/user-avatar-04.png | Bin 0 -> 1170 bytes app/images/user-avatars/user-avatar-05.png | Bin 0 -> 1093 bytes .../components/avatar/avatar.directive.coffee | 49 +++++++++ app/modules/external-apps/external-app.jade | 5 +- app/modules/history/comments/comment.jade | 2 +- .../history-lightbox/history-entry.jade | 2 +- app/modules/history/history/history.jade | 2 +- app/modules/home/duties/duty.jade | 2 +- .../dropdown-user/dropdown-user.jade | 5 +- .../navigation-bar/navigation-bar.scss | 2 +- .../profile/profile-bar/profile-bar.jade | 5 +- .../profile-contacts/profile-contacts.jade | 5 +- .../profile/profile-favs/items/ticket.jade | 6 +- .../profile-projects/profile-projects.jade | 2 +- app/modules/projects/project/project.jade | 5 +- app/modules/services/avatar.service.coffee | 93 ++++++++++++++++++ .../user-timeline-item.jade | 15 ++- .../wiki/history/wiki-history-entry.jade | 2 +- .../admin/admin-project-change-owner.jade | 2 +- .../admin-project-request-ownership.jade | 2 +- .../admin/memberships-row-avatar.jade | 5 +- app/partials/auth/invitation.jade | 6 +- .../common/components/assigned-to.jade | 6 +- .../common/components/created-by.jade | 3 +- .../list-item-assigned-to-avatar.jade | 6 +- .../common/components/user-display.jade | 6 +- app/partials/common/components/watchers.jade | 17 ++-- .../lightbox/lightbox-assigned-to-users.jade | 10 +- .../lightbox/lightbox-change-owner.jade | 5 +- app/partials/taskboard/taskboard-user.jade | 15 ++- .../team/team-member-current-user.jade | 2 +- app/partials/team/team-members.jade | 2 +- app/partials/user/user-profile.jade | 2 +- app/partials/wiki/wiki-summary.jade | 12 ++- 46 files changed, 343 insertions(+), 110 deletions(-) create mode 100644 app/images/user-avatars/user-avatar-01.png create mode 100644 app/images/user-avatars/user-avatar-02.png create mode 100644 app/images/user-avatars/user-avatar-03.png create mode 100644 app/images/user-avatars/user-avatar-04.png create mode 100644 app/images/user-avatars/user-avatar-05.png create mode 100644 app/modules/components/avatar/avatar.directive.coffee create mode 100644 app/modules/services/avatar.service.coffee diff --git a/CHANGELOG.md b/CHANGELOG.md index f1fe705a..0551a4ca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,9 +10,10 @@ - Neew Attachments image slider in preview mode. - New admin area to edit the tag colors used in your project. - Display the current user (me) at first in assignment lightbox (thanks to [@mikaoelitiana](https://github.com/mikaoelitiana)) -- Divide the user dashboard in two columns in large screens, +- Divide the user dashboard in two columns in large screens. - Upvote and downvote issues from the issues list. - Show points per role in statsection of the taskboard panel. +- Show a funny randon animals/color for users with no avatar (like project logos). - Comments: - Add a new permissions to allow add comments instead of use the existent modify permission for this purpose. - Ability to edit comments, view edition history and redesign comments module UI. diff --git a/app/coffee/modules/admin/memberships.coffee b/app/coffee/modules/admin/memberships.coffee index 261d2f3f..1ab6c54f 100644 --- a/app/coffee/modules/admin/memberships.coffee +++ b/app/coffee/modules/admin/memberships.coffee @@ -241,16 +241,19 @@ module.directive("tgMemberships", ["$tgTemplate", "$compile", MembershipsDirecti ## Member Avatar Directive ############################################################################# -MembershipsRowAvatarDirective = ($log, $template, $translate, $compile) -> +MembershipsRowAvatarDirective = ($log, $template, $translate, $compile, avatarService) -> template = $template.get("admin/memberships-row-avatar.html", true) link = ($scope, $el, $attrs) -> pending = $translate.instant("ADMIN.MEMBERSHIP.STATUS_PENDING") render = (member) -> + avatar = avatarService.getAvatar(member) + ctx = { full_name: if member.full_name then member.full_name else "" email: if member.user_email then member.user_email else member.email - imgurl: if member.photo then member.photo else "/" + window._version + "/images/unnamed.png" + imgurl: avatar.url + bg: avatar.bg pending: if !member.is_user_active then pending else "" isOwner: member.is_owner } @@ -272,7 +275,7 @@ MembershipsRowAvatarDirective = ($log, $template, $translate, $compile) -> return {link: link} -module.directive("tgMembershipsRowAvatar", ["$log", "$tgTemplate", '$translate', "$compile", MembershipsRowAvatarDirective]) +module.directive("tgMembershipsRowAvatar", ["$log", "$tgTemplate", '$translate', "$compile", "tgAvatarService", MembershipsRowAvatarDirective]) ############################################################################# diff --git a/app/coffee/modules/common/components.coffee b/app/coffee/modules/common/components.coffee index eb4e2d6e..e42ad1a4 100644 --- a/app/coffee/modules/common/components.coffee +++ b/app/coffee/modules/common/components.coffee @@ -126,7 +126,7 @@ module.directive("tgSprintProgressbar", SprintProgressBarDirective) ## Created-by display directive ############################################################################# -CreatedByDisplayDirective = ($template, $compile, $translate, $navUrls)-> +CreatedByDisplayDirective = ($template, $compile, $translate, $navUrls, avatarService)-> # Display the owner information (full name and photo) and the date of # creation of an object (like USs, tasks and issues). # @@ -141,11 +141,15 @@ CreatedByDisplayDirective = ($template, $compile, $translate, $navUrls)-> link = ($scope, $el, $attrs) -> bindOnce $scope, $attrs.ngModel, (model) -> if model? + + avatar = avatarService.getAvatar(model.owner_extra_info) $scope.owner = model.owner_extra_info or { full_name_display: $translate.instant("COMMON.EXTERNAL_USER") - photo: "/" + window._version + "/images/user-noimage.png" } + $scope.owner.avatar = avatar.url + $scope.owner.bg = avatar.bg + $scope.url = if $scope.owner?.is_active then $navUrls.resolve("user-profile", {username: $scope.owner.username}) else "" @@ -162,11 +166,11 @@ CreatedByDisplayDirective = ($template, $compile, $translate, $navUrls)-> templateUrl: "common/components/created-by.html" } -module.directive("tgCreatedByDisplay", ["$tgTemplate", "$compile", "$translate", "$tgNavUrls", +module.directive("tgCreatedByDisplay", ["$tgTemplate", "$compile", "$translate", "$tgNavUrls", "tgAvatarService", CreatedByDisplayDirective]) -UserDisplayDirective = ($template, $compile, $translate, $navUrls)-> +UserDisplayDirective = ($template, $compile, $translate, $navUrls, avatarService)-> # Display the user information (full name and photo). # # Example: @@ -177,12 +181,15 @@ UserDisplayDirective = ($template, $compile, $translate, $navUrls)-> link = ($scope, $el, $attrs) -> id = $attrs.tgUserId - console.log($scope.usersById[id]) $scope.user = $scope.usersById[id] or { full_name_display: $translate.instant("COMMON.EXTERNAL_USER") - photo: "/" + window._version + "/images/user-noimage.png" } + avatar = avatarService.getAvatar($scope.usersById[id] or null) + + $scope.user.avatar = avatar.url + $scope.user.bg = avatar.bg + $scope.url = if $scope.user.is_active then $navUrls.resolve("user-profile", {username: $scope.user.username}) else "" $scope.$on "$destroy", -> @@ -195,7 +202,7 @@ UserDisplayDirective = ($template, $compile, $translate, $navUrls)-> templateUrl: "common/components/user-display.html" } -module.directive("tgUserDisplay", ["$tgTemplate", "$compile", "$translate", "$tgNavUrls", +module.directive("tgUserDisplay", ["$tgTemplate", "$compile", "$translate", "$tgNavUrls", "tgAvatarService", UserDisplayDirective]) ############################################################################# @@ -205,7 +212,6 @@ module.directive("tgUserDisplay", ["$tgTemplate", "$compile", "$translate", "$tg WatchersDirective = ($rootscope, $confirm, $repo, $modelTransform, $template, $compile, $translate) -> # You have to include a div with the tg-lb-watchers directive in the page # where use this directive - template = $template.get("common/components/watchers.html", true) link = ($scope, $el, $attrs, $model) -> isEditable = -> @@ -242,13 +248,8 @@ WatchersDirective = ($rootscope, $confirm, $repo, $modelTransform, $template, $c $confirm.notify("error") renderWatchers = (watchers) -> - ctx = { - watchers: watchers - isEditable: isEditable() - } - - html = $compile(template(ctx))($scope) - $el.html(html) + $scope.watchers = watchers + $scope.isEditable = isEditable() $el.on "click", ".js-delete-watcher", (event) -> event.preventDefault() @@ -282,7 +283,12 @@ WatchersDirective = ($rootscope, $confirm, $repo, $modelTransform, $template, $c $scope.$on "$destroy", -> $el.off() - return {link:link, require:"ngModel"} + return { + scope: true, + templateUrl: "common/components/watchers.html", + link:link, + require:"ngModel" + } module.directive("tgWatchers", ["$rootScope", "$tgConfirm", "$tgRepo", "$tgQueueModelTransformation", "$tgTemplate", "$compile", "$translate", WatchersDirective]) @@ -292,7 +298,7 @@ module.directive("tgWatchers", ["$rootScope", "$tgConfirm", "$tgRepo", "$tgQueue ## Assigned to directive ############################################################################# -AssignedToDirective = ($rootscope, $confirm, $repo, $loading, $modelTransform, $template, $translate, $compile, $currentUserService) -> +AssignedToDirective = ($rootscope, $confirm, $repo, $loading, $modelTransform, $template, $translate, $compile, $currentUserService, avatarService) -> # You have to include a div with the tg-lb-assignedto directive in the page # where use this directive template = $template.get("common/components/assigned-to.html", true) @@ -326,20 +332,23 @@ AssignedToDirective = ($rootscope, $confirm, $repo, $loading, $modelTransform, $ return transform renderAssignedTo = (assignedObject) -> + avatar = avatarService.getAvatar(assignedObject?.assigned_to_extra_info) + bg = null + if assignedObject?.assigned_to? fullName = assignedObject.assigned_to_extra_info.full_name_display - photo = assignedObject.assigned_to_extra_info.photo isUnassigned = false + bg = avatar.bg else fullName = $translate.instant("COMMON.ASSIGNED_TO.ASSIGN") - photo = "/#{window._version}/images/unnamed.png" isUnassigned = true isIocaine = assignedObject?.is_iocaine ctx = { fullName: fullName - photo: photo + avatar: avatar.url + bg: bg isUnassigned: isUnassigned isEditable: isEditable() isIocaine: isIocaine @@ -386,7 +395,7 @@ AssignedToDirective = ($rootscope, $confirm, $repo, $loading, $modelTransform, $ require:"ngModel" } -module.directive("tgAssignedTo", ["$rootScope", "$tgConfirm", "$tgRepo", "$tgLoading", "$tgQueueModelTransformation", "$tgTemplate", "$translate", "$compile","tgCurrentUserService", +module.directive("tgAssignedTo", ["$rootScope", "$tgConfirm", "$tgRepo", "$tgLoading", "$tgQueueModelTransformation", "$tgTemplate", "$translate", "$compile","tgCurrentUserService", "tgAvatarService", AssignedToDirective]) @@ -776,7 +785,7 @@ ListItemTaskStatusDirective = -> module.directive("tgListitemTaskStatus", ListItemTaskStatusDirective) -ListItemAssignedtoDirective = ($template, $translate) -> +ListItemAssignedtoDirective = ($template, $translate, avatarService) -> template = $template.get("common/components/list-item-assigned-to-avatar.html", true) link = ($scope, $el, $attrs) -> @@ -784,19 +793,22 @@ ListItemAssignedtoDirective = ($template, $translate) -> item = $scope.$eval($attrs.tgListitemAssignedto) ctx = { name: $translate.instant("COMMON.ASSIGNED_TO.NOT_ASSIGNED"), - imgurl: "/#{window._version}/images/unnamed.png" } member = usersById[item.assigned_to] + avatar = avatarService.getAvatar(member) + + ctx.imgurl = avatar.url + ctx.bg = avatar.bg + if member - ctx.imgurl = member.photo ctx.name = member.full_name_display $el.html(template(ctx)) return {link:link} -module.directive("tgListitemAssignedto", ["$tgTemplate", "$translate", ListItemAssignedtoDirective]) +module.directive("tgListitemAssignedto", ["$tgTemplate", "$translate", "tgAvatarService", ListItemAssignedtoDirective]) ListItemIssueStatusDirective = -> diff --git a/app/coffee/modules/common/lightboxes.coffee b/app/coffee/modules/common/lightboxes.coffee index 3fa982a3..0c8a8b4a 100644 --- a/app/coffee/modules/common/lightboxes.coffee +++ b/app/coffee/modules/common/lightboxes.coffee @@ -502,7 +502,7 @@ module.directive("tgLbCreateBulkUserstories", [ ## AssignedTo Lightbox Directive ############################################################################# -AssignedToLightboxDirective = (lightboxService, lightboxKeyboardNavigationService, $template, $compile) -> +AssignedToLightboxDirective = (lightboxService, lightboxKeyboardNavigationService, $template, $compile, avatarService) -> link = ($scope, $el, $attrs) -> selectedUser = null selectedItem = null @@ -530,10 +530,17 @@ AssignedToLightboxDirective = (lightboxService, lightboxKeyboardNavigationServic users = _.sortBy(users, (o) -> if o.id is $scope.user.id then 0 else o.id) users = _.filter(users, _.partial(filterUsers, text)) if text? + visibleUsers = _.slice(users, 0, 5) + + visibleUsers = _.map visibleUsers, (user) -> + user.avatar = avatarService.getAvatar(user) + + selected.avatar = avatarService.getAvatar(selected) + ctx = { selected: selected users: _.slice(users, 0, 5) - showMore: users.length > 5 + showMore: visibleUsers } html = usersTemplate(ctx) @@ -597,7 +604,7 @@ AssignedToLightboxDirective = (lightboxService, lightboxKeyboardNavigationServic } -module.directive("tgLbAssignedto", ["lightboxService", "lightboxKeyboardNavigationService", "$tgTemplate", "$compile", AssignedToLightboxDirective]) +module.directive("tgLbAssignedto", ["lightboxService", "lightboxKeyboardNavigationService", "$tgTemplate", "$compile", "tgAvatarService", AssignedToLightboxDirective]) ############################################################################# diff --git a/app/coffee/modules/issues/list.coffee b/app/coffee/modules/issues/list.coffee index 6dee03b5..a8cfa0b9 100644 --- a/app/coffee/modules/issues/list.coffee +++ b/app/coffee/modules/issues/list.coffee @@ -801,9 +801,9 @@ module.directive("tgIssueStatusInlineEdition", ["$tgRepo", "$tgTemplate", "$root ## Issue assigned to Directive ############################################################################# -IssueAssignedToInlineEditionDirective = ($repo, $rootscope, $translate) -> +IssueAssignedToInlineEditionDirective = ($repo, $rootscope, $translate, avatarService) -> template = _.template(""" - <%- name %> + <%- name %>
<%- name %>
""") @@ -815,9 +815,14 @@ IssueAssignedToInlineEditionDirective = ($repo, $rootscope, $translate) -> } member = $scope.usersById[issue.assigned_to] + + avatar = avatarService.getAvatar(member) + ctx.imgurl = avatar.url + ctx.bg = null + if member ctx.name = member.full_name_display - ctx.imgurl = member.photo + ctx.bg = avatar.bg $el.find(".avatar").html(template(ctx)) $el.find(".issue-assignedto").attr('title', ctx.name) @@ -849,5 +854,5 @@ IssueAssignedToInlineEditionDirective = ($repo, $rootscope, $translate) -> return {link: link} -module.directive("tgIssueAssignedToInlineEdition", ["$tgRepo", "$rootScope", "$translate" +module.directive("tgIssueAssignedToInlineEdition", ["$tgRepo", "$rootScope", "$translate", "tgAvatarService", IssueAssignedToInlineEditionDirective]) diff --git a/app/coffee/modules/kanban/main.coffee b/app/coffee/modules/kanban/main.coffee index 8b99feba..1d95219e 100644 --- a/app/coffee/modules/kanban/main.coffee +++ b/app/coffee/modules/kanban/main.coffee @@ -524,11 +524,11 @@ module.directive("tgKanbanWipLimit", KanbanWipLimitDirective) ## Kanban User Directive ############################################################################# -KanbanUserDirective = ($log, $compile, $translate) -> +KanbanUserDirective = ($log, $compile, $translate, avatarService) -> template = _.template("""
class="not-clickable"<% } %>> - <%- name %> + <%- name %>
""") @@ -551,16 +551,20 @@ KanbanUserDirective = ($log, $compile, $translate) -> render(user) render = (user) -> + avatar = avatarService.getAvatar(user) + if user is undefined ctx = { name: $translate.instant("COMMON.ASSIGNED_TO.NOT_ASSIGNED"), - imgurl: "/#{window._version}/images/unnamed.png", - clickable: clickable + imgurl: avatar.url, + clickable: clickable, + bg: null } else ctx = { name: user.full_name_display, - imgurl: user.photo, + imgurl: avatar.url, + bg: avatar.bg, clickable: clickable } @@ -593,4 +597,4 @@ KanbanUserDirective = ($log, $compile, $translate) -> return {link: link, require:"ngModel"} -module.directive("tgKanbanUserAvatar", ["$log", "$compile", "$translate", KanbanUserDirective]) +module.directive("tgKanbanUserAvatar", ["$log", "$compile", "$translate", "tgAvatarService", KanbanUserDirective]) diff --git a/app/coffee/modules/related-tasks.coffee b/app/coffee/modules/related-tasks.coffee index 3d6e197d..7bf26155 100644 --- a/app/coffee/modules/related-tasks.coffee +++ b/app/coffee/modules/related-tasks.coffee @@ -265,9 +265,9 @@ RelatedTasksDirective = ($repo, $rs, $rootscope) -> module.directive("tgRelatedTasks", ["$tgRepo", "$tgResources", "$rootScope", RelatedTasksDirective]) -RelatedTaskAssignedToInlineEditionDirective = ($repo, $rootscope, $translate) -> +RelatedTaskAssignedToInlineEditionDirective = ($repo, $rootscope, $translate, avatarService) -> template = _.template(""" - <%- name %> + <%- name %>
<%- name %>
""") @@ -275,11 +275,15 @@ RelatedTaskAssignedToInlineEditionDirective = ($repo, $rootscope, $translate) -> updateRelatedTask = (task) -> ctx = { name: $translate.instant("COMMON.ASSIGNED_TO.NOT_ASSIGNED"), - imgurl: "/" + window._version + "/images/unnamed.png" } + member = $scope.usersById[task.assigned_to] + + avatar = avatarService.getAvatar(member) + ctx.imgurl = avatar.url + ctx.bg = avatar.bg + if member - ctx.imgurl = member.photo ctx.name = member.full_name_display $el.find(".avatar").html(template(ctx)) @@ -318,5 +322,5 @@ RelatedTaskAssignedToInlineEditionDirective = ($repo, $rootscope, $translate) -> return {link: link} -module.directive("tgRelatedTaskAssignedToInlineEdition", ["$tgRepo", "$rootScope", "$translate", +module.directive("tgRelatedTaskAssignedToInlineEdition", ["$tgRepo", "$rootScope", "$translate", "tgAvatarService", RelatedTaskAssignedToInlineEditionDirective]) diff --git a/app/coffee/modules/taskboard/main.coffee b/app/coffee/modules/taskboard/main.coffee index d52d8dff..15b3b753 100644 --- a/app/coffee/modules/taskboard/main.coffee +++ b/app/coffee/modules/taskboard/main.coffee @@ -463,7 +463,7 @@ module.directive("tgTaskboardSquishColumn", ["$tgResources", TaskboardSquishColu ## Taskboard User Directive ############################################################################# -TaskboardUserDirective = ($log, $translate) -> +TaskboardUserDirective = ($log, $translate, avatarService) -> clickable = false link = ($scope, $el, $attrs) -> @@ -473,16 +473,18 @@ TaskboardUserDirective = ($log, $translate) -> $scope.$watch 'task.assigned_to', (assigned_to) -> user = $scope.usersById[assigned_to] + avatar = avatarService.getAvatar(user) + if user is undefined _.assign($scope, { name: $translate.instant("COMMON.ASSIGNED_TO.NOT_ASSIGNED"), - imgurl: "/#{window._version}/images/unnamed.png", + avatar: avatar, clickable: clickable }) else _.assign($scope, { name: user.full_name_display, - imgurl: user.photo, + avatar: avatar, clickable: clickable }) @@ -519,4 +521,4 @@ TaskboardUserDirective = ($log, $translate) -> } -module.directive("tgTaskboardUserAvatar", ["$log", "$translate", TaskboardUserDirective]) +module.directive("tgTaskboardUserAvatar", ["$log", "$translate", "tgAvatarService", TaskboardUserDirective]) diff --git a/app/coffee/modules/wiki/main.coffee b/app/coffee/modules/wiki/main.coffee index f10479b9..745d22c0 100644 --- a/app/coffee/modules/wiki/main.coffee +++ b/app/coffee/modules/wiki/main.coffee @@ -174,7 +174,7 @@ module.controller("WikiDetailController", WikiDetailController) ## Wiki Summary Directive ############################################################################# -WikiSummaryDirective = ($log, $template, $compile, $translate) -> +WikiSummaryDirective = ($log, $template, $compile, $translate, avatarService) -> template = $template.get("wiki/wiki-summary.html", true) link = ($scope, $el, $attrs, $model) -> @@ -184,10 +184,12 @@ WikiSummaryDirective = ($log, $template, $compile, $translate) -> else user = $scope.usersById[wiki.last_modifier] + avatar = avatarService.getAvatar(user) + if user is undefined - user = {name: "unknown", imgUrl: "/" + window._version + "/images/user-noimage.png"} + user = {name: "unknown", avatar: avatar} else - user = {name: user.full_name_display, imgUrl: user.photo} + user = {name: user.full_name_display, avatar: avatar} ctx = { totalEditions: wiki.editions @@ -211,7 +213,7 @@ WikiSummaryDirective = ($log, $template, $compile, $translate) -> require: "ngModel" } -module.directive("tgWikiSummary", ["$log", "$tgTemplate", "$compile", "$translate", WikiSummaryDirective]) +module.directive("tgWikiSummary", ["$log", "$tgTemplate", "$compile", "$translate", "tgAvatarService", WikiSummaryDirective]) ############################################################################# diff --git a/app/images/user-avatars/user-avatar-01.png b/app/images/user-avatars/user-avatar-01.png new file mode 100644 index 0000000000000000000000000000000000000000..6695e8f6af78b3140c9ab02e2581847c0f23efb4 GIT binary patch literal 1088 zcmeAS@N?(olHy`uVBq!ia0y~yVAuk}9Lx+13|zwB7#J8BGXi`|BCE!eSDVQt}E)%Bq@L+Byb?M#d(VR@OGQ_KwbO?jD}rKE45g zK_Q{xkuh=c$tkJn8JStxxrL<_mDP1k&8;0hy?qlVO`bY^#=^x*m#tX2X5ISDTXyW) zbKvlaGuQ9ld-UYl^A~U4zW?y?)0b~Qe*XIX=ijf=Wl{_bOah)Rjv*Dd-rl+%EF37& z_HkGVSoXTS9&K8p6xq%ck1Rqu`|!>mR*~+)Vjv&+?o6^$y-0%KFvEj zy(sIX@y~T9`OiNI)--)O^GkM+RnX(^MftxNz2}{rqt-p|+gBa)H-g)lZ z$vu5hrqlh~7SHzUo_S`*>EFt3`#J2>ehT!-@y;)r4)c7U%w0<*Z>y}cG5du2^4^Mm zwt2pJXU&x8U})gn^SXGu%=6z`8Kc>?zAJln##E?rzh3z%T+-mP?bnrezkN$_{bjoH z{=f2jd9nQa?^b=fzju-{G!!;G`+ceGlxDj9<6y&!Py3U!KZVcbdcRbArSHAJ^DjLQ z%$rfepDhHnNX@FLEp7Rlbh|G`rf+7Jlvt(;!QzkMz-#d@VpiHc9Fe<0VxF#kF6*2U FngD%6z1;u+ literal 0 HcmV?d00001 diff --git a/app/images/user-avatars/user-avatar-02.png b/app/images/user-avatars/user-avatar-02.png new file mode 100644 index 0000000000000000000000000000000000000000..16034e353e6d86b919e6d47ad9adb81b975c3894 GIT binary patch literal 1005 zcmeAS@N?(olHy`uVBq!ia0y~yVAuk}9Lx+13|zwB7#J8Btpj{QTp1V`{*MB(fQ_w{ z1_J{_MoExgFaskq3kN3;AHRU0kcg<5l$^Yxs=BtGfuX6jt&_96r>}o-Sa?KCTzo=e zYFb8SPHtX7NqJRuO>JF$Q*S9f3k#7Q$|&7HS!>9XZ3R|vzPCG{L^2Qdx(L7@u#PYV@SoVw|63=g#slGeDsXb3eYlUzNDhP<-}4C z-#{Oc-1wMDI^W;^u5Vg*u3FFL>;Z$~v@8Grccss>{7}8)p}~i~#{z;d5Ey*7>e=e& z@6&3g^03tA-wmJr{NF29UMZ7|3;*AKqf+a7phB^}_rUE6W|5*?6V4*nfE)ymC&6?VSx>dORz#eD_~o zdd$q{;Nq`sD@8PR1x>m2bjy+Q@-GwXX5J2c*>Czq`0=CscQ0xmFN(adz_GcH%eF|T zH(sjb-Ez&{FO28f%_w&^|K@5PvSs7KYZs?Z5BfOu$w$MwPp(nXlgidCd>j9rfmh1p z#g7H2^YzSrzkGajTXM@gW1H~u*$*EWWPnU$tDSmL*guq0*vfM0FPYQ4!R?&2_Rn_P zfaQ3t3chUmvu5X}?W?UG>|%##0EfT=$L4KKeyK}ezPM=mQ~j&Ms*Q&0#4j%P_C0^B z5v*dpnD(ly+UTv)#arf8zr1vPx%>^M@)Hsv`(sPY*1pCzY3hatQn_sbKAab5r{2v8_81$|) zbYx&)=qd^F3ua(sVrF6E<`WPS77-Jdkdl^>m6KOgR#8<`*VNM1)zddHG&V7_vbM3c zcW`v^@beE22@Q{qjf+o6OiE5k&&bZn%P%M{si>}LYVGLk?&Jj z;i4r=m#tX6cHR0d+js2Sf8fxOqsLF2JazuU)tk3&-??}H$+PD#U%h_&{==uw-+w*% zBk+%bfoZp=i(^Q|t+zL?2MY&^G<@t96qVL8OLE0#W~(b3UyYL&IR>5soFen|)IIpg_K za^=bVlF4>jyiz6^7Z!+{RD~vQoYvo(bUr2UMUlPvO6Pm09+j@%a&mQX#KPwv;=(z< zKW-~I(W0}j^8a~eUMZ6oT29yhPCT}3$&nz!sA?@hR>I6pP-;Q8sdm8(3IcV!iq zy{_E*aO%2kET1C9L3TK{OW*w#Q}x5|*7G;lf~yWQ%U()odb{iQWV<{qQILG|I-6f% z%WjBPzrWP6<@(JHldGElu8!`t(YPFKRuy&bS@U^y*^7J47dSSv@m4i1-u_;v?BVV& z&SLRys_pXycR&5L(R1cU&*Nn$CfodWJvYP8wsZfcA5Z@+dAojjdfCqpYAhxh7aqF! z|NB4p^@c6?_7%71Epuv^cgeo@)vK1;^!<5#?7e;UQ`J&FUbg+U{fxx*jklYACRB&; z`p;b$|4K_Cu`?;_gthbj3s>1LEN~1ruKK=V%Ei$9<)K05n|G~REnzjQJXRO%4>sG? zuH{P|zrUz9dYonOqQkDzBEC)&QhD>H1(_MFobCK;`?D2Sz2q;{7R%m=+`H!Zy`GoPw(d-u!w8A9^zz?}rff53 zFEJL^+9KY_28xtd&gR>_{r4>4dv#;Qdig^6%FcKEFJ?1?t(MLEl9XA@dE}{c7_+Kg zw4Sk&+5@v`7fNnSS9SWj)C%PCaKWmRaxZTrYo^6tTRfZnYnxQ?X`zeEWyb7*Gc z-PLtLw|vPDsnx~1cHU~)toK{>cLQfNI6kcIy!DUBHFa@uaS_S+&+u1SJ*Q!U@<|2; O1_n=8KbLh*2~7ZW7gLA; literal 0 HcmV?d00001 diff --git a/app/images/user-avatars/user-avatar-04.png b/app/images/user-avatars/user-avatar-04.png new file mode 100644 index 0000000000000000000000000000000000000000..4c456402b4db4580f6f34688bfc8dc94a5565953 GIT binary patch literal 1170 zcmeAS@N?(olHy`uVBq!ia0y~yVAuk}9Lx+13|zwB7#J8BO9FgCTp1V`{*MCsf)8ae zE({C|)g?iG!3>Pdtn56zd;)?(BBEmA5|UEVvT_P4s_GhAI{F4i#-?WGme%%8&aQ6m z9^S!Wkx|hxaq$U>X<6AhxdnwK<+XM7jm<4>?Hye`{Szinoi=mU?78z7EMBsF)!KC% zHg4Lob=!`eyAB>ce(Lm@i6Kl%&|OhKM5jv*Dd-rjv} z9ug?i{;_vLOwh`gi&|8;V%?Xv#VB10Sf_Z&_2shH8vkoful_rC>zk|k#g>cbJ%4Lg z{rk)u^Xj*ya|-)9IyyT39bf0i^6Grf-KqYKY?~Y2Me2r~jaSMf7Cmj1o&MVTkF{qtcLlLUl`c5CDP;Psb*B#qURdA=R{g?$;cKfUM^f*< zEqqzGKYv-cl_;mxTGpK}Dl;zcl$-@I&#{?puX5D}{ea(`@lKr1XZO8Z>Y)FrY})i| znKK2$onqMZaw3_aO4A$qVkiCj)El=;b*|~+^%~DpI+xz7ygz%(+}Km*+s|LJoNKqi z`b*(uk-hToo$fzel(|w3>XwqYiys5;uljfOeD=PHOwQJ)_0Bg!JoH~-*NTWu3rpPs zRbFJq{#n2pyP7!|>Vb?4_09WsE4|$BSXwvPDs_QV`W?+RYct!RS{FFJXZ-Te?d8Fa z_sil+lY_LjuZiBO$otyk)71A{?RrFR-({aaJ-^l@H+$9h#fLV9RM_uTV_vCqM;Gd- zFJ+s#_iaqRWa~ORZcFgu7wNp0ZqMKMKJs3JDa-u%dQ(^5iu1~?(h;jk`<293-fLF! zfk6lq1&+;Zva-J}n7*92=(NrY=KV{)I|rS4y0T@_Y26oIvNK8pS->&n*nDsE3n|+? zuT$3Z=C69&zGvgl!;&voblcc|jONXC2wt}V7Owf<1L|&PseO4I@*129G_K@p*q;-O UG5EZffq{X+)78&qol`;+04}cLYybcN literal 0 HcmV?d00001 diff --git a/app/images/user-avatars/user-avatar-05.png b/app/images/user-avatars/user-avatar-05.png new file mode 100644 index 0000000000000000000000000000000000000000..265f94f0e4830c9c3df124fb8671b0d81282e58e GIT binary patch literal 1093 zcmeAS@N?(olHy`uVBq!ia0y~yVAuk}9Lx+13|zwB7#J8BBLjRwTp1V`{*MA00M$$9 z-ZC&S6qN+|1v4-*F|%@V@d^kEi%QDKDk`g}Y3k}3nwnc$S=-pzJ2*PI`}hR}hekw3 z#V01EWfql`R@c-vw6sm0GHvFZx$_n*UAA)d`VAX5Z`rzS$Ijh*_8&TY{Pd;E*RJ2b zbN}I^$4{TXdj0m@`wt&Keg5+G+xH*8|NKpNKGMy=z@+Kv;uunK>+PM$;L8aTZ4X11 zbTxD=P|(`Vu~s45u{$EQkdg7`!Psw0*M9iVFVp|&%Y(}%e}yhT+~+_0`&rZ6^jV(i zk1Sl^KrriB@7b)wj?eXSt}#fNWL#L_*vuyqTNtV({-tSN+K$Ufho4{i{oq2bnfdmY z&sagyY`juiL`y!k-oE~3<89{IFWM`&$IqX?Q?+L8>`UJj9<~HHows0x8l}e-tL`h_ zzi-)R^XxlX-R}FReVn!bp2ww?cjkQgIQdHAEO~>wZc+xmTk<^R)0VC|7hd5yKXplJ z?b6e7yS)3WR;Syr@Is9G?I!=CE8IJ1cjmv3%WiLrTl-~}n%rCO&r28YPxraIz1+0w zdW8_gc~)I7HZH%EE9sf*ZF?;KHE*U%+zwL>-v~G9|1w^$J@&s`QD>`_Yqd(aE1=j&X-pCsUCJvFHOny>8ku&qxN6F>eBVI^G`Re z>+v>UvWjD|HxDR?7dQHudWOHTOzyqp@$$toyO$B)kG@^_c-QwQoh9qPJl&nRpj@~9 zt^+8fO)@UjS8ac^?OyJCPszJCO}8IqSg&B6V>dbFG^aW=HcDzI8GcyMnBv#n%cU|{fc^>bP0l+XkKBCNP0 literal 0 HcmV?d00001 diff --git a/app/modules/components/avatar/avatar.directive.coffee b/app/modules/components/avatar/avatar.directive.coffee new file mode 100644 index 00000000..a8ac3a29 --- /dev/null +++ b/app/modules/components/avatar/avatar.directive.coffee @@ -0,0 +1,49 @@ +### +# Copyright (C) 2014-2016 Taiga Agile LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: avatar.directive.coffee +### + +AvatarDirective = (avatarService) -> + link = (scope, el, attrs) -> + if attrs.tgAvatarBig + attributeName = 'avatarBig' + else + attributeName = 'avatar' + + unwatch = scope.$watch attributeName, (user) -> + avatar = avatarService.getAvatar(user, attributeName) + + el.attr('src', avatar.url) + if avatar.bg + el.css('background', avatar.bg) + + unwatch() if user + + return { + link: link + scope: { + avatar: "=tgAvatar" + avatarBig: "=tgAvatarBig" + } + } + +AvatarDirective.$inject = [ + 'tgAvatarService' +] + +angular.module("taigaComponents").directive("tgAvatar", AvatarDirective) +angular.module("taigaComponents").directive("tgAvatarBig", AvatarDirective) diff --git a/app/modules/external-apps/external-app.jade b/app/modules/external-apps/external-app.jade index 59d42918..0cb5600f 100644 --- a/app/modules/external-apps/external-app.jade +++ b/app/modules/external-apps/external-app.jade @@ -9,7 +9,10 @@ section.external-app-wrapper div.user-card.avatar .card-inner div.user-image - img(ng-src="{{::vm.user.get('photo')}}", alt="{{::vm.user.get('full_name_display')}}") + img( + tg-avatar="vm.user" + alt="{{::vm.user.get('full_name_display')}}" + ) div.user-data h3 {{ ::vm.user.get("full_name_display") }} p {{ ::vm.user.get("email") }} diff --git a/app/modules/history/comments/comment.jade b/app/modules/history/comments/comment.jade index 38d8a2a3..d607b991 100644 --- a/app/modules/history/comments/comment.jade +++ b/app/modules/history/comments/comment.jade @@ -2,7 +2,7 @@ include ../../../partials/common/components/wysiwyg.jade .comment-wrapper(ng-if="!vm.comment.delete_comment_date") img.comment-avatar( - ng-src="{{vm.comment.user.photo}}" + tg-avatar="vm.comment.user" ng-alt="{{vm.comment.user.name}}" ) .comment-main diff --git a/app/modules/history/history-lightbox/history-entry.jade b/app/modules/history/history-lightbox/history-entry.jade index 4df2d67b..b3c5ca4a 100644 --- a/app/modules/history/history-lightbox/history-entry.jade +++ b/app/modules/history/history-lightbox/history-entry.jade @@ -1,6 +1,6 @@ .entry-wrapper img.entry-avatar( - ng-src="{{entry.user.photo}}" + tg-avatar="entry.user" ng-alt="{{entry.user.name}}" ) .entry-main diff --git a/app/modules/history/history/history.jade b/app/modules/history/history/history.jade index d53d022c..9e3836fb 100644 --- a/app/modules/history/history/history.jade +++ b/app/modules/history/history/history.jade @@ -2,7 +2,7 @@ section.activities .activities-wrapper .activity(ng-repeat="activity in activities track by activity.id") img.activity-avatar( - ng-src="{{activity.user.photo}}" + tg-avatar="activity.user" ng-alt="{{activity.user.name}}" ) .activity-main diff --git a/app/modules/home/duties/duty.jade b/app/modules/home/duties/duty.jade index eb7e2601..970a3a4c 100644 --- a/app/modules/home/duties/duty.jade +++ b/app/modules/home/duties/duty.jade @@ -11,8 +11,8 @@ a.list-itemtype-ticket( div.list-itemtype-avatar(ng-if="vm.type == 'watching'") img( ng-if="vm.duty.get('assigned_to_extra_info')" - ng-src="{{ ::vm.duty.get('assigned_to_extra_info').get('photo') }}" title="{{ ::vm.duty.get('assigned_to_extra_info').get('full_name_display') }}" + tg-avatar="vm.duty.get('assigned_to_extra_info')" ) img( ng-if="!vm.duty.get('assigned_to_extra_info')" diff --git a/app/modules/navigation-bar/dropdown-user/dropdown-user.jade b/app/modules/navigation-bar/dropdown-user/dropdown-user.jade index 8131593f..2db8f69a 100644 --- a/app/modules/navigation-bar/dropdown-user/dropdown-user.jade +++ b/app/modules/navigation-bar/dropdown-user/dropdown-user.jade @@ -3,11 +3,10 @@ a.user-avatar( title="{{ vm.user.get('full_name_display') }}" ) {{ vm.user.get('full_name_display') }} img( - ng-src="{{ vm.user.get('photo') }}" + tg-avatar="vm.user" alt="{{ vm.user.get('full_name_display') }}" - width="48px" height="40px" - ) + ) div.navbar-dropdown.dropdown-user ul diff --git a/app/modules/navigation-bar/navigation-bar.scss b/app/modules/navigation-bar/navigation-bar.scss index 8cdda49f..a04122cc 100644 --- a/app/modules/navigation-bar/navigation-bar.scss +++ b/app/modules/navigation-bar/navigation-bar.scss @@ -77,7 +77,7 @@ $dropdown-width: 350px; } img { height: 2.5rem; - padding-left: .5rem; + margin-left: .5rem; vertical-align: middle; } svg { diff --git a/app/modules/profile/profile-bar/profile-bar.jade b/app/modules/profile/profile-bar/profile-bar.jade index 8a53a4ad..a3ae25ec 100644 --- a/app/modules/profile/profile-bar/profile-bar.jade +++ b/app/modules/profile/profile-bar/profile-bar.jade @@ -1,6 +1,9 @@ section.profile-bar div.profile-image-wrapper(ng-class="::{'is-current-user': vm.isCurrentUser}") - img.profile-img(ng-src="{{::vm.user.get('big_photo')}}", alt="{{::vm.user.get('full_name')}}") + img.profile-img( + tg-avatar="vm.user" + alt="{{::vm.user.get('full_name')}}" + ) a.profile-edition(title="{{ 'USER.PROFILE.EDIT' | translate }}", tg-nav="user-settings-user-profile", translate="USER.PROFILE.EDIT") div.profile-data h1(ng-class="{'not-full-name': !vm.user.get('full_name')}") {{::vm.user.get("full_name_display")}} diff --git a/app/modules/profile/profile-contacts/profile-contacts.jade b/app/modules/profile/profile-contacts/profile-contacts.jade index c4dc8b71..5f8d2ef6 100644 --- a/app/modules/profile/profile-contacts/profile-contacts.jade +++ b/app/modules/profile/profile-contacts/profile-contacts.jade @@ -14,7 +14,10 @@ section.profile-contacts div.list-itemtype-user(tg-repeat="contact in ::vm.contacts") a.list-itemtype-avatar(tg-nav="user-profile:username=contact.get('username')", title="{{::contact.get('name')}}") - img(ng-src="{{::contact.get('photo')}}", alt="{{::contact.get('full_name')}}") + img( + tg-avatar="contact" + alt="{{::contact.get('full_name')}}" + ) div.list-itemtype-user-data h2 diff --git a/app/modules/profile/profile-favs/items/ticket.jade b/app/modules/profile/profile-favs/items/ticket.jade index 7f974ea4..170109d2 100644 --- a/app/modules/profile/profile-favs/items/ticket.jade +++ b/app/modules/profile/profile-favs/items/ticket.jade @@ -3,11 +3,11 @@ href="" ng-if="::vm.item.get('assigned_to')" tg-nav="user-profile:username=vm.item.get('assigned_to_username')" - title="{{ ::vm.item.get('assigned_to_full_name') }}" + title="{{ ::vm.item.getIn(['assigned_to_extra_info', 'full_name_display']) }}" ) img( - ng-src="{{ ::vm.item.get('assigned_to_photo') }}", - alt="{{ ::vm.item.get('assigned_to_full_name') }}" + tg-avatar="{{ ::vm.item.get('assigned_to_extra_info') }}", + alt="{{ ::vm.item.getIn(['assigned_to_extra_info', 'full_name_display']) }}" ) a.list-itemtype-avatar( diff --git a/app/modules/profile/profile-projects/profile-projects.jade b/app/modules/profile/profile-projects/profile-projects.jade index a1d361f8..df8de196 100644 --- a/app/modules/profile/profile-projects/profile-projects.jade +++ b/app/modules/profile/profile-projects/profile-projects.jade @@ -63,4 +63,4 @@ section.profile-projects tg-nav="user-profile:username=contact.get('username')" title="{{::contact.get('full_name')}}" ) - img(ng-src="{{::contact.get('photo')}}") + tg-avatar="contact" diff --git a/app/modules/projects/project/project.jade b/app/modules/projects/project/project.jade index 731d3d59..cc3acb5a 100644 --- a/app/modules/projects/project/project.jade +++ b/app/modules/projects/project/project.jade @@ -68,7 +68,10 @@ div.wrapper tg-nav="user-profile:username=member.get('username')", title="{{::member.get('full_name')}}" ) - img(ng-src="{{::member.get('photo')}}", alt="{{::member.get('full_name')}}") + img( + tg-avatar="member" + alt="{{::member.get('full_name')}}" + ) tg-svg( ng-if="member.get('id') == vm.project.getIn(['owner', 'id'])" svg-icon="icon-badge" diff --git a/app/modules/services/avatar.service.coffee b/app/modules/services/avatar.service.coffee new file mode 100644 index 00000000..add6b311 --- /dev/null +++ b/app/modules/services/avatar.service.coffee @@ -0,0 +1,93 @@ +### +# Copyright (C) 2014-2015 Taiga Agile LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: avatar.service.coffee +### + +class AvatarService + constructor: () -> + IMAGES = [ + "/#{window._version}/images/user-avatars/user-avatar-01.png" + "/#{window._version}/images/user-avatars/user-avatar-02.png" + "/#{window._version}/images/user-avatars/user-avatar-03.png" + "/#{window._version}/images/user-avatars/user-avatar-04.png" + "/#{window._version}/images/user-avatars/user-avatar-05.png" + ] + + COLORS = [ + "rgba( 178, 176, 204, 1 )" + "rgba( 183, 203, 131, 1 )" + "rgba( 210, 198, 139, 1 )" + "rgba( 178, 178, 178, 1 )" + "rgba( 247, 154, 154, 1 )" + ] + + @.logos = _.cartesianProduct(IMAGES, COLORS) + + getDefault: (key) -> + idx = murmurhash3_32_gc(key, 42) %% @.logos.length + logo = @.logos[idx] + + return { src: logo[0], color: logo[1] } + + getUnnamed: () -> + return { + url: "/#{window._version}/images/unnamed.png" + } + + getAvatar: (user, type) -> + return getUnnamed() if !user + + avatarParamName = 'photo' + + if type == 'avatarBig' + avatarParamName = 'big_photo' + + photo = null + + if user instanceof Immutable.Map + gravatar = user.get('gravatar_id') + photo = user.get(avatarParamName) + else + gravatar = user.gravatar_id + photo = user[avatarParamName] + + return getUnnamed() if !gravatar + + if photo + return { + url: photo + } + else if location.host.indexOf('localhost') != -1 + root = location.protocol + '//' + location.host + logo = @.getDefault(gravatar) + + return { + url: root + logo.src, + bg: logo.color + } + else + root = location.protocol + '//' + location.host + logo = @.getDefault(gravatar) + + logoUrl = encodeURIComponent(root + logo.src) + + return { + url: 'https://www.gravatar.com/avatar/' + gravatar + "?d=" + logoUrl, + bg: logo.color + } + +angular.module("taigaCommon").service("tgAvatarService", AvatarService) diff --git a/app/modules/user-timeline/user-timeline-item/user-timeline-item.jade b/app/modules/user-timeline/user-timeline-item/user-timeline-item.jade index 38a492ee..43604994 100644 --- a/app/modules/user-timeline/user-timeline-item/user-timeline-item.jade +++ b/app/modules/user-timeline/user-timeline-item/user-timeline-item.jade @@ -7,10 +7,16 @@ div.activity-item // profile image with url div.profile-contact-picture(ng-if="timeline.getIn(['data', 'user', 'is_profile_visible'])") a(tg-nav="user-profile:username=timeline.getIn(['data', 'user', 'username'])", title="{{::timeline.getIn(['data', 'user', 'name']) }}") - img(ng-src="{{::timeline.getIn(['data', 'user', 'photo']) || '/#{v}/images/user-noimage.png'}}", alt="{{::timeline.getIn(['data', 'user', 'name'])}}") + img( + tg-avatar="timeline.getIn(['data', 'user'])" + alt="{{::timeline.getIn(['data', 'user', 'name'])}}" + ) // profile image without url div.profile-contact-picture(ng-if="!timeline.getIn(['data', 'user', 'is_profile_visible'])") - img(ng-src="{{::timeline.getIn(['data', 'user', 'photo']) || '/#{v}/images/user-noimage.png'}}", alt="{{::timeline.getIn(['data', 'user', 'name'])}}") + img( + tg-avatar="timeline.getIn(['data', 'user'])" + alt="{{::timeline.getIn(['data', 'user', 'name'])}}" + ) p(tg-compile-html="timeline.get('title_html')") @@ -19,7 +25,10 @@ div.activity-item .activity-member-view(ng-if="::timeline.has('member')") a.profile-member-picture(tg-nav="user-profile:username=timeline.getIn(['member', 'user', 'username'])", title="{{::timeline.getIn(['member', 'user', 'name'])}}") - img(ng-src="{{::timeline.getIn(['member', 'user', 'photo'])}}", alt="{{::timeline.getIn(['member','user', 'name'])}}") + img( + tg-avatar="timeline.getIn(['member', 'user'])" + alt="{{::timeline.getIn(['member','user', 'name'])}}" + ) .activity-member-info a(tg-nav="user-profile:username=timeline.getIn(['member', 'user', 'username'])", title="{{::timeline.getIn(['member','user', 'name'])}}") span {{::timeline.getIn(['member','user', 'name'])}} diff --git a/app/modules/wiki/history/wiki-history-entry.jade b/app/modules/wiki/history/wiki-history-entry.jade index d8d2633c..aa25e102 100644 --- a/app/modules/wiki/history/wiki-history-entry.jade +++ b/app/modules/wiki/history/wiki-history-entry.jade @@ -1,6 +1,6 @@ .activity img.activity-avatar( - ng-src="{{singleHistoryEntry.user.photo}}" + tg-avatar="singleHistoryEntry.user" ng-alt="{{singleHistoryEntry.user.name}}" ) .activity-main diff --git a/app/partials/admin/admin-project-change-owner.jade b/app/partials/admin/admin-project-change-owner.jade index b7a4766a..f29c67d5 100644 --- a/app/partials/admin/admin-project-change-owner.jade +++ b/app/partials/admin/admin-project-change-owner.jade @@ -1,5 +1,5 @@ .owner-avatar - img(ng-src="{{owner.photo || '/#{v}/images/user-noimage.png'}}", alt="{{::owner.full_name_display}}") + img(tg-avatar="owner", alt="{{::owner.full_name_display}}") .owner-info .owner-info-title {{ 'ADMIN.PROJECT_PROFILE.PROJECT_OWNER' | translate }} diff --git a/app/partials/admin/admin-project-request-ownership.jade b/app/partials/admin/admin-project-request-ownership.jade index 713bd6b6..7e17b3e7 100644 --- a/app/partials/admin/admin-project-request-ownership.jade +++ b/app/partials/admin/admin-project-request-ownership.jade @@ -1,5 +1,5 @@ .owner-avatar - img(ng-src="{{owner.photo || '/#{v}/images/user-noimage.png'}}", alt="{{::owner.full_name_display}}") + img(tg-avatar="owner", alt="{{::owner.full_name_display}}") .owner-info .title {{ 'ADMIN.PROJECT_PROFILE.PROJECT_OWNER' | translate }} diff --git a/app/partials/admin/memberships-row-avatar.jade b/app/partials/admin/memberships-row-avatar.jade index a15f3b45..ccebb315 100644 --- a/app/partials/admin/memberships-row-avatar.jade +++ b/app/partials/admin/memberships-row-avatar.jade @@ -1,5 +1,8 @@ figure.avatar - img(src!="<%- imgurl %>", alt!="<%- full_name %>") + img( + style!="background-color: <%- bg %>" + src!="<%- imgurl %>", alt!="<%- full_name %>" + ) figcaption span.name(ng-non-bindable) <%- full_name %> <% if (isOwner) { %> diff --git a/app/partials/auth/invitation.jade b/app/partials/auth/invitation.jade index 6288b606..ececd510 100644 --- a/app/partials/auth/invitation.jade +++ b/app/partials/auth/invitation.jade @@ -2,8 +2,10 @@ div.wrapper div.invitation-main div.centered.invitation-container(tg-invitation) a.avatar(href="", tg-bo-title="invitation.invited_by.full_name_display") - img(tg-bo-src="invitation.invited_by.photo", - tg-bo-alt="invitation.invited_by.full_name_display") + img( + tg-avatar="invitation.invited_by" + tg-bo-alt="invitation.invited_by.full_name_display" + ) span.person-name(tg-bo-bind="invitation.invited_by.full_name_display") span.invitation-text diff --git a/app/partials/common/components/assigned-to.jade b/app/partials/common/components/assigned-to.jade index e5f68800..3a8f8eb1 100644 --- a/app/partials/common/components/assigned-to.jade +++ b/app/partials/common/components/assigned-to.jade @@ -1,5 +1,9 @@ .user-avatar(class!="<% if (isIocaine) { %> is-iocaine <% }; %>") - img(src!="<%- photo %>", alt!="<%- fullName %>") + img( + style!="background-color: <%- bg %>" + src!="<%- avatar %>" + alt!="<%- fullName %>" + ) <% if (isIocaine) { %> .iocaine-symbol(title="{{ 'TASK.TITLE_ACTION_IOCAINE' | translate }}") tg-svg(svg-icon="icon-iocaine") diff --git a/app/partials/common/components/created-by.jade b/app/partials/common/components/created-by.jade index 8486d0fa..606a014d 100644 --- a/app/partials/common/components/created-by.jade +++ b/app/partials/common/components/created-by.jade @@ -12,6 +12,7 @@ title="{{owner.full_name_display}}" ) img( - src="{{owner.photo}}" + ng-style="{'background': owner.bg}" + ng-src="{{owner.avatar}}" alt="{{owner.full_name_display}}" ) diff --git a/app/partials/common/components/list-item-assigned-to-avatar.jade b/app/partials/common/components/list-item-assigned-to-avatar.jade index bb2ead9c..e8535d23 100644 --- a/app/partials/common/components/list-item-assigned-to-avatar.jade +++ b/app/partials/common/components/list-item-assigned-to-avatar.jade @@ -1,3 +1,7 @@ div.avatar - img(src!="<%- imgurl %>", alt!="<%- name %>") + img( + style!="background-color: <%- bg %>" + src!="<%- imgurl %>" + alt!="<%- name %>" + ) span.avatar-caption <%- name %> diff --git a/app/partials/common/components/user-display.jade b/app/partials/common/components/user-display.jade index 3e6bb71a..3ac35373 100644 --- a/app/partials/common/components/user-display.jade +++ b/app/partials/common/components/user-display.jade @@ -4,7 +4,8 @@ title="{{user.full_name_display}}" ) img( - src="{{user.photo}}" + ng-style="{'background-color': user.bg}" + ng-src="{{user.avatar}}" alt="{{user.full_name_display}}" ) a.user-full-name( @@ -15,7 +16,8 @@ a.user-full-name( .user-avatar(ng-if="!url") img( - src="{{user.photo}}" + ng-style="{'background-color': user.bg}" + ng-src="{{user.avatar}}" alt="{{user.full_name_display}}" ) span.user-full-name(ng-if="!url") {{user.full_name_display}} diff --git a/app/partials/common/components/watchers.jade b/app/partials/common/components/watchers.jade index fa5da31e..b899353e 100644 --- a/app/partials/common/components/watchers.jade +++ b/app/partials/common/components/watchers.jade @@ -1,20 +1,15 @@ -<% _.each(watchers, function(watcher) { %> -<% if(watcher) { %> -.user-list-single +.user-list-single(ng-repeat="watcher in watchers") .user-list-avatar img( - src!="<%- watcher.photo %>" - alt!="<%- watcher.full_name_display %>" + tg-avatar="watcher" + alt="{{watcher.full_name_display}}" ) .user-list-name - span(ng-non-bindable) <%- watcher.full_name_display %> + span {{watcher.full_name_display}} - <% if(isEditable){ %> tg-svg.js-delete-watcher.delete-watcher( + ng-if="isEditable" svg-icon="icon-trash", svg-title-translate="COMMON.WATCHERS.DELETE", - data-watcher-id!="<%- watcher.id %>" + data-watcher-id="{{watcher.id}}" ) - <% }; %> -<% } %> -<% }); %> diff --git a/app/partials/common/lightbox/lightbox-assigned-to-users.jade b/app/partials/common/lightbox/lightbox-assigned-to-users.jade index 39065790..16c06377 100644 --- a/app/partials/common/lightbox/lightbox-assigned-to-users.jade +++ b/app/partials/common/lightbox/lightbox-assigned-to-users.jade @@ -5,7 +5,10 @@ href="" title="{{'COMMON.ASSIGNED_TO' | translate}}" ) - img(src!="<%- selected.photo %>") + img( + style!="background: <%- selected.avatar.bg %>" + src!="<%- selected.avatar.url %>" + ) a.user-list-name( href="" title!="<%- selected.full_name_display %>" @@ -25,7 +28,10 @@ href="#" title="{{'COMMON.ASSIGNED_TO.TITLE' | translate}}" ) - img(src!="<%- user.photo %>") + img( + style!="background: <%- user.avatar.bg %>" + src!="<%- user.avatar.url %>" + ) a.user-list-name( href="" title!="<%- user.full_name_display %>" diff --git a/app/partials/common/lightbox/lightbox-change-owner.jade b/app/partials/common/lightbox/lightbox-change-owner.jade index a1264699..dc4f912d 100644 --- a/app/partials/common/lightbox/lightbox-change-owner.jade +++ b/app/partials/common/lightbox/lightbox-change-owner.jade @@ -18,7 +18,7 @@ tg-lightbox-close href="#" title="{{'COMMON.ASSIGNED_TO.TITLE' | translate}}" ) - img(ng-src="{{vm.selected.photo}}") + img(tg-avatar="{{vm.selected}}") a.user-list-name( href="" title="{{vm.selected.full_name_display}}" @@ -33,7 +33,8 @@ tg-lightbox-close href="#" title="{{'COMMON.ASSIGNED_TO.TITLE' | translate}}" ) - img(ng-src="{{user.photo}}") + img(tg-avatar="user") + a.user-list-name( href="" title="{{user.full_name_display}}" diff --git a/app/partials/taskboard/taskboard-user.jade b/app/partials/taskboard/taskboard-user.jade index ca05113f..70f25205 100644 --- a/app/partials/taskboard/taskboard-user.jade +++ b/app/partials/taskboard/taskboard-user.jade @@ -1,6 +1,15 @@ figure.avatar.avatar-assigned-to a(href='#', title="{{'TASKBOARD.TITLE_ACTION_ASSIGN' | translate}}", ng-class="{'not-clickable': !clickable}") - img(ng-src='{{imgurl}}') + img( + ng-style="{'background-color': avatar.bg}" + ng-src='{{avatar.url}}' + ) figure.avatar.avatar-task-link - a(tg-nav='project-tasks-detail:project=project.slug,ref=task.ref', ng-attr-title='{{task.subject}}') - img(ng-src='{{imgurl}}') + a( + tg-nav='project-tasks-detail:project=project.slug,ref=task.ref' + ng-attr-title='{{task.subject}}' + ) + img( + ng-style="{'background-color': avatar.bg}" + ng-src='{{avatar.url}}' + ) diff --git a/app/partials/team/team-member-current-user.jade b/app/partials/team/team-member-current-user.jade index caefc7e5..683d79ad 100644 --- a/app/partials/team/team-member-current-user.jade +++ b/app/partials/team/team-member-current-user.jade @@ -1,7 +1,7 @@ .row .username .avatar - img(tg-bo-src="currentUser.photo", tg-bo-alt="currentUser.full_name_display") + img(tg-avatar="currentUser", tg-bo-alt="currentUser.full_name_display") .avatar-data .name diff --git a/app/partials/team/team-members.jade b/app/partials/team/team-members.jade index 2155d134..0a1fbae4 100644 --- a/app/partials/team/team-members.jade +++ b/app/partials/team/team-members.jade @@ -1,7 +1,7 @@ .row.member(ng-repeat="user in memberships | membersFilter:filtersQ:filtersRole") .username .avatar - img(tg-bo-src="user.photo", tg-bo-alt="user.full_name_display") + img(tg-avatar="user", tg-bo-alt="user.full_name_display") .avatar-data a.name( diff --git a/app/partials/user/user-profile.jade b/app/partials/user/user-profile.jade index 2eb62e65..fc3518bd 100644 --- a/app/partials/user/user-profile.jade +++ b/app/partials/user/user-profile.jade @@ -16,7 +16,7 @@ div.wrapper( form .project-details-image(tg-user-avatar) fieldset.image-container - img.image(ng-src="{{user.big_photo}}" alt="avatar") + img.image(tg-avatar="user" alt="avatar") .loading-overlay img.loading-spinner( src="/#{v}/svg/spinner-circle.svg", diff --git a/app/partials/wiki/wiki-summary.jade b/app/partials/wiki/wiki-summary.jade index e1708e7b..8acc644e 100644 --- a/app/partials/wiki/wiki-summary.jade +++ b/app/partials/wiki/wiki-summary.jade @@ -1,6 +1,10 @@ .wiki-username-edition .avatar - img(src!="<%- user.imgUrl %>" alt!="<%- user.name %>") + img( + style!="background-color: <%- user.avatar.bg %>" + src!="<%- user.avatar.url %>" + alt!="<%- user.name %>" + ) .wiki-user-modification span.description(translate="WIKI.SUMMARY.LAST_MODIFICATION") span.username <%- user.name %> @@ -8,16 +12,16 @@ .wiki-last-modified span.number <%- lastModifiedDate %> span.description(translate="WIKI.SUMMARY.LAST_EDIT") - + .wiki-times-edited span.number <%- totalEditions %> span.description(translate="WIKI.SUMMARY.TIMES_EDITED") - + tg-svg.remove( tg-check-permission="delete_wiki_page" title="{{'WIKI.REMOVE' | translate}}" ng-click="ctrl.delete()" svg-icon="icon-trash" ng-if="wiki.id" - + )