From 5b0f7f8aef115b202aaff6bc25bb514426dc2009 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Manelli?= Date: Fri, 16 Mar 2018 22:13:40 -0300 Subject: Fix drag and drop issues when re-enter board --- client/components/boards/boardBody.js | 103 ++++++++++++++++++++++++------- client/components/lists/list.js | 74 ---------------------- client/components/swimlanes/swimlanes.js | 76 +++++++++++++++-------- 3 files changed, 131 insertions(+), 122 deletions(-) (limited to 'client/components') diff --git a/client/components/boards/boardBody.js b/client/components/boards/boardBody.js index 94f9af39..3632da9b 100644 --- a/client/components/boards/boardBody.js +++ b/client/components/boards/boardBody.js @@ -1,12 +1,8 @@ const subManager = new SubsManager(); +const { calculateIndex } = Utils; BlazeComponent.extendComponent({ - openNewListForm() { - this.childComponents('addListForm')[0].open(); - }, onCreated() { - this.draggingActive = new ReactiveVar(false); - this.showOverlay = new ReactiveVar(false); this.isBoardReady = new ReactiveVar(false); // The pattern we use to manually handle data loading is described here: @@ -24,30 +20,70 @@ BlazeComponent.extendComponent({ }); }); }); + }, - this._isDragging = false; - this._lastDragPositionX = 0; + onlyShowCurrentCard() { + return Utils.isMiniScreen() && Session.get('currentCard'); + }, + +}).register('board'); +BlazeComponent.extendComponent({ + onCreated() { + this.showOverlay = new ReactiveVar(false); + this.draggingActive = new ReactiveVar(false); + this._isDragging = false; // Used to set the overlay this.mouseHasEnterCardDetails = false; }, + onRendered() { + const boardComponent = this; + const $swimlanesDom = boardComponent.$('.js-swimlanes'); - // XXX Flow components allow us to avoid creating these two setter methods by - // exposing a public API to modify the component state. We need to investigate - // best practices here. - setIsDragging(bool) { - this.draggingActive.set(bool); - }, + $swimlanesDom.sortable({ + tolerance: 'pointer', + appendTo: '.board-canvas', + helper: 'clone', + handle: '.js-swimlane-header', + items: '.js-swimlane:not(.placeholder)', + placeholder: 'swimlane placeholder', + distance: 7, + start(evt, ui) { + ui.placeholder.height(ui.helper.height()); + EscapeActions.executeUpTo('popup-close'); + boardComponent.setIsDragging(true); + }, + stop(evt, ui) { + // To attribute the new index number, we need to get the DOM element + // of the previous and the following card -- if any. + const prevSwimlaneDom = ui.item.prev('.js-swimlane').get(0); + const nextSwimlaneDom = ui.item.next('.js-swimlane').get(0); + const sortIndex = calculateIndex(prevSwimlaneDom, nextSwimlaneDom, 1); - scrollLeft(position = 0) { - const lists = this.$('.js-lists'); - lists && lists.animate({ - scrollLeft: position, + $swimlanesDom.sortable('cancel'); + const swimlaneDomElement = ui.item.get(0); + const swimlane = Blaze.getData(swimlaneDomElement); + + Swimlanes.update(swimlane._id, { + $set: { + sort: sortIndex.base, + }, + }); + + boardComponent.setIsDragging(false); + }, }); - }, - onlyShowCurrentCard() { - return Utils.isMiniScreen() && Session.get('currentCard'); + function userIsMember() { + return Meteor.user() && Meteor.user().isBoardMember() && !Meteor.user().isCommentOnly(); + } + + // If there is no data in the board (ie, no lists) we autofocus the list + // creation form by clicking on the corresponding element. + const currentBoard = Boards.findOne(Session.get('currentBoard')); + if (userIsMember() && currentBoard.lists().count() === 0) { + boardComponent.openNewListForm(); + } }, isViewSwimlanes() { @@ -62,6 +98,16 @@ BlazeComponent.extendComponent({ return (board.view === 'board-view-lists'); }, + openNewListForm() { + if (this.isViewSwimlanes()) { + this.childComponents('swimlane')[0] + .childComponents('addListAndSwimlaneForm')[0].open(); + } else if (this.isViewLists()) { + this.childComponents('listsGroup')[0] + .childComponents('addListForm')[0].open(); + } + }, + events() { return [{ // XXX The board-overlay div should probably be moved to the parent @@ -78,4 +124,19 @@ BlazeComponent.extendComponent({ }, }]; }, -}).register('board'); + + // XXX Flow components allow us to avoid creating these two setter methods by + // exposing a public API to modify the component state. We need to investigate + // best practices here. + setIsDragging(bool) { + this.draggingActive.set(bool); + }, + + scrollLeft(position = 0) { + const lists = this.$('.js-lists'); + lists && lists.animate({ + scrollLeft: position, + }); + }, + +}).register('boardBody'); diff --git a/client/components/lists/list.js b/client/components/lists/list.js index 081b1e50..38a87674 100644 --- a/client/components/lists/list.js +++ b/client/components/lists/list.js @@ -19,85 +19,11 @@ BlazeComponent.extendComponent({ // comment below provides further details. onRendered() { const boardComponent = this.parentComponent().parentComponent(); - const $listsDom = boardComponent.$('.js-lists'); - - if (!Session.get('currentCard')) { - boardComponent.scrollLeft(); - } - - // We want to animate the card details window closing. We rely on CSS - // transition for the actual animation. - $listsDom._uihooks = { - removeElement(node) { - const removeNode = _.once(() => { - node.parentNode.removeChild(node); - }); - if ($(node).hasClass('js-card-details')) { - $(node).css({ - flexBasis: 0, - padding: 0, - }); - $listsDom.one(CSSEvents.transitionend, removeNode); - } else { - removeNode(); - } - }, - }; - - $listsDom.sortable({ - tolerance: 'pointer', - helper: 'clone', - handle: '.js-list-header', - items: '.js-list:not(.js-list-composer)', - placeholder: 'list placeholder', - distance: 7, - start(evt, ui) { - ui.placeholder.height(ui.helper.height()); - EscapeActions.executeUpTo('popup-close'); - boardComponent.setIsDragging(true); - }, - stop(evt, ui) { - // To attribute the new index number, we need to get the DOM element - // of the previous and the following card -- if any. - const prevListDom = ui.item.prev('.js-list').get(0); - const nextListDom = ui.item.next('.js-list').get(0); - const sortIndex = calculateIndex(prevListDom, nextListDom, 1); - - $listsDom.sortable('cancel'); - const listDomElement = ui.item.get(0); - const list = Blaze.getData(listDomElement); - - Lists.update(list._id, { - $set: { - sort: sortIndex.base, - }, - }); - - boardComponent.setIsDragging(false); - }, - }); function userIsMember() { return Meteor.user() && Meteor.user().isBoardMember() && !Meteor.user().isCommentOnly(); } - // Disable drag-dropping while in multi-selection mode, or if the current user - // is not a board member - boardComponent.autorun(() => { - const $listDom = $listsDom; - if ($listDom.data('sortable')) { - $listsDom.sortable('option', 'disabled', - MultiSelection.isActive() || !userIsMember()); - } - }); - - // If there is no data in the board (ie, no lists) we autofocus the list - // creation form by clicking on the corresponding element. - const currentBoard = Boards.findOne(Session.get('currentBoard')); - if (userIsMember() && currentBoard.lists().count() === 0) { - boardComponent.openNewListForm(); - } - const itemsSelector = '.js-minicard:not(.placeholder, .js-card-composer)'; const $cards = this.$('.js-minicards'); $cards.sortable({ diff --git a/client/components/swimlanes/swimlanes.js b/client/components/swimlanes/swimlanes.js index dacb487e..3dd7f208 100644 --- a/client/components/swimlanes/swimlanes.js +++ b/client/components/swimlanes/swimlanes.js @@ -3,15 +3,37 @@ const { calculateIndex } = Utils; BlazeComponent.extendComponent({ onRendered() { const boardComponent = this.parentComponent(); - const $swimlanesDom = boardComponent.$('.js-swimlanes'); + const $listsDom = this.$('.js-lists'); + + if (!Session.get('currentCard')) { + boardComponent.scrollLeft(); + } + + // We want to animate the card details window closing. We rely on CSS + // transition for the actual animation. + $listsDom._uihooks = { + removeElement(node) { + const removeNode = _.once(() => { + node.parentNode.removeChild(node); + }); + if ($(node).hasClass('js-card-details')) { + $(node).css({ + flexBasis: 0, + padding: 0, + }); + $listsDom.one(CSSEvents.transitionend, removeNode); + } else { + removeNode(); + } + }, + }; - $swimlanesDom.sortable({ + $listsDom.sortable({ tolerance: 'pointer', - appendTo: '.board-canvas', helper: 'clone', - handle: '.js-swimlane-header', - items: '.js-swimlane:not(.placeholder)', - placeholder: 'swimlane placeholder', + handle: '.js-list-header', + items: '.js-list:not(.js-list-composer)', + placeholder: 'list placeholder', distance: 7, start(evt, ui) { ui.placeholder.height(ui.helper.height()); @@ -21,15 +43,15 @@ BlazeComponent.extendComponent({ stop(evt, ui) { // To attribute the new index number, we need to get the DOM element // of the previous and the following card -- if any. - const prevSwimlaneDom = ui.item.prev('.js-swimlane').get(0); - const nextSwimlaneDom = ui.item.next('.js-swimlane').get(0); - const sortIndex = calculateIndex(prevSwimlaneDom, nextSwimlaneDom, 1); + const prevListDom = ui.item.prev('.js-list').get(0); + const nextListDom = ui.item.next('.js-list').get(0); + const sortIndex = calculateIndex(prevListDom, nextListDom, 1); - $swimlanesDom.sortable('cancel'); - const swimlaneDomElement = ui.item.get(0); - const swimlane = Blaze.getData(swimlaneDomElement); + $listsDom.sortable('cancel'); + const listDomElement = ui.item.get(0); + const list = Blaze.getData(listDomElement); - Swimlanes.update(swimlane._id, { + Lists.update(list._id, { $set: { sort: sortIndex.base, }, @@ -38,6 +60,20 @@ BlazeComponent.extendComponent({ boardComponent.setIsDragging(false); }, }); + + function userIsMember() { + return Meteor.user() && Meteor.user().isBoardMember() && !Meteor.user().isCommentOnly(); + } + + // Disable drag-dropping while in multi-selection mode, or if the current user + // is not a board member + boardComponent.autorun(() => { + const $listDom = $listsDom; + if ($listDom.data('sortable')) { + $listsDom.sortable('option', 'disabled', + MultiSelection.isActive() || !userIsMember()); + } + }); }, onCreated() { this.draggingActive = new ReactiveVar(false); @@ -50,20 +86,6 @@ BlazeComponent.extendComponent({ return this._id; }, - // XXX Flow components allow us to avoid creating these two setter methods by - // exposing a public API to modify the component state. We need to investigate - // best practices here. - setIsDragging(bool) { - this.draggingActive.set(bool); - }, - - scrollLeft(position = 0) { - const lists = this.$('.js-lists'); - lists && lists.animate({ - scrollLeft: position, - }); - }, - currentCardIsInThisList(listId, swimlaneId) { const currentCard = Cards.findOne(Session.get('currentCard')); const currentBoardId = Session.get('currentBoard'); -- cgit v1.2.3-1-g7c22