mirror of
https://github.com/wekan/wekan.git
synced 2025-12-16 15:30:13 +01:00
Renaissance
_,,ad8888888888bba,_
,ad88888I888888888888888ba,
,88888888I88888888888888888888a,
,d888888888I8888888888888888888888b,
d88888PP"""" ""YY88888888888888888888b,
,d88"'__,,--------,,,,.;ZZZY8888888888888,
,8IIl'" ;;l"ZZZIII8888888888,
,I88l;' ;lZZZZZ888III8888888,
,II88Zl;. ;llZZZZZ888888I888888,
,II888Zl;. .;;;;;lllZZZ888888I8888b
,II8888Z;; `;;;;;''llZZ8888888I8888,
II88888Z;' .;lZZZ8888888I888b
II88888Z; _,aaa, .,aaaaa,__.l;llZZZ88888888I888
II88888IZZZZZZZZZ, .ZZZZZZZZZZZZZZ;llZZ88888888I888,
II88888IZZ<'(@@>Z| |ZZZ<'(@@>ZZZZ;;llZZ888888888I88I
,II88888; `""" ;| |ZZ; `""" ;;llZ8888888888I888
II888888l `;; .;llZZ8888888888I888,
,II888888Z; ;;; .;;llZZZ8888888888I888I
III888888Zl; .., `;; ,;;lllZZZ88888888888I888
II88888888Z;;...;(_ _) ,;;;llZZZZ88888888888I888,
II88888888Zl;;;;;' `--'Z;. .,;;;;llZZZZ88888888888I888b
]I888888888Z;;;;' ";llllll;..;;;lllZZZZ88888888888I8888,
II888888888Zl.;;"Y88bd888P";;,..;lllZZZZZ88888888888I8888I
II8888888888Zl;.; `"PPP";;;,..;lllZZZZZZZ88888888888I88888
II888888888888Zl;;. `;;;l;;;;lllZZZZZZZZW88888888888I88888
`II8888888888888Zl;. ,;;lllZZZZZZZZWMZ88888888888I88888
II8888888888888888ZbaalllZZZZZZZZZWWMZZZ8888888888I888888,
`II88888888888888888b"WWZZZZZWWWMMZZZZZZI888888888I888888b
`II88888888888888888;ZZMMMMMMZZZZZZZZllI888888888I8888888
`II8888888888888888 `;lZZZZZZZZZZZlllll888888888I8888888,
II8888888888888888, `;lllZZZZllllll;;.Y88888888I8888888b,
,II8888888888888888b .;;lllllll;;;.;..88888888I88888888b,
II888888888888888PZI;. .`;;;.;;;..; ...88888888I8888888888,
II888888888888PZ;;';;. ;. .;. .;. .. Y8888888I88888888888b,
,II888888888PZ;;' `8888888I8888888888888b,
II888888888' 888888I8888888888888888
,II888888888 ,888888I8888888888888888
,d88888888888 d888888I8888888888ZZZZZZ
,ad888888888888I 8888888I8888ZZZZZZZZZZZZ
888888888888888' 888888IZZZZZZZZZZZZZZZZZ
8888888888P'8P' Y888ZZZZZZZZZZZZZZZZZZZZ
888888888, " ,ZZZZZZZZZZZZZZZZZZZZZZZ
8888888888, ,ZZZZZZZZZZZZZZZZZZZZZZZZZZ
888888888888a, _ ,ZZZZZZZZZZZZZZZZZZZZ88888888
888888888888888ba,_d' ,ZZZZZZZZZZZZZZZZZ8888888888888
8888888888888888888888bbbaaa,,,______,ZZZZZZZZZZZZZZZ88888888888888888
88888888888888888888888888888888888ZZZZZZZZZZZZZZZ88888888888888888888
8888888888888888888888888888888888ZZZZZZZZZZZZZZ8888888888888888888888
888888888888888888888888888888888ZZZZZZZZZZZZZZ88888888888888888888888
8888888888888888888888888888888ZZZZZZZZZZZZZZ8888888888888888888888888
88888888888888888888888888888ZZZZZZZZZZZZZZ888888888888888888888888888
8888888888888888888888888888ZZZZZZZZZZZZZZ88888888888888888 Normand 8
88888888888888888888888888ZZZZZZZZZZZZZZ8888888888888888888 Veilleux 8
8888888888888888888888888ZZZZZZZZZZZZZZ8888888888888888888888888888888
This commit is contained in:
commit
2dbea30842
128 changed files with 10521 additions and 0 deletions
50
client/components/lists/body.jade
Normal file
50
client/components/lists/body.jade
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
template(name="listBody")
|
||||
.minicards.clearfix.js-minicards
|
||||
if cards.count
|
||||
+inlinedForm(autoclose=false position="top")
|
||||
+addCardForm
|
||||
each cards
|
||||
.minicard.card.js-minicard.js-member-droppable(
|
||||
class="{{#if isSelected}}is-selected{{/if}}")
|
||||
a.minicard-details.clearfix.show(href=absoluteUrl)
|
||||
if cover
|
||||
.minicard-cover.js-card-cover(style="background-image: url({{cover.url}});")
|
||||
if labels
|
||||
.minicard-labels
|
||||
each labels
|
||||
.minicard-label(class="card-label-{{color}}" title="{{name}}")
|
||||
.minicard-title= title
|
||||
if members
|
||||
.minicard-members.js-minicard-members
|
||||
each members
|
||||
+userAvatar(userId=this size="small" cardId="{{../_id}}")
|
||||
.badges
|
||||
if comments.count
|
||||
.badge(title="{{_ 'card-comments-title' comments.count }}")
|
||||
span.badge-icon.icon-sm.fa.fa-comment-o
|
||||
.badge-text= comments.count
|
||||
if description
|
||||
.badge.badge-state-image-only(title=description)
|
||||
span.badge-icon.icon-sm.fa.fa-align-left
|
||||
if attachments.count
|
||||
.badge
|
||||
span.badge-icon.icon-sm.fa.fa-paperclip
|
||||
span.badge-text= attachments.count
|
||||
if currentUser.isBoardMember
|
||||
+inlinedForm(autoclose=false position="bottom")
|
||||
+addCardForm
|
||||
else
|
||||
a.open-card-composer.js-open-inlined-form
|
||||
i.fa.fa-plus
|
||||
| {{_ 'add-card'}}
|
||||
|
||||
template(name="addCardForm")
|
||||
.minicard.js-composer
|
||||
.minicard-labels.js-minicard-composer-labels
|
||||
.minicard-details.clearfix
|
||||
textarea.minicard-composer-textarea.js-card-title(autofocus)
|
||||
= getCache
|
||||
.minicard-members.js-minicard-composer-members
|
||||
.add-controls.clearfix
|
||||
button.primary.confirm(type="submit") {{_ 'add'}}
|
||||
a.fa.fa-times.dark-hover.cancel.js-close-inlined-form
|
||||
73
client/components/lists/body.js
Normal file
73
client/components/lists/body.js
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
BlazeComponent.extendComponent({
|
||||
template: function() {
|
||||
return 'listBody';
|
||||
},
|
||||
|
||||
isSelected: function() {
|
||||
return Session.equals('currentCard', this.currentData()._id);
|
||||
},
|
||||
|
||||
addCard: function(evt) {
|
||||
evt.preventDefault();
|
||||
var textarea = $(evt.currentTarget).find('textarea');
|
||||
var title = textarea.val();
|
||||
var position = this.currentData().position;
|
||||
var sortIndex;
|
||||
if (position === 'top') {
|
||||
sortIndex = Utils.getSortIndex(null, this.find('.js-minicard:first'));
|
||||
} else if (position === 'bottom') {
|
||||
sortIndex = Utils.getSortIndex(this.find('.js-minicard:last'), null);
|
||||
}
|
||||
|
||||
// Clear the form in-memory cache
|
||||
// var inputCacheKey = "addCard-" + this.listId;
|
||||
// InputsCache.set(inputCacheKey, '');
|
||||
|
||||
// title trim if not empty then
|
||||
if ($.trim(title)) {
|
||||
Cards.insert({
|
||||
title: title,
|
||||
listId: this.data()._id,
|
||||
boardId: this.data().board()._id,
|
||||
sort: sortIndex
|
||||
}, function(err, _id) {
|
||||
// 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/libreboard/libreboard/issues/80
|
||||
Filter.addException(_id);
|
||||
});
|
||||
|
||||
// We keep the form opened, empty it, and scroll to it.
|
||||
textarea.val('').focus();
|
||||
Utils.Scroll(this.find('.js-minicards')).top(1000, true);
|
||||
}
|
||||
},
|
||||
|
||||
events: function() {
|
||||
return [{
|
||||
submit: this.addCard,
|
||||
'keydown form textarea': function(evt) {
|
||||
// Pressing Enter should submit the card
|
||||
if (evt.keyCode === 13) {
|
||||
evt.preventDefault();
|
||||
$(evt.currentTarget).parents('form:first').submit();
|
||||
|
||||
// Pressing Tab should open the form of the next column, and Maj+Tab go
|
||||
// in the reverse order
|
||||
} else if (evt.keyCode === 9) {
|
||||
evt.preventDefault();
|
||||
var isReverse = evt.shiftKey;
|
||||
var list = $('#js-list-' + this.data()._id);
|
||||
var nextList = list[isReverse ? 'prev' : 'next']('.js-list').get(0) ||
|
||||
$('.js-list:' + (isReverse ? 'last' : 'first')).get(0);
|
||||
var nextListComponent = BlazeComponent.getComponentForElement(nextList);
|
||||
|
||||
// XXX Get the real position
|
||||
var position = 'bottom';
|
||||
nextListComponent.openForm({position: position});
|
||||
}
|
||||
}
|
||||
}];
|
||||
}
|
||||
}).register('listBody');
|
||||
16
client/components/lists/events.js
Normal file
16
client/components/lists/events.js
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
Template.addlistForm.events({
|
||||
submit: function(event, t) {
|
||||
event.preventDefault();
|
||||
var title = t.find('.list-name-input');
|
||||
if ($.trim(title.value)) {
|
||||
Lists.insert({
|
||||
title: title.value,
|
||||
boardId: Session.get('currentBoard'),
|
||||
sort: $('.list').length
|
||||
});
|
||||
|
||||
Utils.Scroll('.js-lists').left(270, true);
|
||||
title.value = '';
|
||||
}
|
||||
}
|
||||
});
|
||||
13
client/components/lists/header.jade
Normal file
13
client/components/lists/header.jade
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
template(name="listHeader")
|
||||
.list-header.js-list-header
|
||||
+inlinedForm
|
||||
+editListTitleForm
|
||||
else
|
||||
h2.list-header-name.js-open-inlined-form= title
|
||||
a.list-header-menu-icon.fa.fa-bars.js-open-list-menu
|
||||
|
||||
template(name="editListTitleForm")
|
||||
input.field.single-line(type="text" value="{{getCache title}}" autofocus)
|
||||
.edit-controls.clearfix
|
||||
input.primary.confirm(type="submit" value="{{_ 'save'}}")
|
||||
a.fa.fa-times.js-close-inlined-form
|
||||
25
client/components/lists/header.js
Normal file
25
client/components/lists/header.js
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
BlazeComponent.extendComponent({
|
||||
template: function() {
|
||||
return 'listHeader';
|
||||
},
|
||||
|
||||
editTitle: function(evt) {
|
||||
evt.preventDefault();
|
||||
var form = this.componentChildren('inlinedForm')[0];
|
||||
var newTitle = form.getValue();
|
||||
if ($.trim(newTitle)) {
|
||||
Lists.update(this.currentData()._id, {
|
||||
$set: {
|
||||
title: newTitle
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
events: function() {
|
||||
return [{
|
||||
'click .js-open-list-menu': Popup.open('listAction'),
|
||||
submit: this.editTitle
|
||||
}];
|
||||
}
|
||||
}).register('listHeader');
|
||||
5
client/components/lists/main.jade
Normal file
5
client/components/lists/main.jade
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
template(name='list')
|
||||
.list.js-list(id="js-list-{{_id}}")
|
||||
.list-wrapper
|
||||
+listHeader
|
||||
+listBody
|
||||
81
client/components/lists/main.js
Normal file
81
client/components/lists/main.js
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
ListComponent = BlazeComponent.extendComponent({
|
||||
template: function() {
|
||||
return 'list';
|
||||
},
|
||||
|
||||
openForm: function(options) {
|
||||
options = options || {};
|
||||
options.position = options.position || 'top';
|
||||
|
||||
var listComponent = this.componentChildren('listBody')[0];
|
||||
var forms = listComponent.componentChildren('inlinedForm');
|
||||
|
||||
if (options.position === 'top') {
|
||||
forms[0].open();
|
||||
} else {
|
||||
forms[forms.length - 1].open();
|
||||
}
|
||||
},
|
||||
|
||||
// XXX The jQuery UI sortable plugin is far from ideal here. First we include
|
||||
// all jQuery components but only use one. Second, it modifies the DOM itself,
|
||||
// resulting in Blaze abandoning reactive update of the nodes that have been
|
||||
// moved which result in bugs if multiple users use the board in real time.
|
||||
// I tried sortable:sortable but that was not better. Should we “simply” write
|
||||
// the drag&drop code ourselves?
|
||||
onRendered: function() {
|
||||
if (Meteor.user().isBoardMember()) {
|
||||
var $cards = this.$('.js-minicards');
|
||||
$cards.sortable({
|
||||
connectWith: ".js-minicards",
|
||||
tolerance: 'pointer',
|
||||
appendTo: '.js-lists',
|
||||
helper: "clone",
|
||||
items: '.js-minicard:not(.placeholder, .hide, .js-composer)',
|
||||
placeholder: 'minicard placeholder',
|
||||
start: function (event, ui) {
|
||||
$('.minicard.placeholder').height(ui.item.height());
|
||||
Popup.close();
|
||||
},
|
||||
stop: function(event, ui) {
|
||||
// To attribute the new index number, we need to get the dom element of
|
||||
// the previous and the following card -- if any.
|
||||
var cardDomElement = ui.item.get(0);
|
||||
var prevCardDomElement = ui.item.prev('.js-minicard').get(0);
|
||||
var nextCardDomElement = ui.item.next('.js-minicard').get(0);
|
||||
var sort = Utils.getSortIndex(prevCardDomElement, nextCardDomElement);
|
||||
var cardId = Blaze.getData(cardDomElement)._id;
|
||||
var listId = Blaze.getData(ui.item.parents('.list').get(0))._id;
|
||||
Cards.update(cardId, {
|
||||
$set: {
|
||||
listId: listId,
|
||||
sort: sort
|
||||
}
|
||||
});
|
||||
}
|
||||
}).disableSelection();
|
||||
|
||||
Utils.liveEvent('mouseover', function($el) {
|
||||
$el.find('.js-member-droppable').droppable({
|
||||
hoverClass: "draggable-hover-card",
|
||||
accept: '.js-member',
|
||||
drop: function(event, ui) {
|
||||
var memberId = Blaze.getData(ui.draggable.get(0)).userId;
|
||||
var cardId = Blaze.getData(this)._id;
|
||||
Cards.update(cardId, {$addToSet: {members: memberId}});
|
||||
}
|
||||
});
|
||||
|
||||
$el.find('.js-member-droppable').droppable({
|
||||
hoverClass: "draggable-hover-card",
|
||||
accept: '.js-label',
|
||||
drop: function(event, ui) {
|
||||
var labelId = Blaze.getData(ui.draggable.get(0))._id;
|
||||
var cardId = Blaze.getData(this)._id;
|
||||
Cards.update(cardId, {$addToSet: {labelIds: labelId}});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}).register('list');
|
||||
136
client/components/lists/main.styl
Normal file
136
client/components/lists/main.styl
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
@import 'nib'
|
||||
|
||||
.list
|
||||
box-sizing: border-box
|
||||
display: flex
|
||||
flex-direction: column
|
||||
flex: 0 0 270px
|
||||
position: relative
|
||||
// Even if this background color is the same as the body we can't leave it
|
||||
// transparent, because that won't work during a list drag.
|
||||
background: darken(white, 10%)
|
||||
height: 100%
|
||||
border-right: 1px solid darken(white, 17%)
|
||||
border-left: 1px solid darken(white, 4%)
|
||||
padding: 12px 7px 5px
|
||||
overflow-y: auto
|
||||
|
||||
&:first-child
|
||||
margin-left: 5px
|
||||
border-left: none
|
||||
|
||||
&:last-child
|
||||
margin-right: 5px
|
||||
border-right: none
|
||||
|
||||
&.editable
|
||||
cursor: grab
|
||||
|
||||
.list-wrapper
|
||||
cursor: default
|
||||
|
||||
&.add-list
|
||||
&.fade
|
||||
opacity: 0
|
||||
|
||||
.list-name-input
|
||||
background: rgba(0, 0, 0, .05)
|
||||
border-color: #aaa
|
||||
box-shadow: inset 0 1px 8px rgba(0, 0, 0, .15)
|
||||
display: block
|
||||
margin: 0
|
||||
transition: margin 85ms ease-in,
|
||||
background 85ms ease-in
|
||||
width: 100%
|
||||
|
||||
.edit-controls
|
||||
height: 32px
|
||||
transition: margin 85ms ease-in,
|
||||
height 85ms ease-in
|
||||
overflow: hidden
|
||||
margin: 4px 0 0
|
||||
|
||||
input[type=submit]
|
||||
margin-top: 0
|
||||
min-height: 30px
|
||||
height: 30px
|
||||
|
||||
.list-header
|
||||
flex: 0 0 auto
|
||||
padding: 10px 26px 4px 6px
|
||||
position: relative
|
||||
min-height: 20px
|
||||
|
||||
.list-header-name
|
||||
display: inline
|
||||
font-size: 16px
|
||||
line-height: 17px
|
||||
margin: 0
|
||||
font-weight: bold
|
||||
min-height: 9px
|
||||
min-width: 30px
|
||||
overflow: hidden
|
||||
text-overflow: ellipsis
|
||||
word-wrap: break-word
|
||||
|
||||
.list-header-menu-icon
|
||||
background-clip: content-box
|
||||
background-origin: content-box
|
||||
padding: 6px 8px
|
||||
position: absolute
|
||||
top: 3px
|
||||
right: -5px
|
||||
color: #a6a6a6
|
||||
|
||||
.list-header-num-cards
|
||||
color: #8c8c8c
|
||||
margin: 0
|
||||
|
||||
.minicards
|
||||
// flex: 1 1 auto
|
||||
overflow-y: auto
|
||||
overflow-x: hidden
|
||||
padding: 4px 4px 1px
|
||||
z-index: 1
|
||||
height: 100%
|
||||
|
||||
&::-webkit-scrollbar-button
|
||||
display: block
|
||||
height: 4px
|
||||
|
||||
.open-card-composer
|
||||
border-top-left-radius: 0
|
||||
border-top-right-radius: 0
|
||||
border-bottom-right-radius: 3px
|
||||
border-bottom-left-radius: 3px
|
||||
color: #8c8c8c
|
||||
display: block
|
||||
// flex: 0 0 auto
|
||||
margin: 2px -3px -3px
|
||||
padding: 7px 10px
|
||||
position: relative
|
||||
text-decoration: none
|
||||
|
||||
&:hover
|
||||
background: #c3c3c3
|
||||
color: #222
|
||||
text-decoration: underline
|
||||
|
||||
|
||||
&::selection
|
||||
background: transparent
|
||||
|
||||
.list.placeholder
|
||||
background-color: rgba(0, 0, 0, .2)
|
||||
border-color: transparent
|
||||
box-shadow: none
|
||||
height: 100px
|
||||
|
||||
.list.ui-sortable-helper
|
||||
cursor: grabbing
|
||||
box-shadow: -2px 2px 8px rgba(0, 0, 0, .3), 0 0 1px rgba(0, 0, 0, .5)
|
||||
transform: rotate(4deg)
|
||||
|
||||
|
||||
.list.ui-sortable-helper .list-header-menu-icon
|
||||
display: none
|
||||
28
client/components/lists/menu.jade
Normal file
28
client/components/lists/menu.jade
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
template(name="listActionPopup")
|
||||
ul.pop-over-list
|
||||
li: a.js-add-card {{_ 'add-card'}}
|
||||
li: a.highlight-icon.js-list-subscribe {{_ 'subscribe'}}
|
||||
if cards.count
|
||||
hr
|
||||
ul.pop-over-list
|
||||
li: a.js-move-cards {{_ 'list-move-cards'}}
|
||||
li: a.js-archive-cards {{_ 'list-archive-cards'}}
|
||||
hr
|
||||
ul.pop-over-list
|
||||
li: a.js-close-list {{_ 'archive-list'}}
|
||||
|
||||
template(name="listMoveCardsPopup")
|
||||
+boardLists
|
||||
|
||||
template(name="boardLists")
|
||||
ul.pop-over-list
|
||||
each currentBoard.lists
|
||||
li
|
||||
if($eq ../_id _id)
|
||||
a.disabled {{title}} ({{_ 'current'}})
|
||||
else
|
||||
a.js-select-list= title
|
||||
|
||||
template(name="listArchiveCardsPopup")
|
||||
p {{_ 'list-archive-cards-pop'}}
|
||||
input.js-confirm.negate.full(type="submit" value="{{_ 'archive-all'}}")
|
||||
46
client/components/lists/menu.js
Normal file
46
client/components/lists/menu.js
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
Template.listActionPopup.events({
|
||||
'click .js-add-card': function() {
|
||||
// XXX We need a better API and architecture here. See
|
||||
// https://github.com/peerlibrary/meteor-blaze-components/issues/19
|
||||
var listDom = document.getElementById('js-list-' + this._id);
|
||||
var listComponent = Blaze.getView(listDom).templateInstance().get('component');
|
||||
listComponent.openForm();
|
||||
Popup.close();
|
||||
},
|
||||
'click .js-list-subscribe': function() {},
|
||||
'click .js-move-cards': Popup.open('listMoveCards'),
|
||||
'click .js-archive-cards': Popup.afterConfirm('listArchiveCards', function() {
|
||||
Cards.find({listId: this._id}).forEach(function(card) {
|
||||
Cards.update(card._id, {
|
||||
$set: {
|
||||
archived: true
|
||||
}
|
||||
});
|
||||
});
|
||||
Popup.close();
|
||||
}),
|
||||
'click .js-close-list': function(evt) {
|
||||
evt.preventDefault();
|
||||
Lists.update(this._id, {
|
||||
$set: {
|
||||
archived: true
|
||||
}
|
||||
});
|
||||
Popup.close();
|
||||
}
|
||||
});
|
||||
|
||||
Template.listMoveCardsPopup.events({
|
||||
'click .js-select-list': function() {
|
||||
var fromList = Template.parentData(2).data._id;
|
||||
var toList = this._id;
|
||||
Cards.find({listId: fromList}).forEach(function(card) {
|
||||
Cards.update(card._id, {
|
||||
$set: {
|
||||
listId: toList
|
||||
}
|
||||
});
|
||||
});
|
||||
Popup.close();
|
||||
}
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue