summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMaxime Quandalle <maxime@quandalle.com>2015-06-12 13:59:39 +0200
committerMaxime Quandalle <maxime@quandalle.com>2015-06-12 17:48:15 +0200
commitc8945679872a0708eb67a477a99a65d508c84cb0 (patch)
tree5cf9f2cc842f891451f7bc247b5f0833c1ab39e7
parent216887490e3be0ba141484afc11d37475e91562d (diff)
downloadwekan-c8945679872a0708eb67a477a99a65d508c84cb0.tar.gz
wekan-c8945679872a0708eb67a477a99a65d508c84cb0.tar.bz2
wekan-c8945679872a0708eb67a477a99a65d508c84cb0.zip
Work on the card activities and comments
This commit also introduces a new CSSEvents object that is used to abstract vendor specifics events related to CSS transitions and animations. Fixes #183. Fixes #179.
-rw-r--r--.jshintrc1
-rw-r--r--client/components/activities/activities.jade107
-rw-r--r--client/components/activities/activities.js36
-rw-r--r--client/components/activities/activities.styl28
-rw-r--r--client/components/activities/comments.jade8
-rw-r--r--client/components/activities/comments.js49
-rw-r--r--client/components/activities/comments.styl40
-rw-r--r--client/components/activities/events.js30
-rw-r--r--client/components/activities/templates.html154
-rw-r--r--client/components/boards/boardBody.js11
-rw-r--r--client/components/boards/boardHeader.jade2
-rw-r--r--client/components/cards/details.jade32
-rw-r--r--client/components/cards/details.js31
-rw-r--r--client/components/cards/details.styl69
-rw-r--r--client/components/cards/events.js182
-rw-r--r--client/components/cards/helpers.js48
-rw-r--r--client/components/cards/labels.jade27
-rw-r--r--client/components/cards/labels.js126
-rw-r--r--client/components/cards/labels.styl16
-rw-r--r--client/components/cards/minicard.jade2
-rw-r--r--client/components/cards/minicard.styl26
-rw-r--r--client/components/cards/templates.html110
-rw-r--r--client/components/forms/forms.styl5
-rw-r--r--client/components/main/editor.styl2
-rw-r--r--client/components/main/popup.js21
-rw-r--r--client/components/users/userAvatar.jade22
-rw-r--r--client/components/users/userAvatar.js37
-rw-r--r--client/config/helpers.js6
-rw-r--r--client/lib/cssEvents.js42
-rw-r--r--client/styles/main.styl3
-rw-r--r--collections/cards.js10
31 files changed, 591 insertions, 692 deletions
diff --git a/.jshintrc b/.jshintrc
index 23a24645..ac8b3192 100644
--- a/.jshintrc
+++ b/.jshintrc
@@ -71,6 +71,7 @@
"AccountsTemplates": true,
// Our objects
+ "CSSEvents": true,
"EscapeActions": true,
"Filter": true,
"Filter": true,
diff --git a/client/components/activities/activities.jade b/client/components/activities/activities.jade
index 1c6b9faf..dd47af7f 100644
--- a/client/components/activities/activities.jade
+++ b/client/components/activities/activities.jade
@@ -1,8 +1,113 @@
template(name="activities")
- .js-sidebar-activities
+ .activities.js-sidebar-activities
//- We should use Template.dynamic here but there is a bug with
//- blaze-components: https://github.com/peerlibrary/meteor-blaze-components/issues/30
if $eq mode "board"
+boardActivities
else
+cardActivities
+
+template(name="boardActivities")
+ each currentBoard.activities
+ .activity
+ +userAvatar(userId=user._id)
+ p.activity-desc
+ +memberName(user=user)
+
+ if($eq activityType 'createBoard')
+ | {{_ 'activity-created' boardLabel}}.
+
+ if($eq activityType 'createList')
+ | {{_ 'activity-added' list.title boardLabel}}.
+
+ if($eq activityType 'archivedList')
+ | {{_ 'activity-archived' list.title}}.
+
+ if($eq activityType 'createCard')
+ | {{{_ 'activity-added' cardLink boardLabel}}}.
+
+ if($eq activityType 'archivedCard')
+ | {{{_ 'activity-archived' cardLink}}}.
+
+ if($eq activityType 'restoredCard')
+ | {{{_ 'activity-sent' cardLink boardLabel}}}.
+
+ if($eq activityType 'moveCard')
+ | {{{_ 'activity-moved' cardLink oldList.title list.title}}}.
+
+ if($eq activityType 'addBoardMember')
+ | {{{_ 'activity-added' memberLink boardLabel}}}.
+
+ if($eq activityType 'removeBoardMember')
+ | {{{_ 'activity-excluded' memberLink boardLabel}}}.
+
+ if($eq activityType 'joinMember')
+ if($eq currentUser._id member._id)
+ | {{{_ 'activity-joined' cardLink}}}.
+ else
+ | {{{_ 'activity-added' memberLink cardLink}}}.
+
+ if($eq activityType 'unjoinMember')
+ if($eq currentUser._id member._id)
+ | {{{_ 'activity-unjoined' cardLink}}}.
+ else
+ | {{{_ 'activity-removed' memberLink cardLink}}}.
+
+ if($eq activityType 'addComment')
+ | {{{_ 'activity-on' cardLink}}}
+ a.activity-comment(href="{{ card.absoluteUrl }}")
+ +viewer
+ = comment.text
+
+ if($eq activityType 'addAttachment')
+ | {{{_ 'activity-attached' attachmentLink cardLink}}}.
+
+ span.activity-meta {{ moment createdAt }}
+
+template(name="cardActivities")
+ each currentCard.activities
+ .activity
+ +userAvatar(userId=user._id)
+ p.activity-desc
+ +memberName(user=user)
+ if($eq activityType 'createCard')
+ | {{_ 'activity-added' cardLabel list.title}}.
+ if($eq activityType 'joinMember')
+ if($eq currentUser._id member._id)
+ | {{_ 'activity-joined' cardLabel}}.
+ else
+ | {{{_ 'activity-added' cardLabel memberLink}}}.
+ if($eq activityType 'unjoinMember')
+ if($eq currentUser._id member._id)
+ | {{_ 'activity-unjoined' cardLabel}}.
+ else
+ | {{{_ 'activity-removed' cardLabel memberLink}}}.
+ if($eq activityType 'archivedCard')
+ | {{_ 'activity-archived' cardLabel}}.
+ if($eq activityType 'restoredCard')
+ | {{_ 'activity-sent' cardLabel boardLabel}}.
+ if($eq activityType 'moveCard')
+ | {{_ 'activity-moved' cardLabel oldList.title list.title}}.
+ if($eq activityType 'addAttachment')
+ | {{{_ 'activity-attached' attachmentLink cardLabel}}}.
+ if attachment.isImage
+ img.attachment-image-preview(src=attachment.url)
+
+ if($eq activityType 'addComment')
+ +inlinedForm(classNames='js-edit-comment')
+ +editor(autofocus=true)
+ = comment.text
+ .edit-controls
+ button.primary(type="submit") {{_ 'edit'}}
+ else
+ .activity-comment
+ +viewer
+ = comment.text
+ span.activity-meta
+ | {{ moment createdAt }} -
+ a.js-open-inlined-form {{_ "edit"}}
+ = ' - '
+ a.js-delete-comment {{_ "delete"}}
+
+ else
+ span.activity-meta {{ moment createdAt }}
diff --git a/client/components/activities/activities.js b/client/components/activities/activities.js
index c806e87b..5d95006a 100644
--- a/client/components/activities/activities.js
+++ b/client/components/activities/activities.js
@@ -49,10 +49,6 @@ BlazeComponent.extendComponent({
return TAPi18n.__('this-board');
},
- cardLabel: function() {
- return TAPi18n.__('this-card');
- },
-
cardLink: function() {
var card = this.currentData().card();
return Blaze.toHTML(HTML.A({
@@ -75,3 +71,35 @@ BlazeComponent.extendComponent({
}, attachment.name()));
}
}).register('activities');
+
+BlazeComponent.extendComponent({
+ template: function() {
+ return 'cardActivities';
+ },
+
+ cardLabel: function() {
+ return TAPi18n.__('this-card');
+ },
+
+ events: function() {
+ return [{
+ // XXX We should use Popup.afterConfirmation here
+ 'click .js-delete-comment': function() {
+ var commentId = this.currentData().commentId;
+ CardComments.remove(commentId);
+ },
+ 'submit .js-edit-comment': function(evt) {
+ evt.preventDefault();
+ var commentText = this.currentComponent().getValue();
+ var commentId = Template.parentData().commentId;
+ if ($.trim(commentText)) {
+ CardComments.update(commentId, {
+ $set: {
+ text: commentText
+ }
+ });
+ }
+ }
+ }];
+ }
+}).register('cardActivities');
diff --git a/client/components/activities/activities.styl b/client/components/activities/activities.styl
new file mode 100644
index 00000000..de2b796d
--- /dev/null
+++ b/client/components/activities/activities.styl
@@ -0,0 +1,28 @@
+.activities
+ clear: both
+
+ .activity
+ margin: 6px 0
+ display: flex
+
+ .member
+ width: 24px
+ height: @width
+
+ .activity-desc
+ flex: 1
+ align-self: center
+ margin: 0
+
+ .activity-comment
+ display: block
+ border-radius: 3px
+ background: white
+ text-decoration: none
+ box-shadow: 0 1px 2px rgba(0,0,0,.2)
+ margin-top: 5px
+ padding: 5px
+
+ .activity-meta
+ font-size: 0.8em
+ color: darken(white, 40%)
diff --git a/client/components/activities/comments.jade b/client/components/activities/comments.jade
index e69de29b..3b47cbf6 100644
--- a/client/components/activities/comments.jade
+++ b/client/components/activities/comments.jade
@@ -0,0 +1,8 @@
+template(name="commentForm")
+ .new-comment.js-new-comment(
+ class="{{#if commentFormIsOpen}}is-open{{/if}}")
+ +userAvatar(userId=currentUser._id)
+ form.js-new-comment-form
+ +editor(class="js-new-comment-input")
+ .add-controls
+ button.primary.confirm.clear.js-add-comment(type="submit") {{_ 'comment'}}
diff --git a/client/components/activities/comments.js b/client/components/activities/comments.js
index e69de29b..d41b86dd 100644
--- a/client/components/activities/comments.js
+++ b/client/components/activities/comments.js
@@ -0,0 +1,49 @@
+var commentFormIsOpen = new ReactiveVar(false);
+
+Template.commentForm.helpers({
+ commentFormIsOpen: function() {
+ return commentFormIsOpen.get();
+ }
+});
+
+Template.commentForm.events({
+ 'click .js-new-comment:not(.focus)': function() {
+ commentFormIsOpen.set(true);
+ },
+ 'submit .js-new-comment-form': function(evt, tpl) {
+ var input = tpl.$('.js-new-comment-input');
+ if ($.trim(input.val())) {
+ CardComments.insert({
+ boardId: this.boardId,
+ cardId: this._id,
+ text: input.val()
+ });
+ input.val('');
+ input.blur();
+ commentFormIsOpen.set(false);
+ Tracker.flush();
+ autosize.update(input);
+ }
+ evt.preventDefault();
+ },
+ // Pressing Ctrl+Enter should submit the form
+ 'keydown form textarea': function(evt, tpl) {
+ if (evt.keyCode === 13 && (evt.metaKey || evt.ctrlKey)) {
+ tpl.find('button[type=submit]').click();
+ }
+ }
+});
+
+Template.commentForm.onDestroyed(function() {
+ commentFormIsOpen.set(false);
+});
+
+EscapeActions.register('inlinedForm',
+ function() {
+ commentFormIsOpen.set(false);
+ $('.js-new-comment-input').blur();
+ },
+ function() { return commentFormIsOpen.get(); }, {
+ noClickEscapeOn: '.js-new-comment'
+ }
+);
diff --git a/client/components/activities/comments.styl b/client/components/activities/comments.styl
index f372e5ef..1857ca99 100644
--- a/client/components/activities/comments.styl
+++ b/client/components/activities/comments.styl
@@ -8,15 +8,15 @@
top: 1px
left: -38px
- &.focus
+ &.is-open
.member
opacity: 1
.helper
display: inline-block
- .new-comment-input
- min-height: 108px
+ textarea
+ min-height: 100px
color: #4d4d4d
cursor: auto
overflow: hidden
@@ -25,22 +25,22 @@
.too-long
margin-top: 8px
-.new-comment-input
- background-color: #fff
- border: 0
- box-shadow: 0 1px 2px rgba(0, 0, 0, .23)
- color: #8c8c8c
- height: 36px
- margin: 4px 4px 6px 0
- padding: 9px 11px
- width: 100%
-
- &:hover,
- &:focus
+ textarea
background-color: #fff
- box-shadow: 0 1px 3px rgba(0, 0, 0, .33)
border: 0
- cursor: pointer
-
- &:focus
- cursor: auto
+ box-shadow: 0 1px 2px rgba(0, 0, 0, .23)
+ color: #8c8c8c
+ height: 36px
+ margin: 4px 4px 6px 0
+ padding: 9px 11px
+ width: 100%
+
+ &:hover,
+ &:is-open
+ background-color: #fff
+ box-shadow: 0 1px 3px rgba(0, 0, 0, .33)
+ border: 0
+ cursor: pointer
+
+ &:is-open
+ cursor: auto
diff --git a/client/components/activities/events.js b/client/components/activities/events.js
deleted file mode 100644
index ea98e65f..00000000
--- a/client/components/activities/events.js
+++ /dev/null
@@ -1,30 +0,0 @@
-Template.cardActivities.events({
- 'click .js-edit-action': function(evt) {
- var $this = $(evt.currentTarget);
- var container = $this.parents('.phenom-comment');
-
- // open and focus
- container.addClass('editing');
- container.find('textarea').focus();
- },
- 'click .js-confirm-delete-action': function() {
- CardComments.remove(this._id);
- },
- 'submit form': function(evt) {
- var $this = $(evt.currentTarget);
- var container = $this.parents('.phenom-comment');
- var text = container.find('textarea');
-
- if ($.trim(text.val())) {
- CardComments.update(this._id, {
- $set: {
- text: text.val()
- }
- });
-
- // reset editing class
- $('.editing').removeClass('editing');
- }
- evt.preventDefault();
- }
-});
diff --git a/client/components/activities/templates.html b/client/components/activities/templates.html
deleted file mode 100644
index 5a595a36..00000000
--- a/client/components/activities/templates.html
+++ /dev/null
@@ -1,154 +0,0 @@
-<template name="boardActivities">
- {{# each currentBoard.activities }}
- <div class="phenom phenom-action clearfix phenom-other">
- {{> userAvatar userId=user._id}}
- <div class="phenom-desc">
- {{ > memberName user=user }}
-
- {{# if $eq activityType 'createBoard' }}
- {{_ 'activity-created' boardLabel}}.
- {{ /if }}
-
- {{# if $eq activityType 'createList' }}
- {{_ 'activity-added' list.title boardLabel}}.
- {{ /if }}
-
- {{# if $eq activityType 'archivedList' }}
- {{_ 'activity-archived' list.title}}.
- {{ /if }}
-
- {{# if $eq activityType 'createCard' }}
- {{{_ 'activity-added' cardLink boardLabel}}}.
- {{ /if }}
-
- {{# if $eq activityType 'archivedCard' }}
- {{{_ 'activity-archived' cardLink}}}.
- {{ /if }}
-
- {{# if $eq activityType 'restoredCard' }}
- {{{_ 'activity-sent' cardLink boardLabel}}}.
- {{ /if }}
-
- {{# if $eq activityType 'moveCard' }}
- {{{_ 'activity-moved' cardLink oldList.title list.title}}}.
- {{ /if }}
-
- {{# if $eq activityType 'addBoardMember' }}
- {{{_ 'activity-added' memberLink boardLabel}}}.
- {{ /if }}
-
- {{# if $eq activityType 'removeBoardMember' }}
- {{{_ 'activity-excluded' memberLink boardLabel}}}.
- {{ /if }}
-
- {{# if $eq activityType 'joinMember' }}
- {{# if $eq currentUser._id member._id }}
- {{{_ 'activity-joined' cardLink}}}.
- {{ else }}
- {{{_ 'activity-added' memberLink cardLink}}}.
- {{/if}}
- {{ /if }}
-
- {{# if $eq activityType 'unjoinMember' }}
- {{# if $eq currentUser._id member._id }}
- {{{_ 'activity-unjoined' cardLink}}}.
- {{ else }}
- {{{_ 'activity-removed' memberLink cardLink}}}.
- {{/if}}
- {{ /if }}
-
- {{# if $eq activityType 'addComment' }}
- <div class="phenom-desc">
- {{{_ 'activity-on' cardLink}}}
- <div class="action-comment markeddown">
- <a href="{{ card.absoluteUrl }}" class="current-comment show tdn">
- <p>{{#viewer}}{{ comment.text }}{{/viewer}}</p>
- </a>
- </div>
- </div>
- {{ /if }}
-
- {{# if $eq activityType 'addAttachment' }}
- <div class="phenom-desc">
- {{{_ 'activity-attached' attachmentLink cardLink}}}.
- </div>
- {{ /if }}
- </div>
- <p class="phenom-meta quiet">
- <span class="date js-hide-on-sending">
- {{ moment createdAt }}
- </span>
- </p>
- </div>
- {{ /each }}
-</template>
-
-<template name="cardActivities">
- {{# each currentCard.comments }}
- <div class="phenom phenom-action clearfix phenom-comment">
- {{> userAvatar userId=user._id}}
- <form>
- <div class="phenom-desc">
- {{ > memberName user=user }}
- <div class="action-comment markeddown">
- <div class="current-comment">
- {{#viewer}}{{ text }}{{/viewer}}
- </div>
- <textarea class="js-text" tabindex="1">{{ text }}</textarea>
- </div>
- </div>
- <div class="edit-controls clearfix">
- <input type="submit" class="primary confirm js-save-edit" value="{{_ 'save'}}" tabindex="2">
- </div>
- </form>
- <p class="phenom-meta quiet">
- <span class="date js-hide-on-sending">{{ moment createdAt }}</span>
- {{# if currentUser }}
- <span class="js-hide-on-sending">
- - <a href="#" class="js-edit-action">{{_ "edit"}}</a>
- - <a href="#" class="js-confirm-delete-action">{{_ "delete"}}</a>
- </span>
- {{/ if }}
- </p>
- </div>
- {{/each}}
-
- {{# each currentCard.activities }}
- <div class="phenom phenom-action clearfix phenom-other">
- {{> 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}}.
- {{ /if }}
- {{# if $eq activityType 'joinMember' }}
- {{# if $eq currentUser._id member._id }}
- {{_ 'activity-joined' cardLabel}}.
- {{ else }}
- {{{_ 'activity-added' cardLabel memberLink}}}.
- {{/if}}
- {{/if}}
- {{# if $eq activityType 'unjoinMember' }}
- {{# if $eq currentUser._id member._id }}
- {{_ 'activity-unjoined' cardLabel}}.
- {{ else }}
- {{{_ 'activity-removed' cardLabel memberLink}}}.
- {{/if}}
- {{ /if }}
- {{# if $eq activityType 'archivedCard' }}
- {{_ 'activity-archived' cardLabel}}.
- {{ /if }}
- {{# if $eq activityType 'restoredCard' }}
- {{_ 'activity-sent' cardLabel boardLabel}}.
- {{/ if }}
- {{# if $eq activityType 'moveCard' }}
- {{_ 'activity-moved' cardLabel oldList.title list.title}}.
- {{/ if }}
- {{# if $eq activityType 'addAttachment' }}
- {{{_ 'activity-attached' attachmentLink cardLabel}}}.
- {{# if attachment.isImage }}
- <img src="{{ attachment.url }}" class="attachment-image-preview">
- {{/if}}
- {{/ if}}
- </div>
- {{/each}}
-</template>
diff --git a/client/components/boards/boardBody.js b/client/components/boards/boardBody.js
index e1b39ce8..1fd64cbc 100644
--- a/client/components/boards/boardBody.js
+++ b/client/components/boards/boardBody.js
@@ -1,12 +1,3 @@
-// XXX This event list must be abstracted somewhere else.
-var endTransitionEvents = [
- 'webkitTransitionEnd',
- 'otransitionend',
- 'oTransitionEnd',
- 'msTransitionEnd',
- 'transitionend'
-].join(' ');
-
BlazeComponent.extendComponent({
template: function() {
return 'boardComponent';
@@ -69,7 +60,7 @@ BlazeComponent.extendComponent({
flexBasis: 0,
padding: 0
});
- $(lists).one(endTransitionEvents, removeNode);
+ $(lists).one(CSSEvents.transitionend, removeNode);
} else {
removeNode();
}
diff --git a/client/components/boards/boardHeader.jade b/client/components/boards/boardHeader.jade
index b0f0eebe..e78de3b2 100644
--- a/client/components/boards/boardHeader.jade
+++ b/client/components/boards/boardHeader.jade
@@ -106,9 +106,11 @@ template(name="createBoardPopup")
p.quiet
if $eq visibility.get 'public'
span.fa.fa-globe.colorful
+ = " "
| {{{_ 'board-public-info'}}}
else
span.fa.fa-lock.colorful
+ = " "
| {{{_ 'board-private-info'}}}
a.js-change-visibility Change.
input.primary.wide(type="submit" value="{{_ 'create'}}")
diff --git a/client/components/cards/details.jade b/client/components/cards/details.jade
index be166ad8..1eeda71d 100644
--- a/client/components/cards/details.jade
+++ b/client/components/cards/details.jade
@@ -1,5 +1,5 @@
template(name="cardDetails")
- section.card-details.js-card-details: .card-details-canvas
+ section.card-details.js-card-details.js-perfect-scrollbar: .card-details-canvas
if cover
.card-details-cover(style="background-image: url({{ cover.url }})")
@@ -42,7 +42,7 @@ template(name="cardDetails")
//- XXX We should use "editable" to avoide repetiting ourselves
if currentUser.isBoardMember
h3.card-details-item-title Description
- +inlinedForm(classNames="js-card-description")
+ +inlinedForm(classNames="card-description js-card-description")
+editor(autofocus=true)
= description
.edit-controls.clearfix
@@ -62,9 +62,13 @@ template(name="cardDetails")
if attachments.count
hr
+WindowAttachmentsModule(card=this)
- if isLoaded
- hr
- +WindowActivityModule(card=this)
+
+ hr
+ h2 {{ _ 'activity'}}
+ if currentUser.isBoardMember
+ +commentForm
+ if isLoaded.get
+ +activities(card=this mode="card")
template(name="cardDetailsActionsPopup")
if currentUser.isBoardMember
@@ -75,14 +79,15 @@ template(name="cardDetailsActionsPopup")
hr
ul.pop-over-list
li: a.js-copy Copy Card
- li: a.js-archive Archive Card
- li: a.js-delete Delete Card
+ unless archived
+ li: a.js-archive Archive Card
+ li: a.js-more More
template(name="moveCardPopup")
+boardLists
template(name="cardMembersPopup")
- ul.pop-over-member-list
+ ul.pop-over-list.pop-over-member-list
each board.members
li.item(class="{{#if isCardMember}}active{{/if}}")
a.name.js-select-member(href="#")
@@ -105,6 +110,17 @@ template(name="cardLabelsPopup")
span.card-label-selectable-icon.fa.fa-check
a.quiet-button.full.js-add-label {{_ 'label-create'}}
+template(name="cardMorePopup")
+ p.quiet
+ span.clearfix
+ span {{_ 'link-card'}}
+ = ' '
+ i.fa.colorful(class="{{#if board.isPublic}}fa-globe{{else}}fa-lock{{/if}}")
+ input.inline-input(type="text" readonly value="{{ rootUrl }}")
+ | {{_ 'added'}}
+ span.date(title=card.createdAt) {{ moment createdAt 'LLL' }}
+ a.js-delete(title="{{_ 'card-delete-notice'}}") {{_ 'delete'}}
+
template(name="cardDeletePopup")
p {{_ "card-delete-pop"}}
unless archived
diff --git a/client/components/cards/details.js b/client/components/cards/details.js
index f3d03793..05da2053 100644
--- a/client/components/cards/details.js
+++ b/client/components/cards/details.js
@@ -4,7 +4,7 @@ BlazeComponent.extendComponent({
},
mixins: function() {
- return [Mixins.InfiniteScrolling];
+ return [Mixins.InfiniteScrolling, Mixins.PerfectScrollbar];
},
calculateNextPeak: function() {
@@ -35,8 +35,19 @@ BlazeComponent.extendComponent({
});
},
+ onCreated: function() {
+ this.isLoaded = new ReactiveVar(false);
+ },
+
events: function() {
- return [{
+ // XXX We can't define this event directly in the event map below because we
+ // miss ES6 object keys interpolation.
+ var events = {};
+ events[CSSEvents.animationend + ' .js-card-details'] = function() {
+ this.isLoaded.set(true);
+ };
+
+ return [_.extend(events, {
'click .js-close-card-details': function() {
Utils.goBoardId(this.data().boardId);
},
@@ -60,7 +71,7 @@ BlazeComponent.extendComponent({
'mouseenter .js-card-details': function() {
this.componentParent().showOverlay.set(true);
}
- }];
+ })];
}
}).register('cardDetails');
@@ -78,11 +89,7 @@ Template.cardDetailsActionsPopup.events({
});
Popup.close();
},
- 'click .js-delete': Popup.afterConfirm('cardDelete', function() {
- var cardId = this._id;
- Cards.remove(cardId);
- Popup.close();
- })
+ 'click .js-more': Popup.open('cardMore')
});
Template.moveCardPopup.events({
@@ -100,6 +107,14 @@ Template.moveCardPopup.events({
}
});
+Template.cardMorePopup.events({
+ 'click .js-delete': Popup.afterConfirm('cardDelete', function() {
+ Popup.close();
+ Cards.remove(this._id);
+ Utils.goBoardId(this.board()._id);
+ })
+});
+
// Close the card details pane by pressing escape
EscapeActions.register('detailsPane',
function() { Utils.goBoardId(Session.get('currentBoard')); },
diff --git a/client/components/cards/details.styl b/client/components/cards/details.styl
index 94c75cf5..72e8c7c9 100644
--- a/client/components/cards/details.styl
+++ b/client/components/cards/details.styl
@@ -10,9 +10,9 @@
background: white
border-radius: 3px
z-index: 20 !important
- animation: flexGrowIn 0.2s
+ animation: flexGrowIn 0.1s
box-shadow: 0 0 7px 0 darken(white, 30%)
- transition: flex-basis 0.2s, padding 0.2s
+ transition: flex-basis 0.1s
margin-top: -9px
.card-details-canvas
@@ -62,13 +62,18 @@
border-radius: 3px
padding: 0px 5px
+ .card-description textarea
+ min-height: 100px
.card-details-items
display: flex
margin: 15px 0
.card-details-item
- flex-grow: 1
+ &.card-details-item-labels,
+ &.card-details-item-members
+ width: 50%
+ flex-shrink: 1
.card-details-item-title
font-size: 14px
@@ -78,62 +83,8 @@
padding-top: 5px
padding-bottom: 5px
-.new-comment
- position: relative
- margin: 0 0 20px 38px
-
- .member
- opacity: .7
- position: absolute
- top: 1px
- left: -38px
-
- .helper
- bottom: 0
- display: none
- position: absolute
- right: 9px
-
- &.focus
-
- .member
- opacity: 1
-
- .helper
- display: inline-block
-
- .new-comment-input
- min-height: 108px
- color: #4d4d4d
- cursor: auto
- overflow: hidden
- word-wrap: break-word
-
- .too-long
- margin-top: 8px
-
-.new-comment-input
- background-color: #fff
- border: 0
- box-shadow: 0 1px 2px rgba(0, 0, 0, .23)
- color: #8c8c8c
- height: 36px
- margin: 4px 4px 6px 0
- padding: 9px 11px
- width: 100%
-
- &:hover,
- &:focus
- background-color: #fff
- box-shadow: 0 1px 3px rgba(0, 0, 0, .33)
- border: 0
- cursor: pointer
-
- &:focus
- cursor: auto
-
-.card-composer
- padding-bottom: 8px
+ .activities
+ padding-top: 10px
input[type="text"].attachment-add-link-input
float: left
diff --git a/client/components/cards/events.js b/client/components/cards/events.js
index 2363f4de..ca2ddb50 100644
--- a/client/components/cards/events.js
+++ b/client/components/cards/events.js
@@ -1,61 +1,3 @@
-Template.cardMemberPopup.events({
- 'click .js-remove-member': function() {
- Cards.update(this.cardId, {$pull: {members: this.userId}});
- Popup.close();
- }
-});
-
-Template.WindowActivityModule.events({
- 'click .js-new-comment:not(.focus)': function(evt) {
- var $this = $(evt.currentTarget);
- $this.addClass('focus');
- },
- 'submit #CommentForm': function(evt, t) {
- var text = t.$('.js-new-comment-input');
- if ($.trim(text.val())) {
- CardComments.insert({
- boardId: this.card.boardId,
- cardId: this.card._id,
- text: text.val()
- });
- text.val('');
- $('.focus').removeClass('focus');
- }
- evt.preventDefault();
- }
-});
-
-Template.WindowSidebarModule.events({
- 'click .js-change-card-members': Popup.open('cardMembers'),
- 'click .js-edit-labels': Popup.open('cardLabels'),
- 'click .js-archive-card': function(evt) {
- // Update
- Cards.update(this.card._id, {
- $set: {
- archived: true
- }
- });
- evt.preventDefault();
- },
- 'click .js-unarchive-card': function(evt) {
- Cards.update(this.card._id, {
- $set: {
- archived: false
- }
- });
- evt.preventDefault();
- },
- 'click .js-delete-card': Popup.afterConfirm('cardDelete', function() {
- Cards.remove(this.card._id);
-
- // redirect board
- Utils.goBoardId(this.card.board()._id);
- Popup.close();
- }),
- 'click .js-more-menu': Popup.open('cardMore'),
- 'click .js-attach': Popup.open('cardAttachments')
-});
-
Template.WindowAttachmentsModule.events({
'click .js-attach': Popup.open('cardAttachments'),
'click .js-confirm-delete': Popup.afterConfirm('attachmentDelete',
@@ -77,130 +19,6 @@ Template.WindowAttachmentsModule.events({
}
});
-Template.cardMembersPopup.events({
- 'click .js-select-member': function(evt) {
- var cardId = Template.parentData(2).data._id;
- var memberId = this.userId;
- var operation;
- if (Cards.find({ _id: cardId, members: memberId}).count() === 0)
- operation = '$addToSet';
- else
- operation = '$pull';
-
- var query = {};
- query[operation] = {
- members: memberId
- };
- Cards.update(cardId, query);
- evt.preventDefault();
- }
-});
-
-Template.cardLabelsPopup.events({
- 'click .js-select-label': function(evt) {
- var cardId = Template.parentData(2).data._id;
- var labelId = this._id;
- var operation;
- if (Cards.find({ _id: cardId, labelIds: labelId}).count() === 0)
- operation = '$addToSet';
- else
- operation = '$pull';
-
- var query = {};
- query[operation] = {
- labelIds: labelId
- };
- Cards.update(cardId, query);
- evt.preventDefault();
- },
- 'click .js-edit-label': Popup.open('editLabel'),
- 'click .js-add-label': Popup.open('createLabel')
-});
-
-Template.formLabel.events({
- 'click .js-palette-color': function(evt) {
- var $this = $(evt.currentTarget);
-
- // hide selected ll colors
- $('.js-palette-select').addClass('hide');
-
- // show select color
- $this.find('.js-palette-select').removeClass('hide');
- }
-});
-
-Template.createLabelPopup.events({
- // Create the new label
- 'submit .create-label': function(evt, tpl) {
- var name = tpl.$('#labelName').val().trim();
- var boardId = Session.get('currentBoard');
- var selectLabelDom = tpl.$('.js-palette-select').get(0);
- var selectLabel = Blaze.getData(selectLabelDom);
- Boards.update(boardId, {
- $push: {
- labels: {
- _id: Random.id(6),
- name: name,
- color: selectLabel.color
- }
- }
- });
- Popup.back();
- evt.preventDefault();
- }
-});
-
-Template.editLabelPopup.events({
- 'click .js-delete-label': Popup.afterConfirm('deleteLabel', function() {
- var boardId = Session.get('currentBoard');
- Boards.update(boardId, {
- $pull: {
- labels: {
- _id: this._id
- }
- }
- });
- Popup.back(2);
- }),
- 'submit .edit-label': function(evt, tpl) {
- var name = tpl.$('#labelName').val().trim();
- var boardId = Session.get('currentBoard');
- var getLabel = Utils.getLabelIndex(boardId, this._id);
- var selectLabelDom = tpl.$('.js-palette-select').get(0);
- var selectLabel = Blaze.getData(selectLabelDom);
- var $set = {};
-
- // set label index
- $set[getLabel.key('name')] = name;
-
- // set color
- $set[getLabel.key('color')] = selectLabel.color;
-
- // update
- Boards.update(boardId, { $set: $set });
-
- // return to the previous popup view trigger
- Popup.back();
-
- evt.preventDefault();
- },
- 'click .js-select-label': function() {
- Cards.remove(this.cardId);
-
- // redirect board
- Utils.goBoardId(this.boardId);
- }
-});
-
-Template.cardMorePopup.events({
- 'click .js-delete': Popup.afterConfirm('cardDelete', function() {
- Cards.remove(this.card._id);
-
- // redirect board
- Utils.goBoardId(this.card.board()._id);
- })
-});
-
Template.cardAttachmentsPopup.events({
'change .js-attach-file': function(evt) {
var card = this.card;
diff --git a/client/components/cards/helpers.js b/client/components/cards/helpers.js
deleted file mode 100644
index ce85002d..00000000
--- a/client/components/cards/helpers.js
+++ /dev/null
@@ -1,48 +0,0 @@
-Template.cardMembersPopup.helpers({
- isCardMember: function() {
- var cardId = Template.parentData()._id;
- var cardMembers = Cards.findOne(cardId).members || [];
- return _.contains(cardMembers, this.userId);
- },
- user: function() {
- return Users.findOne(this.userId);
- }
-});
-
-Template.cardLabelsPopup.helpers({
- isLabelSelected: function(cardId) {
- return _.contains(Cards.findOne(cardId).labelIds, this._id);
- }
-});
-
-var labelColors;
-Meteor.startup(function() {
- labelColors = Boards.simpleSchema()._schema['labels.$.color'].allowedValues;
-});
-
-Template.createLabelPopup.helpers({
- // This is the default color for a new label. We search the first color that
- // is not already used in the board (although it's not a problem if two
- // labels have the same color).
- defaultColor: function() {
- var labels = this.labels || this.card.board().labels;
- var usedColors = _.pluck(labels, 'color');
- var availableColors = _.difference(labelColors, usedColors);
- return availableColors.length > 1 ? availableColors[0] : labelColors[0];
- }
-});
-
-Template.formLabel.helpers({
- labels: function() {
- return _.map(labelColors, function(color) {
- return { color: color, name: '' };
- });
- }
-});
-
-Blaze.registerHelper('currentCard', function() {
- var cardId = Session.get('currentCard');
- if (cardId) {
- return Cards.findOne(cardId);
- }
-});
diff --git a/client/components/cards/labels.jade b/client/components/cards/labels.jade
new file mode 100644
index 00000000..acd1b5ae
--- /dev/null
+++ b/client/components/cards/labels.jade
@@ -0,0 +1,27 @@
+template(name="formLabel")
+ .colors
+ label(for="labelName") {{_ 'name'}}
+ input.js-label-name#labelName(type="text" name="name" value=name autofocus)
+
+ label {{_ "select-color"}}
+ each labels
+ span.card-label.card-label--selectable.palette-color.js-palette-color(class="card-label-{{color}}")
+ if($eq color ../color)
+ i.fa.fa-check
+
+template(name="createLabelPopup")
+ form.create-label
+ with(color=defaultColor)
+ +formLabel
+ button.primary.wide(type="submit") {{_ 'create'}}
+
+template(name="editLabelPopup")
+ form.edit-label
+ +formLabel
+ button.primary.wide.left(type="submit") {{_ 'save'}}
+ span.right
+
+
+template(name="deleteLabelPopup")
+ p {{_ "label-delete-pop"}}
+ button.js-confirm.negate.full(type="submit") {{_ 'delete'}}
diff --git a/client/components/cards/labels.js b/client/components/cards/labels.js
new file mode 100644
index 00000000..36a35f82
--- /dev/null
+++ b/client/components/cards/labels.js
@@ -0,0 +1,126 @@
+Template.cardLabelsPopup.events({
+ 'click .js-select-label': function(evt) {
+ var cardId = Template.parentData(2).data._id;
+ var labelId = this._id;
+ var operation;
+ if (Cards.find({ _id: cardId, labelIds: labelId}).count() === 0)
+ operation = '$addToSet';
+ else
+ operation = '$pull';
+
+ var query = {};
+ query[operation] = {
+ labelIds: labelId
+ };
+ Cards.update(cardId, query);
+ evt.preventDefault();
+ },
+ 'click .js-edit-label': Popup.open('editLabel'),
+ 'click .js-add-label': Popup.open('createLabel')
+});
+
+Template.formLabel.events({
+ 'click .js-palette-color': function(evt) {
+ var $this = $(evt.currentTarget);
+
+ // hide selected ll colors
+ $('.js-palette-select').addClass('hide');
+
+ // show select color
+ $this.find('.js-palette-select').removeClass('hide');
+ }
+});
+
+Template.createLabelPopup.events({
+ // Create the new label
+ 'submit .create-label': function(evt, tpl) {
+ var name = tpl.$('#labelName').val().trim();
+ var boardId = Session.get('currentBoard');
+ var selectLabelDom = tpl.$('.js-palette-select').get(0);
+ var selectLabel = Blaze.getData(selectLabelDom);
+ Boards.update(boardId, {
+ $push: {
+ labels: {
+ _id: Random.id(6),
+ name: name,
+ color: selectLabel.color
+ }
+ }
+ });
+ Popup.back();
+ evt.preventDefault();
+ }
+});
+
+Template.editLabelPopup.events({
+ 'click .js-delete-label': Popup.afterConfirm('deleteLabel', function() {
+ var boardId = Session.get('currentBoard');
+ Boards.update(boardId, {
+ $pull: {
+ labels: {
+ _id: this._id
+ }
+ }
+ });
+ Popup.back(2);
+ }),
+ 'submit .edit-label': function(evt, tpl) {
+ var name = tpl.$('#labelName').val().trim();
+ var boardId = Session.get('currentBoard');
+ var getLabel = Utils.getLabelIndex(boardId, this._id);
+ var selectLabelDom = tpl.$('.js-palette-select').get(0);
+ var selectLabel = Blaze.getData(selectLabelDom);
+ var $set = {};
+
+ // set label index
+ $set[getLabel.key('name')] = name;
+
+ // set color
+ $set[getLabel.key('color')] = selectLabel.color;
+
+ // update
+ Boards.update(boardId, { $set: $set });
+
+ // return to the previous popup view trigger
+ Popup.back();
+
+ evt.preventDefault();
+ },
+ 'click .js-select-label': function() {
+ Cards.remove(this.cardId);
+
+ // redirect board
+ Utils.goBoardId(this.boardId);
+ }
+});
+
+Template.cardLabelsPopup.helpers({
+ isLabelSelected: function(cardId) {
+ return _.contains(Cards.findOne(cardId).labelIds, this._id);
+ }
+});
+
+var labelColors;
+Meteor.startup(function() {
+ labelColors = Boards.simpleSchema()._schema['labels.$.color'].allowedValues;
+});
+
+Template.createLabelPopup.helpers({
+ // This is the default color for a new label. We search the first color that
+ // is not already used in the board (although it's not a problem if two
+ // labels have the same color).
+ defaultColor: function() {
+ var labels = this.labels || this.card.board().labels;
+ var usedColors = _.pluck(labels, 'color');
+ var availableColors = _.difference(labelColors, usedColors);
+ return availableColors.length > 1 ? availableColors[0] : labelColors[0];
+ }
+});
+
+Template.formLabel.helpers({
+ labels: function() {
+ return _.map(labelColors, function(color) {
+ return { color: color, name: '' };
+ });
+ }
+});
diff --git a/client/components/cards/labels.styl b/client/components/cards/labels.styl
index 39f9844f..cbe4d2b3 100644
--- a/client/components/cards/labels.styl
+++ b/client/components/cards/labels.styl
@@ -85,10 +85,6 @@
left: 0
width: 260px
-.editable-labels .card-label:hover
- cursor: pointer
- opacity: .75
-
.edit-labels-pop-over
margin-bottom: 8px
@@ -98,7 +94,9 @@
.card-label-selectable
border-radius: 3px
cursor: pointer
- margin: 0 50px 4px 0
+ margin: 0
+ margin-bottom: 3px
+ width: 190px
min-height: 18px
padding: 8px
position: relative
@@ -113,21 +111,13 @@
&.active,
&.active.selected:hover,
&.active.selected
- margin-right: 38px
padding-right: 32px
.card-label-selectable-icon
right: 6px
- &.active:hover:hover,
- &.active:hover,
- &.active.selected:hover:hover,
- &.active.selected:hover
- margin-right: 38px
-
&.selected,
&:hover
- margin-right: 38px
opacity: .8
.active .card-label-selectable
diff --git a/client/components/cards/minicard.jade b/client/components/cards/minicard.jade
index 670b1f89..2eee3164 100644
--- a/client/components/cards/minicard.jade
+++ b/client/components/cards/minicard.jade
@@ -15,7 +15,7 @@ template(name="minicard")
if comments.count
.badge(title="{{_ 'card-comments-title' comments.count }}")
span.badge-icon.fa.fa-comment-o
- .badge-text= comments.count
+ span.badge-text= comments.count
if description
.badge.badge-state-image-only(title=description)
span.badge-icon.fa.fa-align-left
diff --git a/client/components/cards/minicard.styl b/client/components/cards/minicard.styl
index ebad8dec..c854b1f5 100644
--- a/client/components/cards/minicard.styl
+++ b/client/components/cards/minicard.styl
@@ -78,20 +78,34 @@
margin-bottom: 2px
text-decoration: none
word-wrap: break-word
- clear: both
&::selection
background: transparent
.minicard-labels
float: right
+ display: flex
.minicard-label
- float: right
width: 11px
height: @width
border-radius: 2px
- margin-right: 3px
+ margin-left: 3px
+
+ .badges
+ float: left
+ margin-top: 5px
+ color: darken(white, 60%)
+
+ &:empty
+ display: none
+
+ .badge
+ float: left
+ margin-right: 10px
+
+ .badge-text
+ font-size: 0.9em
.minicard-members
float: right
@@ -109,12 +123,6 @@
.minicard-members:empty
display: none
- .badges
- float: left
-
- &:empty
- display: none
-
&.minicard-composer
margin-bottom: 10px
diff --git a/client/components/cards/templates.html b/client/components/cards/templates.html
index dfa21ace..f61c3df5 100644
--- a/client/components/cards/templates.html
+++ b/client/components/cards/templates.html
@@ -1,34 +1,3 @@
-<template name="cardMemberPopup">
- <div class="board-member-menu">
- <div class="mini-profile-info">
- {{> 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>
- </h3>
- <p class="quiet bottom">@{{ user.username }}</p>
- </div>
- </div>
- {{# if currentUser.isBoardMember }}
- <ul class="pop-over-list">
- <li><a class="js-remove-member">{{_ 'remove-member-from-card'}}</a></li>
- </ul>
- {{/ if }}
- </div>
-</template>
-
-<template name="cardMorePopup">
- <p class="quiet bottom">
- <span class="clearfix">
- <span>{{_ 'link-card'}}</span>
- <span class="icon-sm fa {{#if card.board.isPublic}}fa-globe{{else}}fa-lock{{/if}}"></span>
- <input class="js-url js-autoselect inline-input" type="text" readonly="readonly" value="{{ card.rootUrl }}">
- </span>
- {{_ 'added'}} <span class="date" title="{{ card.createdAt }}">{{ moment card.createdAt 'LLL' }}</span> -
- <a class="js-delete" href="#" title="{{_ 'card-delete-notice'}}">{{_ 'delete'}}</a>
- </p>
-</template>
-
<template name="cardAttachmentsPopup">
<div>
<ul class="pop-over-list">
@@ -42,43 +11,6 @@
</div>
</template>
-<template name="formLabel">
- <div class="colors clearfix">
- <label for="labelName">{{_ 'name'}}</label>
- <input id="labelName" type="text" name="name" class="js-label-name" value='{{ name }}' autofocus>
- <label>{{_ "select-color"}}</label>
- {{# each labels }}
- <span class="card-label card-label--selectable card-label-{{ color }} palette-color js-palette-color">
- <span class="card-label-color-select-icon icon-sm fa fa-check light js-palette-select {{#if $neq color ../color}}hide{{/if}}"></span>
- </span>
- {{/each}}
- </div>
-</template>
-
-<template name="createLabelPopup">
- <form class="create-label">
- {{#with color=defaultColor}}
- {{> formLabel}}
- {{/with}}
- <input type="submit" class="primary wide left" value="{{_ 'create'}}">
- </form>
-</template>
-
-<template name="editLabelPopup">
- <form class="edit-label">
- {{> formLabel}}
- <input type="submit" class="primary wide left" value="{{_ 'save'}}">
- <span class="right">
- <input type="submit" value="{{_ 'delete'}}" class="negate js-delete-label">
- </span>
- </form>
-</template>
-
-<template name="deleteLabelPopup">
- <p>{{_ "label-delete-pop"}}</p>
- <input type="submit" class="js-confirm negate full" value="{{_ 'delete'}}">
-</template>
-
<template name="attachmentDeletePopup">
<p>{{_ "attachment-delete-pop"}}</p>
<input type="submit" class="js-confirm negate full" value="{{_ 'delete'}}">
@@ -263,45 +195,3 @@
</div>
</div>
</template>
-
-<template name="WindowSidebarModule">
- <div class="window-sidebar" style="position: relative;">
- <div class="window-module clearfix">
- <h3>{{_ 'add'}}</h3>
- <div class="clearfix">
- <a href="#" class="button-link js-change-card-members" title="{{_ 'members-title'}}">
- <span class="icon-sm fa fa-user"></span> {{_ 'members'}}
- </a>
- <a href="#" class="button-link js-edit-labels" title="{{_ 'labels-title'}}">
- <span class="icon-sm fa fa-tags"></span> {{_ 'labels'}}
- </a>
- <a href="#" class="button-link js-attach" title="{{_ 'attachment-title'}}">
- <span class="icon-sm fa fa-paperclip"></span> {{_ 'attachment'}}
- </a>
- </div>
- </div>
- <div class="window-module other-actions clearfix">
- <h3>{{_ 'actions'}}</h3>
- <div class="clearfix">
- <hr>
- {{ #if card.archived }}
- <a href="#" class="button-link js-unarchive-card" title="{{_ 'send-to-board-title'}}">
- <span class="icon-sm fa fa-recycle"></span> {{_ 'send-to-board'}}
- </a>
- <a href="#" class="button-link negate js-delete-card" title="{{_ 'delete-title'}}">
- <span class="icon-sm fa fa-trash-o"></span> {{_ 'delete'}}
- </a>
- {{ else }}
- <a href="#" class="button-link js-archive-card" title="{{_ 'archive-title'}}">
- <span class="icon-sm fa fa-archive"></span> {{_ 'archive'}}
- </a>
- {{ /if }}
- </div>
- </div>
- <div class="window-module clearfix">
- <p class="quiet bottom">
- <a href="#" class="quiet-button js-more-menu" title="{{_ 'share-and-more-title'}}">{{_ 'share-and-more'}}</a>
- </p>
- </div>
- </div>
-</template>
diff --git a/client/components/forms/forms.styl b/client/components/forms/forms.styl
index a71aee81..06ae1302 100644
--- a/client/components/forms/forms.styl
+++ b/client/components/forms/forms.styl
@@ -95,6 +95,11 @@ textarea
resize: vertical
width: 100%
+ &.editor
+ resize: none
+ padding-bottom: 22px
+
+
.button
border-radius: 3px
text-decoration: none
diff --git a/client/components/main/editor.styl b/client/components/main/editor.styl
deleted file mode 100644
index 1dc02047..00000000
--- a/client/components/main/editor.styl
+++ /dev/null
@@ -1,2 +0,0 @@
-textarea.editor
- min-height: 100px
diff --git a/client/components/main/popup.js b/client/components/main/popup.js
index 8cb12dd0..5fc4e979 100644
--- a/client/components/main/popup.js
+++ b/client/components/main/popup.js
@@ -1,22 +1,3 @@
-// XXX This event list must be abstracted somewhere else.
-function whichTransitionEvent() {
- var t;
- var el = document.createElement('fakeelement');
- var transitions = {
- transition:'transitionend',
- OTransition:'oTransitionEnd',
- MozTransition:'transitionend',
- WebkitTransition:'webkitTransitionEnd'
- };
-
- for (t in transitions) {
- if (el.style[t] !== undefined) {
- return transitions[t];
- }
- }
-}
-var transitionEvent = whichTransitionEvent();
-
Popup.template.events({
'click .js-back-view': function() {
Popup.back();
@@ -50,7 +31,7 @@ Popup.template.onRendered(function() {
container._uihooks = {
removeElement: function(node) {
$(node).addClass('no-height');
- $(container).one(transitionEvent, function() {
+ $(container).one(CSSEvents.transitionend, function() {
node.parentNode.removeChild(node);
});
}
diff --git a/client/components/users/userAvatar.jade b/client/components/users/userAvatar.jade
index 4c0e5c63..2ea3aa20 100644
--- a/client/components/users/userAvatar.jade
+++ b/client/components/users/userAvatar.jade
@@ -19,14 +19,17 @@ template(name="userPopup")
+userAvatar(userId=user._id)
.info
h3.bottom
- a.js-profile(href="{{pathFor route='Profile' username=user.username}}")= user.profile.name
+ = user.profile.fullname
p.quiet.bottom @{{ user.username }}
template(name="memberName")
- a.js-show-mem-menu(href="{{pathFor route='Profile' username=user.username}}")
+ if showBoth
= user.profile.fullname
- if username
- | ({{ user.username }})
+ | ({{ user.username }})
+ else if user.profile.fullname
+ = user.profile.fullname
+ else
+ = user.username
template(name="changeAvatarPopup")
ul.pop-over-list
@@ -54,3 +57,14 @@ template(name="changeAvatarPopup")
button.full.js-upload-avatar
i.fa.fa-upload
| Upload an avatar
+
+template(name="cardMemberPopup")
+ .board-member-menu
+ .mini-profile-info
+ +userAvatar(userId=user._id)
+ .info
+ h3.bottom= user.profile.fullname
+ p.quiet.bottom @{{ user.username }}
+ if currentUser.isBoardMember
+ ul.pop-over-list
+ li: a.js-remove-member {{_ 'remove-member-from-card'}}
diff --git a/client/components/users/userAvatar.js b/client/components/users/userAvatar.js
index a02646c1..64975141 100644
--- a/client/components/users/userAvatar.js
+++ b/client/components/users/userAvatar.js
@@ -111,3 +111,40 @@ BlazeComponent.extendComponent({
}];
}
}).register('changeAvatarPopup');
+
+Template.cardMembersPopup.helpers({
+ isCardMember: function() {
+ var cardId = Template.parentData()._id;
+ var cardMembers = Cards.findOne(cardId).members || [];
+ return _.contains(cardMembers, this.userId);
+ },
+ user: function() {
+ return Users.findOne(this.userId);
+ }
+});
+
+Template.cardMembersPopup.events({
+ 'click .js-select-member': function(evt) {
+ var cardId = Template.parentData(2).data._id;
+ var memberId = this.userId;
+ var operation;
+ if (Cards.find({ _id: cardId, members: memberId}).count() === 0)
+ operation = '$addToSet';
+ else
+ operation = '$pull';
+
+ var query = {};
+ query[operation] = {
+ members: memberId
+ };
+ Cards.update(cardId, query);
+ evt.preventDefault();
+ }
+});
+
+Template.cardMemberPopup.events({
+ 'click .js-remove-member': function() {
+ Cards.update(this.cardId, {$pull: {members: this.userId}});
+ Popup.close();
+ }
+});
diff --git a/client/config/helpers.js b/client/config/helpers.js
new file mode 100644
index 00000000..01a28f9b
--- /dev/null
+++ b/client/config/helpers.js
@@ -0,0 +1,6 @@
+Blaze.registerHelper('currentCard', function() {
+ var cardId = Session.get('currentCard');
+ if (cardId) {
+ return Cards.findOne(cardId);
+ }
+});
diff --git a/client/lib/cssEvents.js b/client/lib/cssEvents.js
new file mode 100644
index 00000000..487ba69b
--- /dev/null
+++ b/client/lib/cssEvents.js
@@ -0,0 +1,42 @@
+// XXX Should we use something like Moderniz instead of our custom detector?
+
+var whichTransitionEvent = function() {
+ var t;
+ var el = document.createElement('fakeelement');
+ var transitions = {
+ transition:'transitionend',
+ OTransition:'oTransitionEnd',
+ MSTransition:'msTransitionEnd',
+ MozTransition:'transitionend',
+ WebkitTransition:'webkitTransitionEnd'
+ };
+
+ for (t in transitions) {
+ if (el.style[t] !== undefined) {
+ return transitions[t];
+ }
+ }
+};
+
+var whichAnimationEvent = function() {
+ var t;
+ var el = document.createElement('fakeelement');
+ var transitions = {
+ animation:'animationend',
+ OAnimation:'oAnimationEnd',
+ MSTransition:'msAnimationEnd',
+ MozAnimation:'animationend',
+ WebkitAnimation:'webkitAnimationEnd'
+ };
+
+ for (t in transitions) {
+ if (el.style[t] !== undefined) {
+ return transitions[t];
+ }
+ }
+};
+
+CSSEvents = {
+ transitionend: whichTransitionEvent(),
+ animationend: whichAnimationEvent()
+};
diff --git a/client/styles/main.styl b/client/styles/main.styl
index 3509d5c9..c5d169d3 100644
--- a/client/styles/main.styl
+++ b/client/styles/main.styl
@@ -77,6 +77,9 @@ a
cursor: default
text-decoration: none
+strong
+ font-weight: bold
+
p
a
text-decoration: underline
diff --git a/collections/cards.js b/collections/cards.js
index 374dcbc3..92a3f618 100644
--- a/collections/cards.js
+++ b/collections/cards.js
@@ -130,8 +130,7 @@ Cards.helpers({
return _.contains(this.members, memberId);
},
activities: function() {
- return Activities.find({ type: 'card', cardId: this._id },
- { sort: { createdAt: -1 }});
+ return Activities.find({ cardId: this._id }, { sort: { createdAt: -1 }});
},
comments: function() {
return CardComments.find({ cardId: this._id }, { sort: { createdAt: -1 }});
@@ -182,7 +181,6 @@ CardComments.before.insert(function(userId, doc) {
if (Meteor.isServer) {
Cards.after.insert(function(userId, doc) {
Activities.insert({
- type: 'card',
activityType: 'createCard',
boardId: doc.boardId,
listId: doc.listId,
@@ -196,7 +194,6 @@ if (Meteor.isServer) {
if (_.contains(fieldNames, 'archived')) {
if (doc.archived) {
Activities.insert({
- type: 'card',
activityType: 'archivedCard',
boardId: doc.boardId,
listId: doc.listId,
@@ -205,7 +202,6 @@ if (Meteor.isServer) {
});
} else {
Activities.insert({
- type: 'card',
activityType: 'restoredCard',
boardId: doc.boardId,
listId: doc.listId,
@@ -221,7 +217,6 @@ if (Meteor.isServer) {
var oldListId = this.previous.listId;
if (_.contains(fieldNames, 'listId') && doc.listId !== oldListId) {
Activities.insert({
- type: 'card',
activityType: 'moveCard',
listId: doc.listId,
oldListId: oldListId,
@@ -242,7 +237,6 @@ if (Meteor.isServer) {
memberId = modifier.$addToSet.members;
if (! _.contains(doc.members, memberId)) {
Activities.insert({
- type: 'card',
activityType: 'joinMember',
boardId: doc.boardId,
cardId: doc._id,
@@ -256,7 +250,6 @@ if (Meteor.isServer) {
if (modifier.$pull && modifier.$pull.members) {
memberId = modifier.$pull.members;
Activities.insert({
- type: 'card',
activityType: 'unjoinMember',
boardId: doc.boardId,
cardId: doc._id,
@@ -275,7 +268,6 @@ if (Meteor.isServer) {
CardComments.after.insert(function(userId, doc) {
Activities.insert({
- type: 'comment',
activityType: 'addComment',
boardId: doc.boardId,
cardId: doc.cardId,