new user avatar directive

stable
Juanfran 2016-07-19 15:02:00 +02:00 committed by David Barragán Merino
parent 2e3a8b3c9a
commit 51b5897d88
46 changed files with 343 additions and 110 deletions

View File

@ -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.

View File

@ -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])
#############################################################################

View File

@ -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 = ->

View File

@ -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])
#############################################################################

View File

@ -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("""
<img src="<%- imgurl %>" alt="<%- name %>"/>
<img style="background-color: <%- bg %>" src="<%- imgurl %>" alt="<%- name %>"/>
<figcaption><%- name %></figcaption>
""")
@ -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])

View File

@ -524,11 +524,11 @@ module.directive("tgKanbanWipLimit", KanbanWipLimitDirective)
## Kanban User Directive
#############################################################################
KanbanUserDirective = ($log, $compile, $translate) ->
KanbanUserDirective = ($log, $compile, $translate, avatarService) ->
template = _.template("""
<figure class="avatar">
<a href="#" title="{{'US.ASSIGN' | translate}}" <% if (!clickable) {%>class="not-clickable"<% } %>>
<img src="<%- imgurl %>" alt="<%- name %>" class="avatar">
<img style="background-color: <%- bg %>" src="<%- imgurl %>" alt="<%- name %>" class="avatar">
</a>
</figure>
""")
@ -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])

View File

@ -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("""
<img src="<%- imgurl %>" alt="<%- name %>"/>
<img style="background-color: <%- bg %>" src="<%- imgurl %>" alt="<%- name %>"/>
<figcaption><%- name %></figcaption>
""")
@ -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])

View File

@ -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])

View File

@ -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])
#############################################################################

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1005 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1,49 @@
###
# Copyright (C) 2014-2016 Taiga Agile LLC <taiga@taiga.io>
#
# 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 <http://www.gnu.org/licenses/>.
#
# 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)

View File

@ -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") }}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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')"

View File

@ -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

View File

@ -77,7 +77,7 @@ $dropdown-width: 350px;
}
img {
height: 2.5rem;
padding-left: .5rem;
margin-left: .5rem;
vertical-align: middle;
}
svg {

View File

@ -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")}}

View File

@ -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

View File

@ -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(

View File

@ -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"

View File

@ -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"

View File

@ -0,0 +1,93 @@
###
# Copyright (C) 2014-2015 Taiga Agile LLC <taiga@taiga.io>
#
# 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 <http://www.gnu.org/licenses/>.
#
# 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)

View File

@ -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'])}}

View File

@ -1,6 +1,6 @@
.activity
img.activity-avatar(
ng-src="{{singleHistoryEntry.user.photo}}"
tg-avatar="singleHistoryEntry.user"
ng-alt="{{singleHistoryEntry.user.name}}"
)
.activity-main

View File

@ -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 }}

View File

@ -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 }}

View File

@ -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) { %>

View File

@ -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

View File

@ -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")

View File

@ -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}}"
)

View File

@ -1,3 +1,7 @@
div.avatar
img(src!="<%- imgurl %>", alt!="<%- name %>")
img(
style!="background-color: <%- bg %>"
src!="<%- imgurl %>"
alt!="<%- name %>"
)
span.avatar-caption <%- name %>

View File

@ -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}}

View File

@ -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}}"
)
<% }; %>
<% } %>
<% }); %>

View File

@ -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 %>"

View File

@ -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}}"

View File

@ -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}}'
)

View File

@ -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

View File

@ -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(

View File

@ -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",

View File

@ -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"
)