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:
Maxime Quandalle 2015-05-12 19:20:58 +02:00
commit 2dbea30842
128 changed files with 10521 additions and 0 deletions

View 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

View 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');

View 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 = '';
}
}
});

View 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

View 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');

View file

@ -0,0 +1,5 @@
template(name='list')
.list.js-list(id="js-list-{{_id}}")
.list-wrapper
+listHeader
+listBody

View 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');

View 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

View 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'}}")

View 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();
}
});