mirror of
https://github.com/wekan/wekan.git
synced 2025-04-23 13:37:09 -04:00
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.
This commit is contained in:
parent
216887490e
commit
c894567987
31 changed files with 590 additions and 691 deletions
|
@ -71,6 +71,7 @@
|
|||
"AccountsTemplates": true,
|
||||
|
||||
// Our objects
|
||||
"CSSEvents": true,
|
||||
"EscapeActions": true,
|
||||
"Filter": true,
|
||||
"Filter": true,
|
||||
|
|
|
@ -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 }}
|
||||
|
|
|
@ -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');
|
||||
|
|
28
client/components/activities/activities.styl
Normal file
28
client/components/activities/activities.styl
Normal file
|
@ -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%)
|
|
@ -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'}}
|
|
@ -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'
|
||||
}
|
||||
);
|
|
@ -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
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, .23)
|
||||
color: #8c8c8c
|
||||
height: 36px
|
||||
margin: 4px 4px 6px 0
|
||||
padding: 9px 11px
|
||||
width: 100%
|
||||
|
||||
&:focus
|
||||
cursor: auto
|
||||
&:hover,
|
||||
&:is-open
|
||||
background-color: #fff
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, .33)
|
||||
border: 0
|
||||
cursor: pointer
|
||||
|
||||
&:is-open
|
||||
cursor: auto
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
});
|
|
@ -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>
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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'}}")
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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')); },
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
});
|
27
client/components/cards/labels.jade
Normal file
27
client/components/cards/labels.jade
Normal file
|
@ -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'}}
|
126
client/components/cards/labels.js
Normal file
126
client/components/cards/labels.js
Normal file
|
@ -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: '' };
|
||||
});
|
||||
}
|
||||
});
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -95,6 +95,11 @@ textarea
|
|||
resize: vertical
|
||||
width: 100%
|
||||
|
||||
&.editor
|
||||
resize: none
|
||||
padding-bottom: 22px
|
||||
|
||||
|
||||
.button
|
||||
border-radius: 3px
|
||||
text-decoration: none
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
textarea.editor
|
||||
min-height: 100px
|
|
@ -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);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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'}}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
});
|
||||
|
|
6
client/config/helpers.js
Normal file
6
client/config/helpers.js
Normal file
|
@ -0,0 +1,6 @@
|
|||
Blaze.registerHelper('currentCard', function() {
|
||||
var cardId = Session.get('currentCard');
|
||||
if (cardId) {
|
||||
return Cards.findOne(cardId);
|
||||
}
|
||||
});
|
42
client/lib/cssEvents.js
Normal file
42
client/lib/cssEvents.js
Normal file
|
@ -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()
|
||||
};
|
|
@ -77,6 +77,9 @@ a
|
|||
cursor: default
|
||||
text-decoration: none
|
||||
|
||||
strong
|
||||
font-weight: bold
|
||||
|
||||
p
|
||||
a
|
||||
text-decoration: underline
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue