diff options
author | Thiago Fernando <thiagofernando@outlook.com> | 2019-05-10 14:54:25 -0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-05-10 14:54:25 -0300 |
commit | ce0473480bab3fc621d4baecfff0f413e21b5e2c (patch) | |
tree | 06d724b4f80885bdd13137f7977d7a914cca0138 /client/components/lists/listBody.js | |
parent | c43508cacbd64357409a3de114db9dab2ae59a9d (diff) | |
parent | 7ff4067e88ed59686c86d81447fa2ce550032034 (diff) | |
download | wekan-ce0473480bab3fc621d4baecfff0f413e21b5e2c.tar.gz wekan-ce0473480bab3fc621d4baecfff0f413e21b5e2c.tar.bz2 wekan-ce0473480bab3fc621d4baecfff0f413e21b5e2c.zip |
Merge pull request #1 from wekan/devel
ldap changes
Diffstat (limited to 'client/components/lists/listBody.js')
-rw-r--r-- | client/components/lists/listBody.js | 430 |
1 files changed, 414 insertions, 16 deletions
diff --git a/client/components/lists/listBody.js b/client/components/lists/listBody.js index 52f34fab..a5ccba3f 100644 --- a/client/components/lists/listBody.js +++ b/client/components/lists/listBody.js @@ -1,4 +1,12 @@ +const subManager = new SubsManager(); +const InfiniteScrollIter = 10; + BlazeComponent.extendComponent({ + onCreated() { + // for infinite scrolling + this.cardlimit = new ReactiveVar(InfiniteScrollIter); + }, + mixins() { return [Mixins.PerfectScrollbar]; }, @@ -35,25 +43,59 @@ BlazeComponent.extendComponent({ const members = formComponent.members.get(); const labelIds = formComponent.labels.get(); + const customFields = formComponent.customFields.get(); - const boardId = this.data().board()._id; + const board = this.data().board(); + let linkedId = ''; let swimlaneId = ''; - const boardView = Meteor.user().profile.boardView; - if (boardView === 'board-view-swimlanes') - swimlaneId = this.parentComponent().parentComponent().data()._id; - else if (boardView === 'board-view-lists') - swimlaneId = Swimlanes.findOne({boardId})._id; - + const boardView = (Meteor.user().profile || {}).boardView; + let cardType = 'cardType-card'; if (title) { + if (board.isTemplatesBoard()) { + swimlaneId = this.parentComponent().parentComponent().data()._id; // Always swimlanes view + const swimlane = Swimlanes.findOne(swimlaneId); + // If this is the card templates swimlane, insert a card template + if (swimlane.isCardTemplatesSwimlane()) + cardType = 'template-card'; + // If this is the board templates swimlane, insert a board template and a linked card + else if (swimlane.isBoardTemplatesSwimlane()) { + linkedId = Boards.insert({ + title, + permission: 'private', + type: 'template-board', + }); + Swimlanes.insert({ + title: TAPi18n.__('default'), + boardId: linkedId, + }); + cardType = 'cardType-linkedBoard'; + } + } else if (boardView === 'board-view-swimlanes') + swimlaneId = this.parentComponent().parentComponent().data()._id; + else if ((boardView === 'board-view-lists') || (boardView === 'board-view-cal') || !boardView) + swimlaneId = board.getDefaultSwimline()._id; + const _id = Cards.insert({ title, members, labelIds, + customFields, listId: this.data()._id, - boardId: this.data().board()._id, + boardId: board._id, sort: sortIndex, swimlaneId, + type: cardType, + linkedId, }); + + // if the displayed card count is less than the total cards in the list, + // we need to increment the displayed card count to prevent the spinner + // to appear + const cardCount = this.data().cards(this.idOrNull(swimlaneId)).count(); + if (this.cardlimit.get() < cardCount) { + this.cardlimit.set(this.cardlimit.get() + InfiniteScrollIter); + } + // 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. @@ -85,9 +127,9 @@ BlazeComponent.extendComponent({ const methodName = evt.shiftKey ? 'toggleRange' : 'toggle'; 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. + // 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(); @@ -107,11 +149,31 @@ BlazeComponent.extendComponent({ idOrNull(swimlaneId) { const currentUser = Meteor.user(); - if (currentUser.profile.boardView === 'board-view-swimlanes') + if ((currentUser.profile || {}).boardView === 'board-view-swimlanes' || + this.data().board().isTemplatesBoard()) return swimlaneId; return undefined; }, + cardsWithLimit(swimlaneId) { + const limit = this.cardlimit.get(); + const selector = { + listId: this.currentData()._id, + archived: false, + }; + if (swimlaneId) + selector.swimlaneId = swimlaneId; + return Cards.find(Filter.mongoSelector(selector), { + sort: ['sort'], + limit, + }); + }, + + showSpinner(swimlaneId) { + const list = Template.currentData(); + return list.cards(swimlaneId).count() > this.cardlimit.get(); + }, + canSeeAddCard() { return !this.reachedWipLimit() && Meteor.user() && Meteor.user().isBoardMember() && !Meteor.user().isCommentOnly(); }, @@ -146,11 +208,21 @@ BlazeComponent.extendComponent({ onCreated() { this.labels = new ReactiveVar([]); this.members = new ReactiveVar([]); + this.customFields = new ReactiveVar([]); + + const currentBoardId = Session.get('currentBoard'); + arr = []; + _.forEach(Boards.findOne(currentBoardId).customFields().fetch(), function(field){ + if(field.automaticallyOnCard) + arr.push({_id: field._id, value: null}); + }); + this.customFields.set(arr); }, reset() { this.labels.set([]); this.members.set([]); + this.customFields.set([]); }, getLabels() { @@ -162,7 +234,7 @@ BlazeComponent.extendComponent({ pressKey(evt) { // Pressing Enter should submit the card - if (evt.keyCode === 13) { + if (evt.keyCode === 13 && !evt.shiftKey) { evt.preventDefault(); const $form = $(evt.currentTarget).closest('form'); // XXX For some reason $form.submit() does not work (it's probably a bug @@ -171,8 +243,8 @@ BlazeComponent.extendComponent({ // 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 + // 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(); const isReverse = evt.shiftKey; @@ -193,6 +265,9 @@ BlazeComponent.extendComponent({ events() { return [{ keydown: this.pressKey, + 'click .js-link': Popup.open('linkCard'), + 'click .js-search': Popup.open('searchElement'), + 'click .js-card-template': Popup.open('searchElement'), }]; }, @@ -230,7 +305,7 @@ BlazeComponent.extendComponent({ const currentBoard = Boards.findOne(Session.get('currentBoard')); callback($.map(currentBoard.labels, (label) => { if (label.name.indexOf(term) > -1 || - label.color.indexOf(term) > -1) { + label.color.indexOf(term) > -1) { return label; } return null; @@ -264,3 +339,326 @@ BlazeComponent.extendComponent({ }); }, }).register('addCardForm'); + +BlazeComponent.extendComponent({ + onCreated() { + this.selectedBoardId = new ReactiveVar(''); + 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' || !boardView) + this.swimlaneId = Swimlanes.findOne({boardId: this.boardId})._id; + }, + + boards() { + const boards = Boards.find({ + archived: false, + 'members.userId': Meteor.userId(), + _id: {$ne: Session.get('currentBoard')}, + type: 'board', + }, { + sort: ['title'], + }); + return boards; + }, + + swimlanes() { + if (!this.selectedBoardId.get()) { + return []; + } + const swimlanes = Swimlanes.find({boardId: this.selectedBoardId.get()}); + if (swimlanes.count()) + this.selectedSwimlaneId.set(swimlanes.fetch()[0]._id); + return swimlanes; + }, + + lists() { + if (!this.selectedBoardId.get()) { + return []; + } + const lists = Lists.find({boardId: this.selectedBoardId.get()}); + if (lists.count()) + this.selectedListId.set(lists.fetch()[0]._id); + return lists; + }, + + cards() { + if (!this.board) { + return []; + } + const ownCardsIds = this.board.cards().map((card) => { return card.linkedId || card._id; }); + return Cards.find({ + boardId: this.selectedBoardId.get(), + swimlaneId: this.selectedSwimlaneId.get(), + listId: this.selectedListId.get(), + archived: false, + linkedId: {$nin: ownCardsIds}, + _id: {$nin: ownCardsIds}, + type: {$nin: ['template-card']}, + }); + }, + + events() { + return [{ + 'change .js-select-boards'(evt) { + subManager.subscribe('board', $(evt.currentTarget).val()); + this.selectedBoardId.set($(evt.currentTarget).val()); + }, + '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 linkedId = $('.js-select-cards option:selected').val(); + if (!linkedId) { + Popup.close(); + return; + } + 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, + }); + Filter.addException(_id); + Popup.close(); + }, + 'click .js-link-board' (evt) { + //LINK BOARD + evt.stopPropagation(); + evt.preventDefault(); + const impBoardId = $('.js-select-boards option:selected').val(); + if (!impBoardId || Cards.findOne({linkedId: impBoardId, archived: false})) { + Popup.close(); + return; + } + 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() { + this.isCardTemplateSearch = $(Popup._getTopStack().openerElement).hasClass('js-card-template'); + this.isListTemplateSearch = $(Popup._getTopStack().openerElement).hasClass('js-list-template'); + this.isSwimlaneTemplateSearch = $(Popup._getTopStack().openerElement).hasClass('js-open-add-swimlane-menu'); + this.isBoardTemplateSearch = $(Popup._getTopStack().openerElement).hasClass('js-add-board'); + this.isTemplateSearch = this.isCardTemplateSearch || + this.isListTemplateSearch || + this.isSwimlaneTemplateSearch || + this.isBoardTemplateSearch; + let board = {}; + if (this.isTemplateSearch) { + board = Boards.findOne((Meteor.user().profile || {}).templatesBoardId); + } else { + // Prefetch first non-current board id + board = Boards.findOne({ + archived: false, + 'members.userId': Meteor.userId(), + _id: {$nin: [Session.get('currentBoard'), (Meteor.user().profile || {}).templatesBoardId]}, + }); + } + if (!board) { + Popup.close(); + return; + } + const boardId = board._id; + // Subscribe to this board + subManager.subscribe('board', boardId); + this.selectedBoardId = new ReactiveVar(boardId); + + if (!this.isBoardTemplateSearch) { + this.boardId = Session.get('currentBoard'); + // In order to get current board info + subManager.subscribe('board', this.boardId); + this.swimlaneId = ''; + // Swimlane where to insert card + const swimlane = $(Popup._getTopStack().openerElement).parents('.js-swimlane'); + if ((Meteor.user().profile || {}).boardView === 'board-view-swimlanes') + this.swimlaneId = Blaze.getData(swimlane[0])._id; + else + this.swimlaneId = Swimlanes.findOne({boardId: this.boardId})._id; + // List where to insert card + const list = $(Popup._getTopStack().openerElement).closest('.js-list'); + this.listId = Blaze.getData(list[0])._id; + } + this.term = new ReactiveVar(''); + }, + + boards() { + const boards = Boards.find({ + archived: false, + 'members.userId': Meteor.userId(), + _id: {$ne: Session.get('currentBoard')}, + type: 'board', + }, { + sort: ['title'], + }); + return boards; + }, + + results() { + if (!this.selectedBoardId) { + return []; + } + const board = Boards.findOne(this.selectedBoardId.get()); + if (!this.isTemplateSearch || this.isCardTemplateSearch) { + return board.searchCards(this.term.get(), false); + } else if (this.isListTemplateSearch) { + return board.searchLists(this.term.get()); + } else if (this.isSwimlaneTemplateSearch) { + return board.searchSwimlanes(this.term.get()); + } else if (this.isBoardTemplateSearch) { + const boards = board.searchBoards(this.term.get()); + boards.forEach((board) => { + subManager.subscribe('board', board.linkedId); + }); + return boards; + } else { + return []; + } + }, + + events() { + return [{ + 'change .js-select-boards'(evt) { + subManager.subscribe('board', $(evt.currentTarget).val()); + this.selectedBoardId.set($(evt.currentTarget).val()); + }, + 'submit .js-search-term-form'(evt) { + evt.preventDefault(); + this.term.set(evt.target.searchTerm.value); + }, + 'click .js-minicard'(evt) { + // 0. Common + const title = $('.js-element-title').val().trim(); + if (!title) + return; + const element = Blaze.getData(evt.currentTarget); + element.title = title; + let _id = ''; + if (!this.isTemplateSearch || this.isCardTemplateSearch) { + // Card insertion + // 1. Common + element.sort = Lists.findOne(this.listId).cards().count(); + // 1.A From template + if (this.isTemplateSearch) { + element.type = 'cardType-card'; + element.linkedId = ''; + _id = element.copy(this.boardId, this.swimlaneId, this.listId); + // 1.B Linked card + } else { + delete element._id; + element.type = 'cardType-linkedCard'; + element.linkedId = element.linkedId || element._id; + _id = Cards.insert(element); + } + Filter.addException(_id); + // List insertion + } else if (this.isListTemplateSearch) { + element.sort = Swimlanes.findOne(this.swimlaneId).lists().count(); + element.type = 'list'; + _id = element.copy(this.boardId, this.swimlaneId); + } else if (this.isSwimlaneTemplateSearch) { + element.sort = Boards.findOne(this.boardId).swimlanes().count(); + element.type = 'swimlalne'; + _id = element.copy(this.boardId); + } else if (this.isBoardTemplateSearch) { + board = Boards.findOne(element.linkedId); + board.sort = Boards.find({archived: false}).count(); + board.type = 'board'; + board.title = element.title; + delete board.slug; + _id = board.copy(); + } + Popup.close(); + }, + }]; + }, +}).register('searchElementPopup'); + +BlazeComponent.extendComponent({ + onCreated() { + this.cardlimit = this.parentComponent().cardlimit; + + this.listId = this.parentComponent().data()._id; + this.swimlaneId = ''; + + const boardView = (Meteor.user().profile || {}).boardView; + if (boardView === 'board-view-swimlanes') + this.swimlaneId = this.parentComponent().parentComponent().parentComponent().data()._id; + }, + + onRendered() { + this.spinner = this.find('.sk-spinner-list'); + this.container = this.$(this.spinner).parents('.js-perfect-scrollbar')[0]; + + $(this.container).on(`scroll.spinner_${this.swimlaneId}_${this.listId}`, () => this.updateList()); + $(window).on(`resize.spinner_${this.swimlaneId}_${this.listId}`, () => this.updateList()); + + this.updateList(); + }, + + onDestroyed() { + $(this.container).off(`scroll.spinner_${this.swimlaneId}_${this.listId}`); + $(window).off(`resize.spinner_${this.swimlaneId}_${this.listId}`); + }, + + updateList() { + if (this.spinnerInView()) { + this.cardlimit.set(this.cardlimit.get() + InfiniteScrollIter); + window.requestIdleCallback(() => this.updateList()); + } + }, + + spinnerInView() { + const parentViewHeight = this.container.clientHeight; + const bottomViewPosition = this.container.scrollTop + parentViewHeight; + + const threshold = this.spinner.offsetTop; + + // spinner deleted + if (!this.spinner.offsetTop) { + return false; + } + + return bottomViewPosition > threshold; + }, + +}).register('spinnerList'); |