From b5dabfe88695a8f8211b29fea0dc16131c9a1829 Mon Sep 17 00:00:00 2001 From: Maxime Quandalle Date: Fri, 28 Aug 2015 02:21:42 +0200 Subject: More explicit file names --- client/components/lists/body.jade | 30 ------- client/components/lists/body.js | 143 -------------------------------- client/components/lists/header.jade | 16 ---- client/components/lists/header.js | 25 ------ client/components/lists/list.jade | 4 + client/components/lists/list.js | 126 ++++++++++++++++++++++++++++ client/components/lists/list.styl | 110 ++++++++++++++++++++++++ client/components/lists/listBody.jade | 30 +++++++ client/components/lists/listBody.js | 143 ++++++++++++++++++++++++++++++++ client/components/lists/listHeader.jade | 16 ++++ client/components/lists/listHeader.js | 25 ++++++ client/components/lists/listMenu.jade | 29 +++++++ client/components/lists/listMenu.js | 52 ++++++++++++ client/components/lists/main.jade | 4 - client/components/lists/main.js | 126 ---------------------------- client/components/lists/main.styl | 110 ------------------------ client/components/lists/menu.jade | 29 ------- client/components/lists/menu.js | 52 ------------ 18 files changed, 535 insertions(+), 535 deletions(-) delete mode 100644 client/components/lists/body.jade delete mode 100644 client/components/lists/body.js delete mode 100644 client/components/lists/header.jade delete mode 100644 client/components/lists/header.js create mode 100644 client/components/lists/list.jade create mode 100644 client/components/lists/list.js create mode 100644 client/components/lists/list.styl create mode 100644 client/components/lists/listBody.jade create mode 100644 client/components/lists/listBody.js create mode 100644 client/components/lists/listHeader.jade create mode 100644 client/components/lists/listHeader.js create mode 100644 client/components/lists/listMenu.jade create mode 100644 client/components/lists/listMenu.js delete mode 100644 client/components/lists/main.jade delete mode 100644 client/components/lists/main.js delete mode 100644 client/components/lists/main.styl delete mode 100644 client/components/lists/menu.jade delete mode 100644 client/components/lists/menu.js (limited to 'client/components/lists') diff --git a/client/components/lists/body.jade b/client/components/lists/body.jade deleted file mode 100644 index b0a374ea..00000000 --- a/client/components/lists/body.jade +++ /dev/null @@ -1,30 +0,0 @@ -template(name="listBody") - .list-body.js-perfect-scrollbar - .minicards.clearfix.js-minicards - if cards.count - +inlinedForm(autoclose=false position="top") - +addCardForm(listId=_id position="top") - each cards - a.minicard-wrapper.js-minicard(href=absoluteUrl - class="{{#if cardIsSelected}}is-selected{{/if}}" - class="{{#if MultiSelection.isSelected _id}}is-checked{{/if}}") - if MultiSelection.isActive - .materialCheckBox.multi-selection-checkbox.js-toggle-multi-selection( - class="{{#if MultiSelection.isSelected _id}}is-checked{{/if}}") - +minicard(this) - if currentUser.isBoardMember - +inlinedForm(autoclose=false position="bottom") - +addCardForm(listId=_id position="bottom") - else - a.open-minicard-composer.js-card-composer.js-open-inlined-form - i.fa.fa-plus - | {{_ 'add-card'}} - -template(name="addCardForm") - .minicard.minicard-composer.js-composer - .minicard-detailss.clearfix - textarea.minicard-composer-textarea.js-card-title(autofocus) - .minicard-members.js-minicard-composer-members - .add-controls.clearfix - button.primary.confirm(type="submit") {{_ 'add'}} - a.fa.fa-times-thin.js-close-inlined-form diff --git a/client/components/lists/body.js b/client/components/lists/body.js deleted file mode 100644 index 27864474..00000000 --- a/client/components/lists/body.js +++ /dev/null @@ -1,143 +0,0 @@ -BlazeComponent.extendComponent({ - template: function() { - return 'listBody'; - }, - - mixins: function() { - return [Mixins.PerfectScrollbar]; - }, - - openForm: function(options) { - options = options || {}; - options.position = options.position || 'top'; - - var forms = this.componentChildren('inlinedForm'); - var form = _.find(forms, function(component) { - return component.data().position === options.position; - }); - if (! form && forms.length > 0) { - form = forms[0]; - } - form.open(); - }, - - addCard: function(evt) { - evt.preventDefault(); - var textarea = $(evt.currentTarget).find('textarea'); - var title = textarea.val(); - var position = Blaze.getData(evt.currentTarget).position; - var sortIndex; - var firstCard = this.find('.js-minicard:first'); - var lastCard = this.find('.js-minicard:last'); - if (position === 'top') { - sortIndex = Utils.calculateIndex(null, firstCard).base; - } else if (position === 'bottom') { - sortIndex = Utils.calculateIndex(lastCard, null).base; - } - - if ($.trim(title)) { - var _id = Cards.insert({ - title: title, - listId: this.data()._id, - boardId: this.data().board()._id, - sort: sortIndex - }); - // 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(); - if (position === 'bottom') { - this.scrollToBottom(); - } - } - }, - - scrollToBottom: function() { - var container = this.firstNode(); - $(container).animate({ - scrollTop: container.scrollHeight - }); - }, - - clickOnMiniCard: function(evt) { - if (MultiSelection.isActive() || evt.shiftKey) { - evt.stopImmediatePropagation(); - evt.preventDefault(); - var methodName = evt.shiftKey ? 'toogleRange' : 'toogle'; - MultiSelection[methodName](this.currentData()._id); - - // If the card is already selected, we want to de-select it. - // XXX We should probably modify the minicard href attribute instead of - // overwriting the event in case the card is already selected. - } else if (Session.equals('currentCard', this.currentData()._id)) { - evt.stopImmediatePropagation(); - evt.preventDefault(); - Utils.goBoardId(Session.get('currentBoard')); - } - }, - - cardIsSelected: function() { - return Session.equals('currentCard', this.currentData()._id); - }, - - toggleMultiSelection: function(evt) { - evt.stopPropagation(); - evt.preventDefault(); - MultiSelection.toogle(this.currentData()._id); - }, - - events: function() { - return [{ - 'click .js-minicard': this.clickOnMiniCard, - 'click .js-toggle-multi-selection': this.toggleMultiSelection, - 'click .open-minicard-composer': this.scrollToBottom, - submit: this.addCard - }]; - } -}).register('listBody'); - -BlazeComponent.extendComponent({ - template: function() { - return 'addCardForm'; - }, - - pressKey: function(evt) { - // Pressing Enter should submit the card - if (evt.keyCode === 13) { - evt.preventDefault(); - var $form = $(evt.currentTarget).closest('form'); - // XXX For some reason $form.submit() does not work (it's probably a bug - // of blaze-component related to the fact that the submit event is non- - // bubbling). This is why we click on the submit button instead -- which - // work. - $form.find('button[type=submit]').click(); - - // 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().listId); - var listSelector = '.js-list:not(.js-list-composer)'; - var nextList = list[isReverse ? 'prev' : 'next'](listSelector).get(0); - // If there is no next list, loop back to the beginning. - if (! nextList) { - nextList = $(listSelector + (isReverse ? ':last' : ':first')).get(0); - } - - BlazeComponent.getComponentForElement(nextList).openForm({ - position:this.data().position - }); - } - }, - - events: function() { - return [{ - keydown: this.pressKey - }]; - } -}).register('addCardForm'); diff --git a/client/components/lists/header.jade b/client/components/lists/header.jade deleted file mode 100644 index 288cfd57..00000000 --- a/client/components/lists/header.jade +++ /dev/null @@ -1,16 +0,0 @@ -template(name="listHeader") - .list-header.js-list-header - +inlinedForm - +editListTitleForm - else - h2.list-header-name( - class="{{#if currentUser.isBoardMember}}js-open-inlined-form is-editable{{/if}}") - = title - a.list-header-menu-icon.fa.fa-bars.js-open-list-menu - -template(name="editListTitleForm") - .list-composer - input.full-line(type="text" value=title autofocus) - .edit-controls.clearfix - button.primary.confirm(type="submit") {{_ 'save'}} - a.fa.fa-times-thin.js-close-inlined-form diff --git a/client/components/lists/header.js b/client/components/lists/header.js deleted file mode 100644 index 014cfd80..00000000 --- a/client/components/lists/header.js +++ /dev/null @@ -1,25 +0,0 @@ -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'); diff --git a/client/components/lists/list.jade b/client/components/lists/list.jade new file mode 100644 index 00000000..c959b87f --- /dev/null +++ b/client/components/lists/list.jade @@ -0,0 +1,4 @@ +template(name='list') + .list.js-list(id="js-list-{{_id}}") + +listHeader + +listBody diff --git a/client/components/lists/list.js b/client/components/lists/list.js new file mode 100644 index 00000000..3b602f43 --- /dev/null +++ b/client/components/lists/list.js @@ -0,0 +1,126 @@ +BlazeComponent.extendComponent({ + template: function() { + return 'list'; + }, + + // Proxies + openForm: function(options) { + this.componentChildren('listBody')[0].openForm(options); + }, + + onCreated: function() { + this.newCardFormIsVisible = new ReactiveVar(true); + }, + + // The jquery UI sortable library is the best solution I've found so far. I + // tried sortable and dragula but they were not powerful enough four our use + // case. I also considered writing/forking a drag-and-drop + sortable library + // but it's probably too much work. + // By calling asking the sortable library to cancel its move on the `stop` + // callback, we basically solve all issues related to reactive updates. A + // comment below provides further details. + onRendered: function() { + var self = this; + if (! Meteor.user() || ! Meteor.user().isBoardMember()) + return; + + var boardComponent = self.componentParent(); + var itemsSelector = '.js-minicard:not(.placeholder, .js-card-composer)'; + var $cards = self.$('.js-minicards'); + $cards.sortable({ + connectWith: '.js-minicards', + tolerance: 'pointer', + appendTo: 'body', + helper: function(evt, item) { + var helper = item.clone(); + if (MultiSelection.isActive()) { + var andNOthers = $cards.find('.js-minicard.is-checked').length - 1; + if (andNOthers > 0) { + helper.append($(Blaze.toHTML(HTML.DIV( + // XXX Super bad class name + {'class': 'and-n-other'}, + // XXX Need to translate + 'and ' + andNOthers + ' other cards.' + )))); + } + } + return helper; + }, + distance: 7, + items: itemsSelector, + scroll: false, + placeholder: 'minicard-wrapper placeholder', + start: function(evt, ui) { + ui.placeholder.height(ui.helper.height()); + EscapeActions.executeUpTo('popup'); + boardComponent.setIsDragging(true); + }, + stop: function(evt, ui) { + // To attribute the new index number, we need to get the DOM element + // of the previous and the following card -- if any. + var prevCardDom = ui.item.prev('.js-minicard').get(0); + var nextCardDom = ui.item.next('.js-minicard').get(0); + var nCards = MultiSelection.isActive() ? MultiSelection.count() : 1; + var sortIndex = Utils.calculateIndex(prevCardDom, nextCardDom, nCards); + var listId = Blaze.getData(ui.item.parents('.list').get(0))._id; + + // Normally the jquery-ui sortable library moves the dragged DOM element + // to its new position, which disrupts Blaze reactive updates mechanism + // (especially when we move the last card of a list, or when multiple + // users move some cards at the same time). To prevent these UX glitches + // we ask sortable to gracefully cancel the move, and to put back the + // DOM in its initial state. The card move is then handled reactively by + // Blaze with the below query. + $cards.sortable('cancel'); + + if (MultiSelection.isActive()) { + Cards.find(MultiSelection.getMongoSelector()).forEach(function(c, i) { + Cards.update(c._id, { + $set: { + listId: listId, + sort: sortIndex.base + i * sortIndex.increment + } + }); + }); + } else { + var cardDomElement = ui.item.get(0); + var cardId = Blaze.getData(cardDomElement)._id; + Cards.update(cardId, { + $set: { + listId: listId, + sort: sortIndex.base + } + }); + } + boardComponent.setIsDragging(false); + } + }); + + // We want to re-run this function any time a card is added. + self.autorun(function() { + var currentBoardId = Tracker.nonreactive(function() { + return Session.get('currentBoard'); + }); + Cards.find({ boardId: currentBoardId }).fetch(); + Tracker.afterFlush(function() { + $cards.find(itemsSelector).droppable({ + hoverClass: 'draggable-hover-card', + accept: '.js-member,.js-label', + drop: function(event, ui) { + var cardId = Blaze.getData(this)._id; + var addToSet; + + if (ui.draggable.hasClass('js-member')) { + var memberId = Blaze.getData(ui.draggable.get(0)).userId; + addToSet = { members: memberId }; + } else { + var labelId = Blaze.getData(ui.draggable.get(0))._id; + addToSet = { labelIds: labelId }; + } + Cards.update(cardId, { $addToSet: addToSet }); + } + }); + }); + }); + } +}).register('list'); diff --git a/client/components/lists/list.styl b/client/components/lists/list.styl new file mode 100644 index 00000000..bfa0f348 --- /dev/null +++ b/client/components/lists/list.styl @@ -0,0 +1,110 @@ +@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, 13%) + height: 100% + border-left: 1px solid darken(white, 20%) + padding: 0 + + &:first-child + margin-left: 5px + border-left: none + + .card-details + & + border-left: none + + &.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) + + &.placeholder + background-color: rgba(0, 0, 0, .2) + border-color: transparent + box-shadow: none + height: 100px + + &.list-composer, & list-composer + padding: 17px + + form + margin-top: -5px + + .list-name-input + background: rgba(255, 255, 255, .4) + border-color: #aaa + 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 + +.list-header + flex: 0 0 auto + margin: 20px 12px 4px + 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 + position: absolute + top: 0 + right: 0 + +.list-body + flex: 1 + display: flex + overflow-y: auto + padding: 5px 11px + + .minicards + flex: 1 + + form + margin-bottom: 9px + + .ps-scrollbar-y-rail + transform: translateX(2px) + + .open-minicard-composer + border-radius: 2px + color: #8c8c8c + display: block + padding: 7px 10px + position: relative + text-decoration: none + animation: fadeIn 0.3s + + i.fa + margin-right: 7px + + &:hover + background: #fafafa + color: #222 + box-shadow: 0 1px 2px rgba(0,0,0,.2) diff --git a/client/components/lists/listBody.jade b/client/components/lists/listBody.jade new file mode 100644 index 00000000..b0a374ea --- /dev/null +++ b/client/components/lists/listBody.jade @@ -0,0 +1,30 @@ +template(name="listBody") + .list-body.js-perfect-scrollbar + .minicards.clearfix.js-minicards + if cards.count + +inlinedForm(autoclose=false position="top") + +addCardForm(listId=_id position="top") + each cards + a.minicard-wrapper.js-minicard(href=absoluteUrl + class="{{#if cardIsSelected}}is-selected{{/if}}" + class="{{#if MultiSelection.isSelected _id}}is-checked{{/if}}") + if MultiSelection.isActive + .materialCheckBox.multi-selection-checkbox.js-toggle-multi-selection( + class="{{#if MultiSelection.isSelected _id}}is-checked{{/if}}") + +minicard(this) + if currentUser.isBoardMember + +inlinedForm(autoclose=false position="bottom") + +addCardForm(listId=_id position="bottom") + else + a.open-minicard-composer.js-card-composer.js-open-inlined-form + i.fa.fa-plus + | {{_ 'add-card'}} + +template(name="addCardForm") + .minicard.minicard-composer.js-composer + .minicard-detailss.clearfix + textarea.minicard-composer-textarea.js-card-title(autofocus) + .minicard-members.js-minicard-composer-members + .add-controls.clearfix + button.primary.confirm(type="submit") {{_ 'add'}} + a.fa.fa-times-thin.js-close-inlined-form diff --git a/client/components/lists/listBody.js b/client/components/lists/listBody.js new file mode 100644 index 00000000..27864474 --- /dev/null +++ b/client/components/lists/listBody.js @@ -0,0 +1,143 @@ +BlazeComponent.extendComponent({ + template: function() { + return 'listBody'; + }, + + mixins: function() { + return [Mixins.PerfectScrollbar]; + }, + + openForm: function(options) { + options = options || {}; + options.position = options.position || 'top'; + + var forms = this.componentChildren('inlinedForm'); + var form = _.find(forms, function(component) { + return component.data().position === options.position; + }); + if (! form && forms.length > 0) { + form = forms[0]; + } + form.open(); + }, + + addCard: function(evt) { + evt.preventDefault(); + var textarea = $(evt.currentTarget).find('textarea'); + var title = textarea.val(); + var position = Blaze.getData(evt.currentTarget).position; + var sortIndex; + var firstCard = this.find('.js-minicard:first'); + var lastCard = this.find('.js-minicard:last'); + if (position === 'top') { + sortIndex = Utils.calculateIndex(null, firstCard).base; + } else if (position === 'bottom') { + sortIndex = Utils.calculateIndex(lastCard, null).base; + } + + if ($.trim(title)) { + var _id = Cards.insert({ + title: title, + listId: this.data()._id, + boardId: this.data().board()._id, + sort: sortIndex + }); + // 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(); + if (position === 'bottom') { + this.scrollToBottom(); + } + } + }, + + scrollToBottom: function() { + var container = this.firstNode(); + $(container).animate({ + scrollTop: container.scrollHeight + }); + }, + + clickOnMiniCard: function(evt) { + if (MultiSelection.isActive() || evt.shiftKey) { + evt.stopImmediatePropagation(); + evt.preventDefault(); + var methodName = evt.shiftKey ? 'toogleRange' : 'toogle'; + MultiSelection[methodName](this.currentData()._id); + + // If the card is already selected, we want to de-select it. + // XXX We should probably modify the minicard href attribute instead of + // overwriting the event in case the card is already selected. + } else if (Session.equals('currentCard', this.currentData()._id)) { + evt.stopImmediatePropagation(); + evt.preventDefault(); + Utils.goBoardId(Session.get('currentBoard')); + } + }, + + cardIsSelected: function() { + return Session.equals('currentCard', this.currentData()._id); + }, + + toggleMultiSelection: function(evt) { + evt.stopPropagation(); + evt.preventDefault(); + MultiSelection.toogle(this.currentData()._id); + }, + + events: function() { + return [{ + 'click .js-minicard': this.clickOnMiniCard, + 'click .js-toggle-multi-selection': this.toggleMultiSelection, + 'click .open-minicard-composer': this.scrollToBottom, + submit: this.addCard + }]; + } +}).register('listBody'); + +BlazeComponent.extendComponent({ + template: function() { + return 'addCardForm'; + }, + + pressKey: function(evt) { + // Pressing Enter should submit the card + if (evt.keyCode === 13) { + evt.preventDefault(); + var $form = $(evt.currentTarget).closest('form'); + // XXX For some reason $form.submit() does not work (it's probably a bug + // of blaze-component related to the fact that the submit event is non- + // bubbling). This is why we click on the submit button instead -- which + // work. + $form.find('button[type=submit]').click(); + + // 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().listId); + var listSelector = '.js-list:not(.js-list-composer)'; + var nextList = list[isReverse ? 'prev' : 'next'](listSelector).get(0); + // If there is no next list, loop back to the beginning. + if (! nextList) { + nextList = $(listSelector + (isReverse ? ':last' : ':first')).get(0); + } + + BlazeComponent.getComponentForElement(nextList).openForm({ + position:this.data().position + }); + } + }, + + events: function() { + return [{ + keydown: this.pressKey + }]; + } +}).register('addCardForm'); diff --git a/client/components/lists/listHeader.jade b/client/components/lists/listHeader.jade new file mode 100644 index 00000000..288cfd57 --- /dev/null +++ b/client/components/lists/listHeader.jade @@ -0,0 +1,16 @@ +template(name="listHeader") + .list-header.js-list-header + +inlinedForm + +editListTitleForm + else + h2.list-header-name( + class="{{#if currentUser.isBoardMember}}js-open-inlined-form is-editable{{/if}}") + = title + a.list-header-menu-icon.fa.fa-bars.js-open-list-menu + +template(name="editListTitleForm") + .list-composer + input.full-line(type="text" value=title autofocus) + .edit-controls.clearfix + button.primary.confirm(type="submit") {{_ 'save'}} + a.fa.fa-times-thin.js-close-inlined-form diff --git a/client/components/lists/listHeader.js b/client/components/lists/listHeader.js new file mode 100644 index 00000000..014cfd80 --- /dev/null +++ b/client/components/lists/listHeader.js @@ -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'); diff --git a/client/components/lists/listMenu.jade b/client/components/lists/listMenu.jade new file mode 100644 index 00000000..052f064c --- /dev/null +++ b/client/components/lists/listMenu.jade @@ -0,0 +1,29 @@ +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-select-cards {{_ 'list-select-cards'}} + 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'}}") diff --git a/client/components/lists/listMenu.js b/client/components/lists/listMenu.js new file mode 100644 index 00000000..dda1270c --- /dev/null +++ b/client/components/lists/listMenu.js @@ -0,0 +1,52 @@ +Template.listActionPopup.events({ + 'click .js-add-card': function() { + var listDom = document.getElementById('js-list-' + this._id); + var listComponent = BlazeComponent.getComponentForElement(listDom); + listComponent.openForm({ position: 'top' }); + Popup.close(); + }, + 'click .js-list-subscribe': function() {}, + 'click .js-select-cards': function() { + var cardIds = Cards.find( + {listId: this._id}, + {fields: { _id: 1 }} + ).map(function(card) { return card._id; }); + MultiSelection.add(cardIds); + Popup.close(); + }, + '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(); + } +}); diff --git a/client/components/lists/main.jade b/client/components/lists/main.jade deleted file mode 100644 index c959b87f..00000000 --- a/client/components/lists/main.jade +++ /dev/null @@ -1,4 +0,0 @@ -template(name='list') - .list.js-list(id="js-list-{{_id}}") - +listHeader - +listBody diff --git a/client/components/lists/main.js b/client/components/lists/main.js deleted file mode 100644 index 3b602f43..00000000 --- a/client/components/lists/main.js +++ /dev/null @@ -1,126 +0,0 @@ -BlazeComponent.extendComponent({ - template: function() { - return 'list'; - }, - - // Proxies - openForm: function(options) { - this.componentChildren('listBody')[0].openForm(options); - }, - - onCreated: function() { - this.newCardFormIsVisible = new ReactiveVar(true); - }, - - // The jquery UI sortable library is the best solution I've found so far. I - // tried sortable and dragula but they were not powerful enough four our use - // case. I also considered writing/forking a drag-and-drop + sortable library - // but it's probably too much work. - // By calling asking the sortable library to cancel its move on the `stop` - // callback, we basically solve all issues related to reactive updates. A - // comment below provides further details. - onRendered: function() { - var self = this; - if (! Meteor.user() || ! Meteor.user().isBoardMember()) - return; - - var boardComponent = self.componentParent(); - var itemsSelector = '.js-minicard:not(.placeholder, .js-card-composer)'; - var $cards = self.$('.js-minicards'); - $cards.sortable({ - connectWith: '.js-minicards', - tolerance: 'pointer', - appendTo: 'body', - helper: function(evt, item) { - var helper = item.clone(); - if (MultiSelection.isActive()) { - var andNOthers = $cards.find('.js-minicard.is-checked').length - 1; - if (andNOthers > 0) { - helper.append($(Blaze.toHTML(HTML.DIV( - // XXX Super bad class name - {'class': 'and-n-other'}, - // XXX Need to translate - 'and ' + andNOthers + ' other cards.' - )))); - } - } - return helper; - }, - distance: 7, - items: itemsSelector, - scroll: false, - placeholder: 'minicard-wrapper placeholder', - start: function(evt, ui) { - ui.placeholder.height(ui.helper.height()); - EscapeActions.executeUpTo('popup'); - boardComponent.setIsDragging(true); - }, - stop: function(evt, ui) { - // To attribute the new index number, we need to get the DOM element - // of the previous and the following card -- if any. - var prevCardDom = ui.item.prev('.js-minicard').get(0); - var nextCardDom = ui.item.next('.js-minicard').get(0); - var nCards = MultiSelection.isActive() ? MultiSelection.count() : 1; - var sortIndex = Utils.calculateIndex(prevCardDom, nextCardDom, nCards); - var listId = Blaze.getData(ui.item.parents('.list').get(0))._id; - - // Normally the jquery-ui sortable library moves the dragged DOM element - // to its new position, which disrupts Blaze reactive updates mechanism - // (especially when we move the last card of a list, or when multiple - // users move some cards at the same time). To prevent these UX glitches - // we ask sortable to gracefully cancel the move, and to put back the - // DOM in its initial state. The card move is then handled reactively by - // Blaze with the below query. - $cards.sortable('cancel'); - - if (MultiSelection.isActive()) { - Cards.find(MultiSelection.getMongoSelector()).forEach(function(c, i) { - Cards.update(c._id, { - $set: { - listId: listId, - sort: sortIndex.base + i * sortIndex.increment - } - }); - }); - } else { - var cardDomElement = ui.item.get(0); - var cardId = Blaze.getData(cardDomElement)._id; - Cards.update(cardId, { - $set: { - listId: listId, - sort: sortIndex.base - } - }); - } - boardComponent.setIsDragging(false); - } - }); - - // We want to re-run this function any time a card is added. - self.autorun(function() { - var currentBoardId = Tracker.nonreactive(function() { - return Session.get('currentBoard'); - }); - Cards.find({ boardId: currentBoardId }).fetch(); - Tracker.afterFlush(function() { - $cards.find(itemsSelector).droppable({ - hoverClass: 'draggable-hover-card', - accept: '.js-member,.js-label', - drop: function(event, ui) { - var cardId = Blaze.getData(this)._id; - var addToSet; - - if (ui.draggable.hasClass('js-member')) { - var memberId = Blaze.getData(ui.draggable.get(0)).userId; - addToSet = { members: memberId }; - } else { - var labelId = Blaze.getData(ui.draggable.get(0))._id; - addToSet = { labelIds: labelId }; - } - Cards.update(cardId, { $addToSet: addToSet }); - } - }); - }); - }); - } -}).register('list'); diff --git a/client/components/lists/main.styl b/client/components/lists/main.styl deleted file mode 100644 index bfa0f348..00000000 --- a/client/components/lists/main.styl +++ /dev/null @@ -1,110 +0,0 @@ -@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, 13%) - height: 100% - border-left: 1px solid darken(white, 20%) - padding: 0 - - &:first-child - margin-left: 5px - border-left: none - - .card-details + & - border-left: none - - &.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) - - &.placeholder - background-color: rgba(0, 0, 0, .2) - border-color: transparent - box-shadow: none - height: 100px - - &.list-composer, & list-composer - padding: 17px - - form - margin-top: -5px - - .list-name-input - background: rgba(255, 255, 255, .4) - border-color: #aaa - 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 - -.list-header - flex: 0 0 auto - margin: 20px 12px 4px - 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 - position: absolute - top: 0 - right: 0 - -.list-body - flex: 1 - display: flex - overflow-y: auto - padding: 5px 11px - - .minicards - flex: 1 - - form - margin-bottom: 9px - - .ps-scrollbar-y-rail - transform: translateX(2px) - - .open-minicard-composer - border-radius: 2px - color: #8c8c8c - display: block - padding: 7px 10px - position: relative - text-decoration: none - animation: fadeIn 0.3s - - i.fa - margin-right: 7px - - &:hover - background: #fafafa - color: #222 - box-shadow: 0 1px 2px rgba(0,0,0,.2) diff --git a/client/components/lists/menu.jade b/client/components/lists/menu.jade deleted file mode 100644 index 052f064c..00000000 --- a/client/components/lists/menu.jade +++ /dev/null @@ -1,29 +0,0 @@ -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-select-cards {{_ 'list-select-cards'}} - 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'}}") diff --git a/client/components/lists/menu.js b/client/components/lists/menu.js deleted file mode 100644 index dda1270c..00000000 --- a/client/components/lists/menu.js +++ /dev/null @@ -1,52 +0,0 @@ -Template.listActionPopup.events({ - 'click .js-add-card': function() { - var listDom = document.getElementById('js-list-' + this._id); - var listComponent = BlazeComponent.getComponentForElement(listDom); - listComponent.openForm({ position: 'top' }); - Popup.close(); - }, - 'click .js-list-subscribe': function() {}, - 'click .js-select-cards': function() { - var cardIds = Cards.find( - {listId: this._id}, - {fields: { _id: 1 }} - ).map(function(card) { return card._id; }); - MultiSelection.add(cardIds); - Popup.close(); - }, - '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(); - } -}); -- cgit v1.2.3-1-g7c22