diff options
-rw-r--r-- | .jshintrc | 1 | ||||
-rw-r--r-- | .meteor/packages | 1 | ||||
-rw-r--r-- | .meteor/versions | 5 | ||||
-rw-r--r-- | client/components/activities/templates.html | 6 | ||||
-rw-r--r-- | client/components/cards/details.jade | 4 | ||||
-rw-r--r-- | client/components/cards/events.js | 4 | ||||
-rw-r--r-- | client/components/cards/minicard.jade | 2 | ||||
-rw-r--r-- | client/components/cards/templates.html | 6 | ||||
-rw-r--r-- | client/components/forms/forms.styl | 3 | ||||
-rw-r--r-- | client/components/lists/main.js | 2 | ||||
-rw-r--r-- | client/components/main/popup.styl | 74 | ||||
-rw-r--r-- | client/components/sidebar/sidebar.jade | 8 | ||||
-rw-r--r-- | client/components/sidebar/sidebarFilters.jade | 2 | ||||
-rw-r--r-- | client/components/users/userAvatar.jade | 38 | ||||
-rw-r--r-- | client/components/users/userAvatar.js | 84 | ||||
-rw-r--r-- | client/components/users/userHeader.jade | 4 | ||||
-rw-r--r-- | client/components/users/userProfile.html | 79 | ||||
-rw-r--r-- | client/components/users/userProfile.js | 31 | ||||
-rw-r--r-- | client/config/avatar.js | 3 | ||||
-rw-r--r-- | collections/avatars.js | 27 | ||||
-rw-r--r-- | collections/users.js | 1 | ||||
-rw-r--r-- | server/publications/avatars.js | 3 |
22 files changed, 161 insertions, 227 deletions
@@ -55,6 +55,7 @@ "SubsManager": false, "Mousetrap": false, "Avatar": true, + "Avatars": true, "Ps": true, "Presence": true, "Presences": true, diff --git a/.meteor/packages b/.meteor/packages index 8509d2ec..87d21d6c 100644 --- a/.meteor/packages +++ b/.meteor/packages @@ -46,7 +46,6 @@ tmeasday:presence underscore # UI components -bengott:avatar fortawesome:fontawesome linto:jquery-ui mousetrap:mousetrap diff --git a/.meteor/versions b/.meteor/versions index 46ab71d1..5fe0a841 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -6,7 +6,6 @@ alethes:pages@1.8.4 audit-argument-checks@1.0.3 autoupdate@1.2.1 base64@1.0.3 -bengott:avatar@0.7.6 binary-heap@1.0.3 blaze@2.1.2 blaze-tools@1.0.3 @@ -52,9 +51,6 @@ iron:location@1.0.9 iron:middleware-stack@1.0.9 iron:router@1.0.9 iron:url@1.0.9 -jparker:crypto-core@0.1.0 -jparker:crypto-md5@0.1.1 -jparker:gravatar@0.3.1 jquery@1.11.3_2 json@1.0.3 kenton:accounts-sandstorm@0.1.3 @@ -107,7 +103,6 @@ softwarerero:accounts-t9n@1.0.9 spacebars@1.0.6 spacebars-compiler@1.0.6 srp@1.0.3 -stylus@1.0.7 tap:i18n@1.4.1 templating@1.1.1 tmeasday:presence@1.0.6 diff --git a/client/components/activities/templates.html b/client/components/activities/templates.html index 8d3ff763..5a595a36 100644 --- a/client/components/activities/templates.html +++ b/client/components/activities/templates.html @@ -1,7 +1,7 @@ <template name="boardActivities"> {{# each currentBoard.activities }} <div class="phenom phenom-action clearfix phenom-other"> - {{> userAvatar user=user size="extra-small" class="creator js-show-mem-menu" }} + {{> userAvatar userId=user._id}} <div class="phenom-desc"> {{ > memberName user=user }} @@ -86,7 +86,7 @@ <template name="cardActivities"> {{# each currentCard.comments }} <div class="phenom phenom-action clearfix phenom-comment"> - {{> userAvatar user=user size="small" class="creator js-show-mem-menu" }} + {{> userAvatar userId=user._id}} <form> <div class="phenom-desc"> {{ > memberName user=user }} @@ -115,7 +115,7 @@ {{# each currentCard.activities }} <div class="phenom phenom-action clearfix phenom-other"> - {{> userAvatar user=user size="extra-small" class="creator js-show-mem-menu" }} + {{> userAvatar userId=user._id size="extra-small" class="creator js-show-mem-menu" }} {{ > memberName user=user }} {{# if $eq activityType 'createCard' }} {{_ 'activity-added' cardLabel list.title}}. diff --git a/client/components/cards/details.jade b/client/components/cards/details.jade index 5ee962cd..dc3d3dc3 100644 --- a/client/components/cards/details.jade +++ b/client/components/cards/details.jade @@ -27,7 +27,7 @@ template(name="cardDetails") .card-details-item.card-details-item-members h3 {{_ 'members'}} each members - +userAvatar(userId=this size="small" cardId=../_id) + +userAvatar(userId=this cardId=../_id) a.member.add-member.card-details-item-add-button.js-add-members i.fa.fa-plus @@ -86,7 +86,7 @@ template(name="cardMembersPopup") each board.members li.item(class="{{#if isCardMember}}active{{/if}}") a.name.js-select-member(href="#") - +userAvatar(user=user size="small") + +userAvatar(userId=user._id) span.full-name = user.profile.name | (<span class="username">{{ user.username }}</span>) diff --git a/client/components/cards/events.js b/client/components/cards/events.js index 21d628df..2363f4de 100644 --- a/client/components/cards/events.js +++ b/client/components/cards/events.js @@ -134,7 +134,7 @@ Template.createLabelPopup.events({ 'submit .create-label': function(evt, tpl) { var name = tpl.$('#labelName').val().trim(); var boardId = Session.get('currentBoard'); - var selectLabelDom = tpl.$('.js-palette-select:not(.hide)').get(0); + var selectLabelDom = tpl.$('.js-palette-select').get(0); var selectLabel = Blaze.getData(selectLabelDom); Boards.update(boardId, { $push: { @@ -166,7 +166,7 @@ Template.editLabelPopup.events({ var name = tpl.$('#labelName').val().trim(); var boardId = Session.get('currentBoard'); var getLabel = Utils.getLabelIndex(boardId, this._id); - var selectLabelDom = tpl.$('.js-palette-select:not(.hide)').get(0); + var selectLabelDom = tpl.$('.js-palette-select').get(0); var selectLabel = Blaze.getData(selectLabelDom); var $set = {}; diff --git a/client/components/cards/minicard.jade b/client/components/cards/minicard.jade index efca9673..670b1f89 100644 --- a/client/components/cards/minicard.jade +++ b/client/components/cards/minicard.jade @@ -10,7 +10,7 @@ template(name="minicard") if members .minicard-members.js-minicard-members each members - +userAvatar(userId=this size="small" cardId="{{../_id}}") + +userAvatar(userId=this) .badges if comments.count .badge(title="{{_ 'card-comments-title' comments.count }}") diff --git a/client/components/cards/templates.html b/client/components/cards/templates.html index d003f051..dfa21ace 100644 --- a/client/components/cards/templates.html +++ b/client/components/cards/templates.html @@ -1,7 +1,7 @@ <template name="cardMemberPopup"> <div class="board-member-menu"> <div class="mini-profile-info"> - {{> userAvatar user=user }} + {{> userAvatar userId=user._id }} <div class="info"> <h3 class="bottom" style="margin-right: 40px;"> <a class="js-profile" href="{{ pathFor route='Profile' username=user.username }}">{{ user.profile.name }}</a> @@ -125,7 +125,7 @@ <h3 class="card-details-item-header">{{_ 'members'}}</h3> <div class="js-card-details-members-list clearfix"> {{# each card.members }} - {{> userAvatar userId=this size="small" cardId=../card._id }} + {{> userAvatar userId=this}} {{/ each }} <a class="card-details-item-add-button dark-hover js-details-edit-members"> <span class="icon-sm fa fa-plus"></span> @@ -196,7 +196,7 @@ </div> {{# if currentUser.isBoardMember }} <div class="new-comment js-new-comment"> - {{> userAvatar user=currentUser size="small" class="member-no-menu" }} + {{> userAvatar userId=currentUser._id}} <form id="CommentForm"> {{#editor class="new-comment-input js-new-comment-input"}}{{/editor}} <div class="add-controls clearfix"> diff --git a/client/components/forms/forms.styl b/client/components/forms/forms.styl index 1f62ca34..f13a7e79 100644 --- a/client/components/forms/forms.styl +++ b/client/components/forms/forms.styl @@ -156,6 +156,9 @@ button box-shadow: 0 1px 0 #4d4d4d color: #fff + i.fa + margin-right: 10px + input[type="submit"].disabled, input[type="submit"]:disabled, input[type="button"].disabled, diff --git a/client/components/lists/main.js b/client/components/lists/main.js index 2b07c3ee..520d0772 100644 --- a/client/components/lists/main.js +++ b/client/components/lists/main.js @@ -25,7 +25,7 @@ BlazeComponent.extendComponent({ return; var boardComponent = self.componentParent(); - var itemsSelector = '.js-minicard:not(.placeholder, .hide, .js-composer)'; + var itemsSelector = '.js-minicard:not(.placeholder, .js-composer)'; var $cards = self.$('.js-minicards'); $cards.sortable({ connectWith: '.js-minicards', diff --git a/client/components/main/popup.styl b/client/components/main/popup.styl index 43b0dae7..ce40fc83 100644 --- a/client/components/main/popup.styl +++ b/client/components/main/popup.styl @@ -13,7 +13,7 @@ hr margin: 4px -10px - width: 275px + 2*10px + width: 300px input[type="text"], input[type="email"], @@ -122,12 +122,8 @@ margin-bottom: 8px .pop-over-list - &.navigable li.not-selectable>a:hover, - li.not-selectable>a:hover - color: #8c8c8c - cursor: default - li > a + clear: both cursor: pointer display: block font-weight: 700 @@ -153,7 +149,6 @@ background: #fff .sub-name - clear: both color: #8c8c8c display: block font-size: 12px @@ -164,21 +159,6 @@ &.current background-color: #e2e6e9 - .unread-indicator - background: #2e85b8 - background: linear-gradient(to bottom, #2e85b8 0, #2b7cab 100%) - border-radius: 7px - display: block - height: 14px - opacity: 0 - position: absolute - right: 16px - top: 8px - width: 14px - - &.any - opacity: 1 - &:active background-color: #2e85b8 @@ -204,8 +184,7 @@ margin: 0 .pop-over-list.checkable - - .icon-check + .fa-check display: none position: absolute top: 6px @@ -214,54 +193,9 @@ li.active a padding-right: 28px - .icon-check + .fa-check display: block - &.left-check - - .icon-check - right: auto - left: 10px - - li a - padding-right: 10px - padding-left: 30px - - li.active a - padding-right: 10px - - &.normal-weight li>a - font-weight: 400 - - &.navigable - - li > a:hover - background-color: transparent - color: #4d4d4d - - .sub-name, - .quiet - color: #8c8c8c - - li.selected > a - background-color: #005377 - color: #fff - - .sub-name, - .quiet - color: #eee - - li.selected > a - - &.current - background-color: #005377 - - .unread-indicator - background: #fff - - &:active - background-color: #005377 - .pop-over.miniprofile .header border-bottom-color: transparent diff --git a/client/components/sidebar/sidebar.jade b/client/components/sidebar/sidebar.jade index e6265a61..303ce352 100644 --- a/client/components/sidebar/sidebar.jade +++ b/client/components/sidebar/sidebar.jade @@ -27,11 +27,7 @@ template(name="membersWidget") | {{_ 'members'}} .board-widget-content each currentBoard.members - +userAvatar( - userId=this.userId - draggable=true - size="small" - showStatus=true) + +userAvatar(userId=this.userId showStatus=true) unless isSandstorm if currentUser.isBoardAdmin a.member.add-member.js-manage-board-members @@ -86,7 +82,7 @@ template(name="addMemberPopup") +esEach(index="users") li.item.js-member-item(class="{{#if isBoardMember }}disabled{{/if}}") a.name.js-select-member(title="{{ profile.name }} ({{ username }})") - +userAvatar(user=this size="small") + +userAvatar(userId=_id) span.full-name = profile.name | (<span class="username">{{ username }}</span>) diff --git a/client/components/sidebar/sidebarFilters.jade b/client/components/sidebar/sidebarFilters.jade index 34b3074f..29b65f3b 100644 --- a/client/components/sidebar/sidebarFilters.jade +++ b/client/components/sidebar/sidebarFilters.jade @@ -23,7 +23,7 @@ template(name="filterSidebar") with getUser userId li(class="{{#if Filter.members.isSelected _id}}active{{/if}}") a.name.js-toogle-member-filter - +userAvatar(user=this size="small") + +userAvatar(userId=this._id) span.sidebar-list-item-description = profile.name | (<span class="username">{{ username }}</span>) diff --git a/client/components/users/userAvatar.jade b/client/components/users/userAvatar.jade index 98682eb5..9542f6c4 100644 --- a/client/components/users/userAvatar.jade +++ b/client/components/users/userAvatar.jade @@ -1,22 +1,42 @@ template(name="userAvatar") - .member.js-member(class="{{class}}" title="{{userData.profile.name}} ({{userData.username}})") - +avatar(user=userData size=size) + .member.js-member(title="{{userData.profile.fullname}} ({{userData.username}})") + if userData.profile.avatarUrl + img.avatar.avatar-image(src=userData.profile.avatarUrl) if showStatus span.member-presence-status(class=presenceStatusClassName) span.member-type(class=memberType) - template(name="userPopup") .board-member-menu .mini-profile-info +userAvatar(user=user) - .info - h3.bottom - a.js-profile(href="{{ pathFor route='Profile' username=user.username }}")= user.profile.name - p.quiet.bottom @{{ user.username }} + .info + h3.bottom + a.js-profile(href="{{pathFor route='Profile' username=user.username}}")= user.profile.name + p.quiet.bottom @{{ user.username }} template(name="memberName") - a.inline-object.js-show-mem-menu(href="{{ pathFor route='Profile' username=user.username }}") - = user.profile.name + a.js-show-mem-menu(href="{{pathFor route='Profile' username=user.username}}") + = user.profile.fullname if username | ({{ user.username }}) + +template(name="changeAvatarPopup") + ul.pop-over-list + each uploadedAvatars + li: a.js-select-avatar + .member: .avatar + img.avatar-image(src="{{url avatarUrlOptions}}") + | Uploaded avatar + if isSelected + i.fa.fa-check + p.sub-name + unless isSelected + a.js-delete-avatar + | Delete + | - + = original.name + input.hide.js-upload-avatar-input(accept="image/*;capture=camera" type="file") + button.full.js-upload-avatar + i.fa.fa-upload + | Upload an avatar diff --git a/client/components/users/userAvatar.js b/client/components/users/userAvatar.js index d7d221db..deae01cf 100644 --- a/client/components/users/userAvatar.js +++ b/client/components/users/userAvatar.js @@ -1,17 +1,22 @@ +Meteor.subscribe('my-avatars'); + Template.userAvatar.helpers({ userData: function() { - if (! this.user) { - this.user = Users.findOne(this.userId); - } - return this.user; + return Users.findOne(this.userId, { + fields: { + profile: 1, + username: 1 + } + }); }, + memberType: function() { - var userId = this.userId || this.user._id; - var user = Users.findOne(userId); + var user = Users.findOne(this.userId); return user && user.isBoardAdmin() ? 'admin' : 'normal'; }, + presenceStatusClassName: function() { - var userPresence = Presences.findOne({ userId: this.user._id }); + var userPresence = Presences.findOne({ userId: this.userId }); if (! userPresence) return 'disconnected'; else if (Session.equals('currentBoard', userPresence.state.currentBoardId)) @@ -20,3 +25,68 @@ Template.userAvatar.helpers({ return 'idle'; } }); + +BlazeComponent.extendComponent({ + template: function() { + return 'changeAvatarPopup'; + }, + + avatarUrlOptions: function() { + return { + auth: false, + brokenIsFine: true + }; + }, + + uploadedAvatars: function() { + return Avatars.find({userId: Meteor.userId()}); + }, + + isSelected: function() { + var userProfile = Meteor.user().profile; + var avatarUrl = userProfile && userProfile.avatarUrl; + var currentAvatarUrl = this.currentData().url(this.avatarUrlOptions()); + return avatarUrl === currentAvatarUrl; + }, + + setAvatar: function(avatarUrl) { + Meteor.users.update(Meteor.userId(), { + $set: { + 'profile.avatarUrl': avatarUrl + } + }); + }, + + events: function() { + return [{ + 'click .js-upload-avatar': function() { + this.$('.js-upload-avatar-input').click(); + }, + 'change .js-upload-avatar-input': function(evt) { + var self = this; + var file, fileUrl; + + FS.Utility.eachFile(evt, function(f) { + file = Avatars.insert(new FS.File(f)); + fileUrl = file.url(self.avatarUrlOptions()); + }); + var fetchAvatarInterval = window.setInterval(function() { + $.ajax({ + url: fileUrl, + success: function() { + self.setAvatar(file.url(self.avatarUrlOptions())); + window.clearInterval(fetchAvatarInterval); + } + }); + }, 100); + }, + 'click .js-select-avatar': function() { + var avatarUrl = this.currentData().url(this.avatarUrlOptions()); + this.setAvatar(avatarUrl); + }, + 'click .js-delete-avatar': function() { + Avatars.remove(this.currentData()._id); + } + }]; + } +}).register('changeAvatarPopup'); diff --git a/client/components/users/userHeader.jade b/client/components/users/userHeader.jade index 960264a9..f30ee09d 100644 --- a/client/components/users/userHeader.jade +++ b/client/components/users/userHeader.jade @@ -7,7 +7,7 @@ template(name="headerUserBar") else = currentUser.username a.header-user-bar-avatar.js-change-avatar - +userAvatar(user=currentUser) + +userAvatar(userId=currentUser._id) template(name="memberMenuPopup") ul.pop-over-list @@ -33,8 +33,6 @@ template(name="editProfilePopup") input.js-profile-initials(type="text" value=profile.initials) input.primary.wide(type="submit" value="{{_ 'save'}}") -template(name="changeAvatarPopup") - template(name="changePasswordPopup") +atForm(state='changePwd') diff --git a/client/components/users/userProfile.html b/client/components/users/userProfile.html deleted file mode 100644 index 3d1f8c9b..00000000 --- a/client/components/users/userProfile.html +++ /dev/null @@ -1,79 +0,0 @@ -<template name='profile'> - {{ # if profile }} - <div class="tabbed-pane-header"> - <div class="tabbed-pane-header-wrapper clearfix"> - <a class="tabbed-pane-header-image profile-image ed js-change-avatar-profile" href="#"> - {{> userAvatar user=profile size="large"}} - </a> - <div class="tabbed-pane-header-details"> - <div class="js-current-details"> - <div class="tabbed-pane-header-details-name"> - <h1 class="inline"> {{ profile.profile.name }} </h1> - <p class="window-title-extra quiet"> @{{ profile.username }} </p> - </div> - <div class="tabbed-pane-header-details-content"> - <p>{{ profile.profile.bio }}</p> - </div> - <div class="tabbed-pane-header-details-content"></div> - </div> - {{ > profileEditForm }} - </div> - </div> - </div> - {{ else }} - {{ > message label='user-profile-not-found' }} - {{ /if }} -</template> - -<template name="settings"> - {{ > profile profile=currentUser }} - <div class="tabbed-pane-main-col clearfix"> - <div class="tabbed-pane-main-col-loading hide js-loading-page"> - <span class="tabbed-pane-main-col-loading-spinner spinner"></span> - </div> - <div class="tabbed-pane-main-col-wrapper js-content"> - <div class="window-module clearfix"> - <div class="window-module-title"> - <h3>{{_ "account-details"}}</h3> - </div> - <a class="big-link js-change-name-and-bio" href="#"> - <span class="text">{{_ 'change-name-initials-bio'}}</span> - </a> - <a class="big-link js-change-avatar" href="#"> - <span class="text">{{_ 'change-avatar'}}</span> - </a> - <a class="big-link js-change-password" href="#"> - <span class="text">{{_ 'change-password'}}</span> - </a> - <a class="big-link js-change-email" href="#"> - <span class="text">{{_ 'change-email'}}</span> - </a> - </div> - </div> - </div> -</template> - -<template name="profileEditForm"> - {{#if $eq currentUser.username profile.username }} - {{# if session 'ProfileEditForm' }} - <form id="ProfileEditForm" class="js-profile-form"> - <p class="error js-profile-form-error hide"></p> - <label>{{_ "username"}}</label> - <input type="text" id="username" value="{{ profile.username }}" disabled> - <label>{{_ "fullname"}}</label> - <input type="text" id="name" value="{{ profile.profile.name }}"> - <label> - {{_ "bio"}} <span class="quiet">({{_ 'optional'}})</span> - </label> - <textarea id="bio">{{ profile.profile.bio }}</textarea> - <input type="submit" class="primary wide js-submit-profile" value="{{_ 'save'}}"> - <input type="button" class="js-cancel-edit-profile" value="{{_ 'cancel'}}"> - </form> - {{ else }} - <a class="button-link tabbed-pane-header-details-edit js-edit-profile" href="#"> - <span class="icon-sm fa fa-pencil"></span> - {{_ "edit-profile"}} - </a> - {{ /if }} - {{ /if }} -</template> diff --git a/client/components/users/userProfile.js b/client/components/users/userProfile.js deleted file mode 100644 index 040abed0..00000000 --- a/client/components/users/userProfile.js +++ /dev/null @@ -1,31 +0,0 @@ -Template.profileEditForm.events({ - 'click .js-edit-profile': function() { - Session.set('ProfileEditForm', true); - }, - 'click .js-cancel-edit-profile': function() { - Session.set('ProfileEditForm', false); - }, - 'submit #ProfileEditForm': function(evt, t) { - var name = t.find('#name').value; - var bio = t.find('#bio').value; - - // trim and update - if ($.trim(name)) { - Users.update(this.profile()._id, { - $set: { - 'profile.name': name, - 'profile.bio': bio - } - }, function() { - - // update complete close profileEditForm - Session.set('ProfileEditForm', false); - }); - } - evt.preventDefault(); - } -}); - -Template.memberName.events({ - 'click .js-show-mem-menu': Popup.open('user') -}); diff --git a/client/config/avatar.js b/client/config/avatar.js deleted file mode 100644 index fc4ba58b..00000000 --- a/client/config/avatar.js +++ /dev/null @@ -1,3 +0,0 @@ -Avatar.options = { - fallbackType: 'initials' -}; diff --git a/collections/avatars.js b/collections/avatars.js new file mode 100644 index 00000000..5ca074ee --- /dev/null +++ b/collections/avatars.js @@ -0,0 +1,27 @@ +Avatars = new FS.Collection('avatars', { + stores: [ + new FS.Store.GridFS('avatars') + ], + filter: { + maxSize: 32000, + allow: { + contentTypes: ['image/*'] + } + } +}); + +var isOwner = function(userId, file) { + return userId && userId === file.userId; +}; + +Avatars.allow({ + insert: isOwner, + update: isOwner, + remove: isOwner, + download: function() { return true; }, + fetch: ['userId'] +}); + +Avatars.files.before.insert(function(userId, doc) { + doc.userId = userId; +}); diff --git a/collections/users.js b/collections/users.js index 8d1c0d58..304011f6 100644 --- a/collections/users.js +++ b/collections/users.js @@ -43,6 +43,7 @@ Users.helpers({ Meteor.methods({ setUsername: function(username) { + check(username, String); var nUsersWithUsername = Users.find({username: username}).count(); if (nUsersWithUsername > 0) { throw new Meteor.Error('username-already-taken'); diff --git a/server/publications/avatars.js b/server/publications/avatars.js new file mode 100644 index 00000000..dca5692b --- /dev/null +++ b/server/publications/avatars.js @@ -0,0 +1,3 @@ +Meteor.publish('my-avatars', function() { + return Avatars.find({ userId: this.userId }); +}); |