mirror of https://github.com/wekan/wekan
commit
ca6cadbe6d
@ -1,3 +1,22 @@ |
||||
.integration-form |
||||
padding: 5px |
||||
border-bottom: 1px solid #ccc |
||||
|
||||
.flex |
||||
display: -webkit-box |
||||
display: -moz-box |
||||
display: -webkit-flex |
||||
display: -moz-flex |
||||
display: -ms-flexbox |
||||
display: flex |
||||
|
||||
.option |
||||
@extends .flex |
||||
-webkit-border-radius: 3px; |
||||
border-radius: 3px; |
||||
background: #fff; |
||||
text-decoration: none; |
||||
-webkit-box-shadow: 0 1px 2px rgba(0,0,0,0.2); |
||||
box-shadow: 0 1px 2px rgba(0,0,0,0.2); |
||||
margin-top: 5px; |
||||
padding: 5px; |
||||
|
@ -0,0 +1,97 @@ |
||||
template(name="subtasks") |
||||
h3 {{_ 'subtasks'}} |
||||
if toggleDeleteDialog.get |
||||
.board-overlay#card-details-overlay |
||||
+subtaskDeleteDialog(subtask = subtaskToDelete) |
||||
|
||||
|
||||
.card-subtasks-items |
||||
each subtask in currentCard.subtasks |
||||
+subtaskDetail(subtask = subtask) |
||||
|
||||
if canModifyCard |
||||
+inlinedForm(autoclose=false classNames="js-add-subtask" cardId = cardId) |
||||
+addSubtaskItemForm |
||||
else |
||||
a.js-open-inlined-form |
||||
i.fa.fa-plus |
||||
| {{_ 'add-subtask'}}... |
||||
|
||||
template(name="subtaskDetail") |
||||
.js-subtasks.subtask |
||||
+inlinedForm(classNames="js-edit-subtask-title" subtask = subtask) |
||||
+editSubtaskItemForm(subtask = subtask) |
||||
else |
||||
.subtask-title |
||||
span |
||||
a.js-view-subtask(title="{{ subtask.title }}") {{_ "view-it"}} |
||||
if canModifyCard |
||||
a.js-delete-subtask.toggle-delete-subtask-dialog {{_ "delete"}}... |
||||
|
||||
if canModifyCard |
||||
h2.title.js-open-inlined-form.is-editable |
||||
+viewer |
||||
= subtask.title |
||||
else |
||||
h2.title |
||||
+viewer |
||||
= subtask.title |
||||
|
||||
template(name="subtaskDeleteDialog") |
||||
.js-confirm-subtask-delete |
||||
p |
||||
i(class="fa fa-exclamation-triangle" aria-hidden="true") |
||||
p |
||||
| {{_ 'confirm-subtask-delete-dialog'}} |
||||
span {{subtask.title}} |
||||
| ? |
||||
.js-subtask-delete-buttons |
||||
button.confirm-subtask-delete(type="button") {{_ 'delete'}} |
||||
button.toggle-delete-subtask-dialog(type="button") {{_ 'cancel'}} |
||||
|
||||
template(name="addSubtaskItemForm") |
||||
textarea.js-add-subtask-item(rows='1' autofocus) |
||||
.edit-controls.clearfix |
||||
button.primary.confirm.js-submit-add-subtask-item-form(type="submit") {{_ 'save'}} |
||||
a.fa.fa-times-thin.js-close-inlined-form |
||||
|
||||
template(name="editSubtaskItemForm") |
||||
textarea.js-edit-subtask-item(rows='1' autofocus) |
||||
if $eq type 'item' |
||||
= item.title |
||||
else |
||||
= subtask.title |
||||
.edit-controls.clearfix |
||||
button.primary.confirm.js-submit-edit-subtask-item-form(type="submit") {{_ 'save'}} |
||||
a.fa.fa-times-thin.js-close-inlined-form |
||||
span(title=createdAt) {{ moment createdAt }} |
||||
if canModifyCard |
||||
a.js-delete-subtask-item {{_ "delete"}}... |
||||
|
||||
template(name="subtasksItems") |
||||
.subtasks-items.js-subtasks-items |
||||
each item in subtasks.items |
||||
+inlinedForm(classNames="js-edit-subtask-item" item = item subtasks = subtasks) |
||||
+editSubtaskItemForm(type = 'item' item = item subtasks = subtasks) |
||||
else |
||||
+subtaskItemDetail(item = item subtasks = subtasks) |
||||
if canModifyCard |
||||
+inlinedForm(autoclose=false classNames="js-add-subtask-item" subtasks = subtasks) |
||||
+addSubtaskItemForm |
||||
else |
||||
a.add-subtask-item.js-open-inlined-form |
||||
i.fa.fa-plus |
||||
| {{_ 'add-subtask-item'}}... |
||||
|
||||
template(name='subtaskItemDetail') |
||||
.js-subtasks-item.subtasks-item |
||||
if canModifyCard |
||||
.check-box.materialCheckBox(class="{{#if item.isFinished }}is-checked{{/if}}") |
||||
.item-title.js-open-inlined-form.is-editable(class="{{#if item.isFinished }}is-checked{{/if}}") |
||||
+viewer |
||||
= item.title |
||||
else |
||||
.materialCheckBox(class="{{#if item.isFinished }}is-checked{{/if}}") |
||||
.item-title(class="{{#if item.isFinished }}is-checked{{/if}}") |
||||
+viewer |
||||
= item.title |
@ -0,0 +1,145 @@ |
||||
BlazeComponent.extendComponent({ |
||||
canModifyCard() { |
||||
return Meteor.user() && Meteor.user().isBoardMember() && !Meteor.user().isCommentOnly(); |
||||
}, |
||||
}).register('subtaskDetail'); |
||||
|
||||
BlazeComponent.extendComponent({ |
||||
|
||||
addSubtask(event) { |
||||
event.preventDefault(); |
||||
const textarea = this.find('textarea.js-add-subtask-item'); |
||||
const title = textarea.value.trim(); |
||||
const cardId = this.currentData().cardId; |
||||
const card = Cards.findOne(cardId); |
||||
const sortIndex = -1; |
||||
const crtBoard = Boards.findOne(card.boardId); |
||||
const targetBoard = crtBoard.getDefaultSubtasksBoard(); |
||||
const listId = targetBoard.getDefaultSubtasksListId(); |
||||
const swimlaneId = targetBoard.getDefaultSwimline()._id; |
||||
|
||||
if (title) { |
||||
const _id = Cards.insert({ |
||||
title, |
||||
parentId: cardId, |
||||
members: [], |
||||
labelIds: [], |
||||
customFields: [], |
||||
listId, |
||||
boardId: targetBoard._id, |
||||
sort: sortIndex, |
||||
swimlaneId, |
||||
}); |
||||
|
||||
// In case the filter is active we need to add the newly inserted card in
|
||||
// the list of exceptions -- cards that are not filtered. Otherwise the
|
||||
// card will disappear instantly.
|
||||
// See https://github.com/wekan/wekan/issues/80
|
||||
Filter.addException(_id); |
||||
|
||||
|
||||
setTimeout(() => { |
||||
this.$('.add-subtask-item').last().click(); |
||||
}, 100); |
||||
} |
||||
textarea.value = ''; |
||||
textarea.focus(); |
||||
}, |
||||
|
||||
canModifyCard() { |
||||
return Meteor.user() && Meteor.user().isBoardMember() && !Meteor.user().isCommentOnly(); |
||||
}, |
||||
|
||||
deleteSubtask() { |
||||
const subtask = this.currentData().subtask; |
||||
if (subtask && subtask._id) { |
||||
subtask.archive(); |
||||
this.toggleDeleteDialog.set(false); |
||||
} |
||||
}, |
||||
|
||||
editSubtask(event) { |
||||
event.preventDefault(); |
||||
const textarea = this.find('textarea.js-edit-subtask-item'); |
||||
const title = textarea.value.trim(); |
||||
const subtask = this.currentData().subtask; |
||||
subtask.setTitle(title); |
||||
}, |
||||
|
||||
onCreated() { |
||||
this.toggleDeleteDialog = new ReactiveVar(false); |
||||
this.subtaskToDelete = null; //Store data context to pass to subtaskDeleteDialog template
|
||||
}, |
||||
|
||||
pressKey(event) { |
||||
//If user press enter key inside a form, submit it
|
||||
//Unless the user is also holding down the 'shift' key
|
||||
if (event.keyCode === 13 && !event.shiftKey) { |
||||
event.preventDefault(); |
||||
const $form = $(event.currentTarget).closest('form'); |
||||
$form.find('button[type=submit]').click(); |
||||
} |
||||
}, |
||||
|
||||
events() { |
||||
const events = { |
||||
'click .toggle-delete-subtask-dialog'(event) { |
||||
if($(event.target).hasClass('js-delete-subtask')){ |
||||
this.subtaskToDelete = this.currentData().subtask; //Store data context
|
||||
} |
||||
this.toggleDeleteDialog.set(!this.toggleDeleteDialog.get()); |
||||
}, |
||||
'click .js-view-subtask'(event) { |
||||
if($(event.target).hasClass('js-view-subtask')){ |
||||
const subtask = this.currentData().subtask; |
||||
const board = subtask.board(); |
||||
FlowRouter.go('card', { |
||||
boardId: board._id, |
||||
slug: board.slug, |
||||
cardId: subtask._id, |
||||
}); |
||||
} |
||||
}, |
||||
}; |
||||
|
||||
return [{ |
||||
...events, |
||||
'submit .js-add-subtask': this.addSubtask, |
||||
'submit .js-edit-subtask-title': this.editSubtask, |
||||
'click .confirm-subtask-delete': this.deleteSubtask, |
||||
keydown: this.pressKey, |
||||
}]; |
||||
}, |
||||
}).register('subtasks'); |
||||
|
||||
Template.subtaskDeleteDialog.onCreated(() => { |
||||
const $cardDetails = this.$('.card-details'); |
||||
this.scrollState = { position: $cardDetails.scrollTop(), //save current scroll position
|
||||
top: false, //required for smooth scroll animation
|
||||
}; |
||||
//Callback's purpose is to only prevent scrolling after animation is complete
|
||||
$cardDetails.animate({ scrollTop: 0 }, 500, () => { this.scrollState.top = true; }); |
||||
|
||||
//Prevent scrolling while dialog is open
|
||||
$cardDetails.on('scroll', () => { |
||||
if(this.scrollState.top) { //If it's already in position, keep it there. Otherwise let animation scroll
|
||||
$cardDetails.scrollTop(0); |
||||
} |
||||
}); |
||||
}); |
||||
|
||||
Template.subtaskDeleteDialog.onDestroyed(() => { |
||||
const $cardDetails = this.$('.card-details'); |
||||
$cardDetails.off('scroll'); //Reactivate scrolling
|
||||
$cardDetails.animate( { scrollTop: this.scrollState.position }); |
||||
}); |
||||
|
||||
Template.subtaskItemDetail.helpers({ |
||||
canModifyCard() { |
||||
return Meteor.user() && Meteor.user().isBoardMember() && !Meteor.user().isCommentOnly(); |
||||
}, |
||||
}); |
||||
|
||||
BlazeComponent.extendComponent({ |
||||
// ...
|
||||
}).register('subtaskItemDetail'); |
@ -0,0 +1,142 @@ |
||||
.js-add-subtask |
||||
color: #8c8c8c |
||||
|
||||
textarea.js-add-subtask-item, textarea.js-edit-subtask-item |
||||
overflow: hidden |
||||
word-wrap: break-word |
||||
resize: none |
||||
height: 34px |
||||
|
||||
.delete-text |
||||
color: #8c8c8c |
||||
text-decoration: underline |
||||
word-wrap: break-word |
||||
float: right |
||||
padding-top: 6px |
||||
&:hover |
||||
color: inherit |
||||
|
||||
.subtask-title |
||||
.checkbox |
||||
float: left |
||||
width: 30px |
||||
height 30px |
||||
font-size: 18px |
||||
line-height: 30px |
||||
|
||||
.title |
||||
font-size: 18px |
||||
line-height: 25px |
||||
|
||||
.subtasks-stat |
||||
margin: 0 0.5em |
||||
float: right |
||||
padding-top: 6px |
||||
&.is-finished |
||||
color: #3cb500 |
||||
|
||||
.js-delete-subtask |
||||
@extends .delete-text |
||||
margin: 0 0.5em |
||||
|
||||
.js-view-subtask |
||||
@extends .delete-text |
||||
|
||||
.js-confirm-subtask-delete |
||||
background-color: darken(white, 3%) |
||||
position: absolute |
||||
float: left; |
||||
width: 60% |
||||
margin-top: 0 |
||||
margin-left: 13% |
||||
padding-bottom: 2% |
||||
padding-left: 3% |
||||
padding-right: 3% |
||||
z-index: 17 |
||||
border-radius: 3px |
||||
|
||||
p |
||||
position: relative |
||||
margin-top: 3% |
||||
width: 100% |
||||
text-align: center |
||||
span |
||||
font-weight: bold |
||||
|
||||
i |
||||
font-size: 2em |
||||
|
||||
.js-subtask-delete-buttons |
||||
position: relative |
||||
padding: left 2% right 2% |
||||
.confirm-subtask-delete |
||||
margin-left: 12% |
||||
float: left |
||||
.toggle-delete-subtask-dialog |
||||
margin-right: 12% |
||||
float: right |
||||
|
||||
#card-details-overlay |
||||
top: 0 |
||||
bottom: -600px |
||||
right: 0 |
||||
|
||||
.subtasks |
||||
background: darken(white, 3%) |
||||
|
||||
&.placeholder |
||||
background: darken(white, 20%) |
||||
border-radius: 2px |
||||
|
||||
&.ui-sortable-helper |
||||
box-shadow: -2px 2px 8px rgba(0, 0, 0, .3), |
||||
0 0 1px rgba(0, 0, 0, .5) |
||||
transform: rotate(4deg) |
||||
cursor: grabbing |
||||
|
||||
|
||||
.subtasks-item |
||||
margin: 0 0 0 0.1em |
||||
line-height: 18px |
||||
font-size: 1.1em |
||||
margin-top: 3px |
||||
display: flex |
||||
background: darken(white, 3%) |
||||
|
||||
&.placeholder |
||||
background: darken(white, 20%) |
||||
border-radius: 2px |
||||
|
||||
&.ui-sortable-helper |
||||
box-shadow: -2px 2px 8px rgba(0, 0, 0, .3), |
||||
0 0 1px rgba(0, 0, 0, .5) |
||||
transform: rotate(4deg) |
||||
cursor: grabbing |
||||
|
||||
&:hover |
||||
background-color: darken(white, 8%) |
||||
|
||||
.check-box |
||||
margin: 0.1em 0 0 0; |
||||
&.is-checked |
||||
border-bottom: 2px solid #3cb500 |
||||
border-right: 2px solid #3cb500 |
||||
|
||||
.item-title |
||||
flex: 1 |
||||
padding-left: 10px; |
||||
&.is-checked |
||||
color: #8c8c8c |
||||
font-style: italic |
||||
& .viewer |
||||
p |
||||
margin-bottom: 2px |
||||
|
||||
.js-delete-subtask-item |
||||
margin: 0 0 0.5em 1.33em |
||||
@extends .delete-text |
||||
padding: 12px 0 0 0 |
||||
|
||||
.add-subtask-item |
||||
margin: 0.2em 0 0.5em 1.33em |
||||
display: inline-block |
Loading…
Reference in new issue