Skip to content

Commit

Permalink
LDBR-4.21: Drag and Drop (#46)
Browse files Browse the repository at this point in the history
* LDBR-4.21: сделать простой DnD

* LDBR-4.21: Исправить прохождение CI
  • Loading branch information
DPeshkoff authored Dec 16, 2021
1 parent 72d92ac commit 00be196
Show file tree
Hide file tree
Showing 7 changed files with 193 additions and 17 deletions.
4 changes: 3 additions & 1 deletion src/actions/cardlist.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,15 @@ export const cardListActions = {
* Обновляет список карточек
* @param {Number} position позиция на доске
* @param {String} title заголовок
* @param {Number} clid айди колонки
*/
updateCardList(position, title) {
updateCardList(position, title, clid = null) {
Dispatcher.dispatch({
actionName: CardListActionTypes.CARD_LIST_UPDATE_SUBMIT,
data: {
cardList_name: title,
pos: position,
clid,
},
});
},
Expand Down
2 changes: 1 addition & 1 deletion src/components/Card/Card.hbs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<div class="card editCard" data-id="{{cid}}">
<div class="card editCard dragCard" data-id="{{cid}}" draggable="true">
<div class="card__tags-container" data-id="{{cid}}">
{{#each tags}}
<div class="card-tag tag-colors__{{this.color.color_name}}" data-id="{{cid}}"></div>
Expand Down
4 changes: 2 additions & 2 deletions src/components/CardList/CardList.hbs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
<div class="column">
<div class="column dragCardList" data-id="{{clid}}" draggable="true">
<div class="column__header">
<div class="column__title">{{cardList_name}}</div>
<span class="material-icon-add addCardToCardList" data-id="{{clid}}"></span>
<span class="material-icon-edit editCardList" data-id="{{clid}}"></span>
<span class="material-icon-delete deleteCardList" data-id="{{clid}}"></span>
</div>
<div class="horizontal-line"></div>
<div class="column__content custom-scroll" data-id="{{clid}}">
<div class="column__content custom-scroll cardDropZone" data-id="{{clid}}">
{{#each _cards}}
{{{this}}}
{{/each}}
Expand Down
2 changes: 1 addition & 1 deletion src/popups/Card/CardPopUp.js
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ export default class CardPopUp extends BaseComponent {
_onSave(event) {
event.preventDefault();
const data = {
position: parseInt(this._elements.positionSelect.value, 10),
pos: parseInt(this._elements.positionSelect.value, 10),
card_name: this._elements.card_name.value,
description: this._elements.description.value,
cid: this.context.cid,
Expand Down
42 changes: 31 additions & 11 deletions src/stores/BoardStore/BoardStore.js
Original file line number Diff line number Diff line change
Expand Up @@ -803,8 +803,10 @@ class BoardStore extends BaseStore {

let payload;

const clid = (data.clid? data.clid : this._storage.get('cardlist-popup').clid);

try {
payload = await Network._updateCardList(data, this._storage.get('cardlist-popup').clid);
payload = await Network._updateCardList(data, clid);
} catch (error) {
console.log('Unable to connect to backend, reason: ', error);
return;
Expand All @@ -814,21 +816,26 @@ class BoardStore extends BaseStore {
case HttpStatusCodes.Ok:
this._storage.get('cardlist-popup').visible = false;

const cardList = this._getCardListById(this._storage.get('cardlist-popup').clid);
const cardList = this._getCardListById(clid);
const bound = data.pos > cardList.pos ?
{left: cardList.pos, right: data.pos, increment: -1} :
{left: data.pos - 1, right: cardList.pos - 1, increment: 1};

// Обновим позиции списков в storage
const cardLists = this._storage.get('card_lists');

if (data.pos !== cardList.pos) {
const cardListIndex = cardLists.indexOf(cardList);
cardLists.splice(data.pos - 1, 0, cardLists.splice(cardListIndex, 1)[0]);
}

for (let index = bound.left; index < bound.right; index += 1) {
cardLists[index].pos += bound.increment;
}

// Обновим cardList:
cardList.cardList_name = data.cardList_name;
cardList.pos = data.pos;
cardList.pos = cardLists.indexOf(cardList) + 1;

// Переупорядочим списки
cardLists.sort((lhs, rhs) => {
Expand Down Expand Up @@ -1124,18 +1131,19 @@ class BoardStore extends BaseStore {
let payload;

const _data = {
position: data.position,
pos: data.pos,
cid: this._storage.get('card-popup').cid,
clid: this._storage.get('card-popup').clid,
cid: (data.cid? data.cid : this._storage.get('card-popup').cid),
clid: (data.clid? data.clid : this._storage.get('card-popup').clid),
card_name: data.card_name,
description: data.description,
bid: this._storage.get('card-popup').bid,
bid: (data.bid? data.bid : this._storage.get('card-popup').bid),
deadline: data.deadline,
deadline_check: data.deadline_check,
};

try {
payload = await Network._updateCard(_data, this._storage.get('card-popup').cid);
payload = await Network._updateCard(_data, _data.cid);
} catch (error) {
console.log('Unable to connect to backend, reason: ', error);
return;
Expand All @@ -1146,14 +1154,25 @@ class BoardStore extends BaseStore {
this._storage.get('card-popup').visible = false;

const card = this._getCardById(
this._storage.get('card-popup').clid,
this._storage.get('card-popup').cid,
(data.clidPrev? data.clidPrev : _data.clid),
_data.cid,
);
const bound = data.pos > card.pos ?
{left: card.pos, right: data.pos, increment: -1} :
{left: data.pos - 1, right: card.pos - 1, increment: 1};

const cards = this._getCardListById(this._storage.get('card-popup').clid).cards;
const cards = this._getCardListById(_data.clid).cards;

if (data.clidPrev) {
if (data.clidPrev !== _data.clid) {
const oldCards = this._getCardListById(data.clidPrev).cards;
oldCards.splice(oldCards.indexOf(card), 1);
cards.splice(card.pos - 1, 0, card);
} else {
const cardIndex = cards.indexOf(card);
cards.splice(card.pos - 1, 0, cards.splice(cardIndex, 1)[0]);
}
}

for (let index = bound.left; index < bound.right; index += 1) {
cards[index].pos += bound.increment;
Expand All @@ -1164,7 +1183,8 @@ class BoardStore extends BaseStore {

card.card_name = data.card_name;
card.description = data.description;
card.pos = data.pos;
card.position = data.pos;
card.pos = cards.indexOf(card) + 1;

card.deadline = data.deadline;
card.deadlineStatus = validator.validateDeadline(data.deadline, data.deadline_check);
Expand Down
2 changes: 1 addition & 1 deletion src/views/BoardView/BoardView.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
<div class="vertical-line"></div>
<div class="button button_small" id="showTagsBoardPopUpId">Теги</div>
</div>
<div class="columns custom-scroll">
<div class="columns custom-scroll cardListDropZone">
{{#each _cardlists}}
{{{this}}}
{{/each}}
Expand Down
154 changes: 154 additions & 0 deletions src/views/BoardView/BoardView.js
Original file line number Diff line number Diff line change
Expand Up @@ -155,14 +155,18 @@ export default class BoardView extends BaseView {
addMembersBtn: document.getElementById('showAddBoardMemberPopUpId'),
showTagsBtn: document.getElementById('showTagsBoardPopUpId'),
cardLists: {
dragAreas: document.querySelectorAll('.dragCardList'),
addCardBtns: document.querySelectorAll('.addCardToCardList'),
editBtns: document.querySelectorAll('.editCardList'),
deleteBtns: document.querySelectorAll('.deleteCardList'),
cardListsDropZones: document.querySelectorAll('.cardListDropZone'),
},
cards: {
dragAreas: document.querySelectorAll('.dragCard'),
editAreas: document.querySelectorAll('.editCard'),
deleteBtns: document.querySelectorAll('.deleteCard'),
checkDeadlineCardBtns: document.querySelectorAll('.checkDeadlineCard'),
cardDropZones: document.querySelectorAll('.cardDropZone'),
},
};
}
Expand Down Expand Up @@ -204,6 +208,9 @@ export default class BoardView extends BaseView {
},
};
this._onAddBoardMemberShow = this._onAddBoardMemberShow.bind(this);
/* DnD */
this._onCardDrop = this._onCardDrop.bind(this);
this._onDragOver = this._onDragOver.bind(this);
this._onShowTagListPopUpBoard = this._onShowTagListPopUpBoard.bind(this);
}

Expand Down Expand Up @@ -234,6 +241,26 @@ export default class BoardView extends BaseView {
this._elements.cards.checkDeadlineCardBtns.forEach((checkDeadlineCardBtn)=>{
checkDeadlineCardBtn.addEventListener('click', this._onCheckDeadlineCard);
});
/* DnD: card */
this._elements.cards.cardDropZones.forEach((cardDropZone)=>{
cardDropZone.addEventListener('drop', this._onCardDrop);
});
this._elements.cardLists.cardListsDropZones.forEach((cardListDropZone)=>{
cardListDropZone.addEventListener('dragover', this._onDragOver);
});
this._elements.cards.dragAreas.forEach((dragArea)=>{
dragArea.addEventListener('dragstart', this._onCardDrag);
});
/* DnD: cardList */
this._elements.cardLists.cardListsDropZones.forEach((cardListDropZone)=>{
cardListDropZone.addEventListener('drop', this._onCardListDrop);
});
this._elements.cardLists.cardListsDropZones.forEach((cardListDropZone)=>{
cardListDropZone.addEventListener('dragover', this._onDragOver);
});
this._elements.cardLists.dragAreas.forEach((dragArea)=>{
dragArea.addEventListener('dragstart', this._onCardListDrag);
});
this._elements.showTagsBtn?.addEventListener('click', this._onShowTagListPopUpBoard);
}

Expand Down Expand Up @@ -263,6 +290,26 @@ export default class BoardView extends BaseView {
this._elements.cards.checkDeadlineCardBtns.forEach((checkDeadlineCardBtn)=>{
checkDeadlineCardBtn.removeEventListener('click', this._onCheckDeadlineCard);
});
/* DnD: card */
this._elements.cards.cardDropZones.forEach((cardDropZone)=>{
cardDropZone.removeEventListener('drop', this._onCardDrop);
});
this._elements.cardLists.cardListsDropZones.forEach((cardListDropZone)=>{
cardListDropZone.removeEventListener('dragover', this._onDragOver);
});
this._elements.cards.dragAreas.forEach((dragArea)=>{
dragArea.removeEventListener('dragstart', this._onCardDrag);
});
/* DnD: cardList */
this._elements.cardLists.cardListsDropZones.forEach((cardListDropZone)=>{
cardListDropZone.removeEventListener('drop', this._onCardListDrop);
});
this._elements.cardLists.cardListsDropZones.forEach((cardListDropZone)=>{
cardListDropZone.removeEventListener('dragover', this._onDragOver);
});
this._elements.cardLists.dragAreas.forEach((dragArea)=>{
dragArea.removeEventListener('dragstart', this._onCardListDrag);
});
this._elements.showTagsBtn?.removeEventListener('click', this._onShowTagListPopUpBoard);
}

Expand Down Expand Up @@ -420,6 +467,113 @@ export default class BoardView extends BaseView {
}
}

/**
* Callback, вызываемый при перемещении карточки
* @param {Event} event - объект события
* @private
*/
_onCardDrop(event) {
event.preventDefault();
const data = event.dataTransfer.getData('brr/card');
const clidPrev = parseInt(event.dataTransfer.getData('brr/card/cardList'), 10);
if (data && clidPrev) {
try {
const element = document.querySelector(`.card [data-id="${data}"]`);
const cardElement = event.target.closest('.card');
const target = event.target.closest('.cardDropZone');

target.insertBefore(element, cardElement);

const position = Array.from(target.children).findIndex((card) =>
card.attributes.getNamedItem('data-id').value === element.dataset.id);
if (position === -1) {
throw new Error(`BoardView: карточка ${data} не найдена`);
}
const card = BoardStore._getCardById(clidPrev, parseInt(data, 10));

card.cid = parseInt(data, 10);
card.clid = parseInt(element.closest('.cardDropZone').dataset.id, 10);
card.pos = position + 1;
card.clidPrev = clidPrev;

cardActions.updateCard(
card,
);
} catch (error) {
throw new Error(`BoardView: не получилось переместить карточку (причина: ${error})`);
}
}
}

/**
* Callback, вызываемый при завершении D&D
* @param {Event} event - объект события
* @private
*/
_onDragOver(event) {
event.preventDefault();
event.dataTransfer.dropEffect = 'move';
event.target.style.opacity = 1;
event.target.style.transform = 'translate(0, 0)';
}

/**
* Callback, вызываемый при перетаскивании карточки
* @param {Event} event - объект события
* @private
*/
_onCardDrag(event) {
event.dataTransfer.setData('brr/card', event.target.closest('.card').dataset.id);
event.dataTransfer.setData('brr/card/cardList',
event.target.closest('.cardDropZone').dataset.id);
event.dataTransfer.effectAllowed = 'move';
event.target.style.opacity = 0.6;
event.target.style.transform = 'translate(10px, 10px)';
}

/**
* Callback, вызываемый при перетаскивании колонки
* @param {Event} event - объект события
* @private
*/
_onCardListDrag(event) {
event.dataTransfer.setData('brr/cardList', event.target.closest('.column').dataset.id);
event.dataTransfer.effectAllowed = 'move';
event.target.style.opacity = 0.6;
event.target.style.transform = 'translate(10px, 10px)';
}

/**
* Callback, вызываемый при перемещении колонки
* @param {Event} event - объект события
* @private
*/
_onCardListDrop(event) {
event.preventDefault();
const data = event.dataTransfer.getData('brr/cardList');
if (data && !event.dataTransfer.getData('brr/card')) {
try {
const element = document.querySelector(`.column [data-id="${data}"]`);
const cardListElement = event.target.closest('.column');
const target = event.target.closest('.cardListDropZone');

target.insertBefore(element, cardListElement);

const position = Array.from(target.children).findIndex((cardList) =>
cardList.attributes.getNamedItem('data-id').value === element.dataset.id);
if (position === -1) {
throw new Error(`BoardView: колонка ${data} не найдена`);
}
const cardList = BoardStore._getCardListById(parseInt(data, 10));

cardListActions.updateCardList(
position + 1, cardList.cardList_name, parseInt(element.dataset.id, 10),
);
} catch (error) {
throw new Error(`BoardView: не получилось переместить колонку (причина: ${error})`);
}
}
}
/**
* Callback, вызываемый при обновлении ссылки приглашение на доску
* @param {Event} event объект события
Expand Down

0 comments on commit 00be196

Please sign in to comment.