Allow a user to edit its profile or avatar from a member popover

Fixes the data context on the member popover in the details pane. Also
change the way Popover detect if the click is initiated from a parent
popover -- from reading Blaze context, to looking at the event target
parents.
This commit is contained in:
Maxime Quandalle 2015-06-19 14:39:38 +02:00
parent fad4cba5e2
commit 8cf9ec2660
8 changed files with 70 additions and 55 deletions

View file

@ -44,8 +44,9 @@ template(name="boardMenuPopup")
if currentUser.isBoardMember if currentUser.isBoardMember
ul.pop-over-list ul.pop-over-list
li: a.js-open-archives Archived elements li: a.js-open-archives Archived elements
li: a.js-change-board-color Change color if currentUser.isBoardAdmin
li: a Permissions li: a.js-change-board-color Change color
li: a Permissions
hr hr
ul.pop-over-list ul.pop-over-list
li: a Copy this board li: a Copy this board

View file

@ -39,7 +39,7 @@ template(name="cardDetails")
a.card-label.add-label.js-add-labels a.card-label.add-label.js-add-labels
i.fa.fa-plus i.fa.fa-plus
//- XXX We should use "editable" to avoide repetiting ourselves //- XXX We should use "editable" to avoid repetiting ourselves
if currentUser.isBoardMember if currentUser.isBoardMember
h3.card-details-item-title Description h3.card-details-item-title Description
+inlinedForm(classNames="card-description js-card-description") +inlinedForm(classNames="card-description js-card-description")

View file

@ -32,6 +32,6 @@ template(name="cardLabelsPopup")
span.card-label.card-label-selectable.js-select-label(class="card-label-{{color}}" span.card-label.card-label-selectable.js-select-label(class="card-label-{{color}}"
class="{{# if isLabelSelected ../_id }}active{{/ if }}") class="{{# if isLabelSelected ../_id }}active{{/ if }}")
= name = name
if currentUser.isBoardAdmin if isLabelSelected ../_id
span.card-label-selectable-icon.fa.fa-check i.card-label-selectable-icon.fa.fa-check
a.quiet-button.full.js-add-label {{_ 'label-create'}} a.quiet-button.full.js-add-label {{_ 'label-create'}}

View file

@ -9,6 +9,11 @@ template(name="userAvatar")
span.member-presence-status(class=presenceStatusClassName) span.member-presence-status(class=presenceStatusClassName)
span.member-type(class=memberType) span.member-type(class=memberType)
if showEdit
if $eq currentUser._id userData._id
a.edit-avatar.js-change-avatar
i.fa.fa-pencil
template(name="userAvatarInitials") template(name="userAvatarInitials")
svg.avatar.avatar-initials(viewBox="0 0 {{viewPortWidth}} 15") svg.avatar.avatar-initials(viewBox="0 0 {{viewPortWidth}} 15")
text(x="0" y="13")= initials text(x="0" y="13")= initials
@ -18,9 +23,8 @@ template(name="userPopup")
.mini-profile-info .mini-profile-info
+userAvatar(userId=user._id) +userAvatar(userId=user._id)
.info .info
h3.bottom h3= user.profile.fullname
= user.profile.fullname p.quiet @{{ user.username }}
p.quiet.bottom @{{ user.username }}
template(name="memberName") template(name="memberName")
if showBoth if showBoth
@ -61,10 +65,14 @@ template(name="changeAvatarPopup")
template(name="cardMemberPopup") template(name="cardMemberPopup")
.board-member-menu .board-member-menu
.mini-profile-info .mini-profile-info
+userAvatar(userId=user._id) +userAvatar(userId=user._id showEdit=true)
.info .info
h3.bottom= user.profile.fullname h3= user.profile.fullname
p.quiet.bottom @{{ user.username }} p.quiet @{{ user.username }}
if currentUser.isBoardMember if currentUser.isBoardMember
ul.pop-over-list ul.pop-over-list
li: a.js-remove-member {{_ 'remove-member-from-card'}} li: a.js-remove-member {{_ 'remove-member-from-card'}}
if $eq currentUser._id user._id
with currentUser
li: a.js-edit-profile Edit Profile

View file

@ -26,6 +26,10 @@ Template.userAvatar.helpers({
} }
}); });
Template.userAvatar.events({
'click .js-change-avatar': Popup.open('changeAvatar')
});
Template.userAvatarInitials.helpers({ Template.userAvatarInitials.helpers({
initials: function() { initials: function() {
var user = Users.findOne(this.userId); var user = Users.findOne(this.userId);
@ -142,9 +146,16 @@ Template.cardMembersPopup.events({
} }
}); });
Template.cardMemberPopup.helpers({
user: function() {
return Users.findOne(this.userId);
}
});
Template.cardMemberPopup.events({ Template.cardMemberPopup.events({
'click .js-remove-member': function() { 'click .js-remove-member': function() {
Cards.update(this.cardId, {$pull: {members: this.userId}}); Cards.update(this.cardId, {$pull: {members: this.userId}});
Popup.close(); Popup.close();
} },
'click .js-edit-profile': Popup.open('editProfile')
}); });

View file

@ -56,39 +56,24 @@ avatar-radius = 50%
background: #bdbdbd background: #bdbdbd
border-color: #ededed border-color: #ededed
&.extra-small .edit-avatar
.avatar-initials position: absolute
font-size: 9px top: 0
width: 18px height: 100%
height: 18px width: 100%
line-height: 18px border-radius: avatar-radius
background: black
display: flex
align-items: center
justify-content: center
opacity: 0
.avatar-image &:hover
width: 18px opacity: 0.6
height: 18px
&.small i.fa-pencil
width: 30px color: white
height: 30px
.avatar-initials
font-size: 12px
line-height: 30px
&.large
height: 85px
line-height: 85px
width: 85px
.avatar
width: 85px
height: 85px
.avatar-initials
font-size: 16px
font-weight: 700
line-height: 85px
width: 85px
&.add-member &.add-member
display: flex display: flex
@ -106,3 +91,19 @@ avatar-radius = 50%
&.me &.me
background: #cfdfe8 background: #cfdfe8
.mini-profile-info
margin-top: 10px
.info
padding-top: 5px
h3, p
margin-bottom: 0
p
padding-top: 0
.member
width: 50px
height: @width
margin-right: 10px

View file

@ -24,7 +24,7 @@ template(name="editProfilePopup")
form form
label label
| {{_ "fullname"}} | {{_ "fullname"}}
input.js-profile-fullname(type="text" value=profile.name autofocus) input.js-profile-fullname(type="text" value=profile.fullname autofocus)
label label
| {{_ "username"}} | {{_ "username"}}
input.js-profile-username(type="text" value=username) input.js-profile-username(type="text" value=username)

View file

@ -16,6 +16,10 @@ Popup = {
var self = this; var self = this;
var popupName = name + 'Popup'; var popupName = name + 'Popup';
var clickFromPopup = function(evt) {
return $(evt.target).closest('.js-pop-over').length !== 0;
};
return function(evt) { return function(evt) {
// If a popup is already openened, clicking again on the opener element // If a popup is already openened, clicking again on the opener element
// should close it -- and interupt the current `open` function. // should close it -- and interupt the current `open` function.
@ -34,7 +38,7 @@ Popup = {
// has one. This allows us to position a sub-popup exactly at the same // has one. This allows us to position a sub-popup exactly at the same
// position than its parent. // position than its parent.
var openerElement; var openerElement;
if (self._hasPopupParent()) { if (clickFromPopup(evt)) {
openerElement = self._getTopStack().openerElement; openerElement = self._getTopStack().openerElement;
} else { } else {
self._stack = []; self._stack = [];
@ -47,9 +51,8 @@ Popup = {
// We push our popup data to the stack. The top of the stack is always // We push our popup data to the stack. The top of the stack is always
// used as the data source for our current popup. // used as the data source for our current popup.
self._stack.push({ self._stack.push({
__isPopup: true,
popupName: popupName, popupName: popupName,
hasPopupParent: self._hasPopupParent(), hasPopupParent: clickFromPopup(evt),
title: self._getTitle(popupName), title: self._getTitle(popupName),
openerElement: openerElement, openerElement: openerElement,
depth: self._stack.length, depth: self._stack.length,
@ -155,15 +158,6 @@ Popup = {
return this._stack[this._stack.length - 1]; return this._stack[this._stack.length - 1];
}, },
// We use the blaze API to determine if the current popup has been opened from
// a parent popup. The number we give to the `Template.parentData` has been
// determined experimentally and is susceptible to change if you modify the
// `Popup.template`
_hasPopupParent: function() {
var tryParentData = Template.parentData(3);
return !! (tryParentData && tryParentData.__isPopup);
},
// We automatically calculate the popup offset from the reference element // We automatically calculate the popup offset from the reference element
// position and dimensions. We also reactively use the window dimensions to // position and dimensions. We also reactively use the window dimensions to
// ensure that the popup is always visible on the screen. // ensure that the popup is always visible on the screen.