summaryrefslogtreecommitdiffstats
path: root/client/components/lists
diff options
context:
space:
mode:
Diffstat (limited to 'client/components/lists')
-rw-r--r--client/components/lists/list.styl11
-rw-r--r--client/components/lists/listBody.jade54
-rw-r--r--client/components/lists/listBody.js201
3 files changed, 265 insertions, 1 deletions
diff --git a/client/components/lists/list.styl b/client/components/lists/list.styl
index fa32ff6d..72cb19f4 100644
--- a/client/components/lists/list.styl
+++ b/client/components/lists/list.styl
@@ -187,3 +187,14 @@
padding: 7px
top: -@padding
right: 17px
+
+.link-board-wrapper
+ display: flex
+ align-items: baseline
+
+ .js-link-board
+ margin-left: 15px
+
+.search-card-results
+ max-height: 250px
+ overflow: hidden
diff --git a/client/components/lists/listBody.jade b/client/components/lists/listBody.jade
index 32c6b278..8069717e 100644
--- a/client/components/lists/listBody.jade
+++ b/client/components/lists/listBody.jade
@@ -34,8 +34,60 @@ template(name="addCardForm")
.add-controls.clearfix
button.primary.confirm(type="submit") {{_ 'add'}}
- a.fa.fa-times-thin.js-close-inlined-form
+ span.quiet
+ | {{_ 'or'}}
+ a.js-link {{_ 'link'}}
+ span.quiet
+ |  
+ | /
+ a.js-search {{_ 'search'}}
template(name="autocompleteLabelLine")
.minicard-label(class="card-label-{{colorName}}" title=labelName)
span(class="{{#if hasNoName}}quiet{{/if}}")= labelName
+
+template(name="linkCardPopup")
+ label {{_ 'boards'}}:
+ .link-board-wrapper
+ select.js-select-boards
+ each boards
+ if $eq _id currentBoard._id
+ option(value="{{_id}}" selected) {{_ 'current'}}
+ else
+ option(value="{{_id}}") {{title}}
+ input.primary.confirm.js-link-board(type="button" value="{{_ 'link'}}")
+
+ label {{_ 'swimlanes'}}:
+ select.js-select-swimlanes
+ each swimlanes
+ option(value="{{_id}}") {{title}}
+
+ label {{_ 'lists'}}:
+ select.js-select-lists
+ each lists
+ option(value="{{_id}}") {{title}}
+
+ label {{_ 'cards'}}:
+ select.js-select-cards
+ each cards
+ option(value="{{_id}}") {{title}}
+
+ .edit-controls.clearfix
+ input.primary.confirm.js-done(type="button" value="{{_ 'link'}}")
+
+template(name="searchCardPopup")
+ label {{_ 'boards'}}:
+ .link-board-wrapper
+ select.js-select-boards
+ each boards
+ if $eq _id currentBoard._id
+ option(value="{{_id}}" selected) {{_ 'current'}}
+ else
+ option(value="{{_id}}") {{title}}
+ form.js-search-term-form
+ input(type="text" name="searchTerm" placeholder="{{_ 'search-example'}}" autofocus)
+ .list-body.js-perfect-scrollbar.search-card-results
+ .minicards.clearfix.js-minicards
+ each results
+ a.minicard-wrapper.js-minicard
+ +minicard(this)
diff --git a/client/components/lists/listBody.js b/client/components/lists/listBody.js
index 0a10f7d5..83592a64 100644
--- a/client/components/lists/listBody.js
+++ b/client/components/lists/listBody.js
@@ -1,3 +1,5 @@
+const subManager = new SubsManager();
+
BlazeComponent.extendComponent({
mixins() {
return [Mixins.PerfectScrollbar];
@@ -55,6 +57,7 @@ BlazeComponent.extendComponent({
boardId: boardId._id,
sort: sortIndex,
swimlaneId,
+ type: 'cardType-card',
});
// 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
@@ -197,6 +200,8 @@ BlazeComponent.extendComponent({
events() {
return [{
keydown: this.pressKey,
+ 'click .js-link': Popup.open('linkCard'),
+ 'click .js-search': Popup.open('searchCard'),
}];
},
@@ -268,3 +273,199 @@ BlazeComponent.extendComponent({
});
},
}).register('addCardForm');
+
+BlazeComponent.extendComponent({
+ onCreated() {
+ // Prefetch first non-current board id
+ const boardId = Boards.findOne({
+ archived: false,
+ 'members.userId': Meteor.userId(),
+ _id: {$ne: Session.get('currentBoard')},
+ }, {
+ sort: ['title'],
+ })._id;
+ // Subscribe to this board
+ subManager.subscribe('board', boardId);
+ this.selectedBoardId = new ReactiveVar(boardId);
+ this.selectedSwimlaneId = new ReactiveVar('');
+ this.selectedListId = new ReactiveVar('');
+
+ this.boardId = Session.get('currentBoard');
+ // In order to get current board info
+ subManager.subscribe('board', this.boardId);
+ this.board = Boards.findOne(this.boardId);
+ // List where to insert card
+ const list = $(Popup._getTopStack().openerElement).closest('.js-list');
+ this.listId = Blaze.getData(list[0])._id;
+ // Swimlane where to insert card
+ const swimlane = $(Popup._getTopStack().openerElement).closest('.js-swimlane');
+ this.swimlaneId = '';
+ const boardView = Meteor.user().profile.boardView;
+ if (boardView === 'board-view-swimlanes')
+ this.swimlaneId = Blaze.getData(swimlane[0])._id;
+ else if (boardView === 'board-view-lists')
+ this.swimlaneId = Swimlanes.findOne({boardId: this.boardId})._id;
+ },
+
+ boards() {
+ const boards = Boards.find({
+ archived: false,
+ 'members.userId': Meteor.userId(),
+ _id: {$ne: Session.get('currentBoard')},
+ }, {
+ sort: ['title'],
+ });
+ return boards;
+ },
+
+ swimlanes() {
+ const swimlanes = Swimlanes.find({boardId: this.selectedBoardId.get()});
+ if (swimlanes.count())
+ this.selectedSwimlaneId.set(swimlanes.fetch()[0]._id);
+ return swimlanes;
+ },
+
+ lists() {
+ const lists = Lists.find({boardId: this.selectedBoardId.get()});
+ if (lists.count())
+ this.selectedListId.set(lists.fetch()[0]._id);
+ return lists;
+ },
+
+ cards() {
+ return Cards.find({
+ boardId: this.selectedBoardId.get(),
+ swimlaneId: this.selectedSwimlaneId.get(),
+ listId: this.selectedListId.get(),
+ archived: false,
+ linkedId: null,
+ _id: {$nin: this.board.cards().map((card) => { return card.linkedId || card._id; })},
+ });
+ },
+
+ events() {
+ return [{
+ 'change .js-select-boards'(evt) {
+ this.selectedBoardId.set($(evt.currentTarget).val());
+ subManager.subscribe('board', this.selectedBoardId.get());
+ },
+ 'change .js-select-swimlanes'(evt) {
+ this.selectedSwimlaneId.set($(evt.currentTarget).val());
+ },
+ 'change .js-select-lists'(evt) {
+ this.selectedListId.set($(evt.currentTarget).val());
+ },
+ 'click .js-done' (evt) {
+ // LINK CARD
+ evt.stopPropagation();
+ evt.preventDefault();
+ const _id = Cards.insert({
+ title: $('.js-select-cards option:selected').text(), //dummy
+ listId: this.listId,
+ swimlaneId: this.swimlaneId,
+ boardId: this.boardId,
+ sort: Lists.findOne(this.listId).cards().count(),
+ type: 'cardType-linkedCard',
+ linkedId: $('.js-select-cards option:selected').val(),
+ });
+ Filter.addException(_id);
+ Popup.close();
+ },
+ 'click .js-link-board' (evt) {
+ //LINK BOARD
+ evt.stopPropagation();
+ evt.preventDefault();
+ const impBoardId = $('.js-select-boards option:selected').val();
+ const _id = Cards.insert({
+ title: $('.js-select-boards option:selected').text(), //dummy
+ listId: this.listId,
+ swimlaneId: this.swimlaneId,
+ boardId: this.boardId,
+ sort: Lists.findOne(this.listId).cards().count(),
+ type: 'cardType-linkedBoard',
+ linkedId: impBoardId,
+ });
+ Filter.addException(_id);
+ Popup.close();
+ },
+ }];
+ },
+}).register('linkCardPopup');
+
+BlazeComponent.extendComponent({
+ mixins() {
+ return [Mixins.PerfectScrollbar];
+ },
+
+ onCreated() {
+ // Prefetch first non-current board id
+ const boardId = Boards.findOne({
+ archived: false,
+ 'members.userId': Meteor.userId(),
+ _id: {$ne: Session.get('currentBoard')},
+ })._id;
+ // Subscribe to this board
+ subManager.subscribe('board', boardId);
+ this.selectedBoardId = new ReactiveVar(boardId);
+
+ this.boardId = Session.get('currentBoard');
+ // In order to get current board info
+ subManager.subscribe('board', this.boardId);
+ const board = Boards.findOne(this.boardId);
+ // List where to insert card
+ const list = $(Popup._getTopStack().openerElement).closest('.js-list');
+ this.listId = Blaze.getData(list[0])._id;
+ // Swimlane where to insert card
+ const swimlane = $(Popup._getTopStack().openerElement).closest('.js-swimlane');
+ this.swimlaneId = '';
+ if (board.view === 'board-view-swimlanes')
+ this.swimlaneId = Blaze.getData(swimlane[0])._id;
+ else
+ this.swimlaneId = Swimlanes.findOne({boardId: this.boardId})._id;
+ this.term = new ReactiveVar('');
+ },
+
+ boards() {
+ const boards = Boards.find({
+ archived: false,
+ 'members.userId': Meteor.userId(),
+ _id: {$ne: Session.get('currentBoard')},
+ }, {
+ sort: ['title'],
+ });
+ return boards;
+ },
+
+ results() {
+ const board = Boards.findOne(this.selectedBoardId.get());
+ return board.searchCards(this.term.get(), true);
+ },
+
+ events() {
+ return [{
+ 'change .js-select-boards'(evt) {
+ this.selectedBoardId.set($(evt.currentTarget).val());
+ subManager.subscribe('board', this.selectedBoardId.get());
+ },
+ 'submit .js-search-term-form'(evt) {
+ evt.preventDefault();
+ this.term.set(evt.target.searchTerm.value);
+ },
+ 'click .js-minicard'(evt) {
+ // LINK CARD
+ const card = Blaze.getData(evt.currentTarget);
+ const _id = Cards.insert({
+ title: card.title, //dummy
+ listId: this.listId,
+ swimlaneId: this.swimlaneId,
+ boardId: this.boardId,
+ sort: Lists.findOne(this.listId).cards().count(),
+ type: 'cardType-linkedCard',
+ linkedId: card._id,
+ });
+ Filter.addException(_id);
+ Popup.close();
+ },
+ }];
+ },
+}).register('searchCardPopup');