New kanban structure with drag&drop support

pull/1/head
yflory 5 years ago
parent c26560e3f9
commit 2e81605c95

@ -39,9 +39,8 @@ define([
$container.find('.kanban-remove-item').remove(); $container.find('.kanban-remove-item').remove();
$container.find('.kanban-board .kanban-item').each(function (i, el) { $container.find('.kanban-board .kanban-item').each(function (i, el) {
var pos = kanban.findElementPosition(el); var pos = kanban.findElementPosition(el);
var board = kanban.options.boards.find(function (b) { var boards = kanban.options.boards;
return b.id === $(el.parentNode.parentNode).attr('data-id'); var board = boards.data[$(el.parentNode.parentNode).attr('data-id')];
});
$('<button>', { $('<button>', {
'class': 'kanban-remove-item btn btn-default fa fa-times', 'class': 'kanban-remove-item btn btn-default fa fa-times',
title: Messages.kanban_removeItem title: Messages.kanban_removeItem
@ -59,41 +58,48 @@ define([
// Kanban code // Kanban code
var initKanban = function (framework, boards) { var initKanban = function (framework, boards) {
var defaultBoards = [{ var items = {};
for (var i=1; i<=6; i++) {
items['id'+i] = {
id: "id"+i,
title: Messages._getKey('kanban_item', [i])
};
}
var defaultBoards = {
list: ["todo", "working", "done"],
data: {
"todo": {
"id": "todo", "id": "todo",
"title": Messages.kanban_todo, "title": Messages.kanban_todo,
"color": "blue", "color": "blue",
"item": [{ "item": ["id1", "id2"]
"title": Messages._getKey('kanban_item', [1]) },
}, { "working": {
"title": Messages._getKey('kanban_item', [2])
}]
}, {
"id": "working", "id": "working",
"title": Messages.kanban_working, "title": Messages.kanban_working,
"color": "orange", "color": "orange",
"item": [{ "item": ["id3", "id4"]
"title": Messages._getKey('kanban_item', [3]) },
}, { "done": {
"title": Messages._getKey('kanban_item', [4])
}]
}, {
"id": "done", "id": "done",
"title": Messages.kanban_done, "title": Messages.kanban_done,
"color": "green", "color": "green",
"item": [{ "item": ["id5", "id6"]
"title": Messages._getKey('kanban_item', [5]) }
}, { },
"title": Messages._getKey('kanban_item', [6]) items: items
}] };
}];
if (!boards) { if (!boards) {
verbose("Initializing with default boards content"); verbose("Initializing with default boards content");
boards = defaultBoards; boards = defaultBoards;
} else if (Array.isArray(boards)) {
// XXX also migrate colors!
throw new Error("NEED MIGRATION"); // XXX
} else { } else {
verbose("Initializing with boards content " + boards); verbose("Initializing with boards content " + boards);
} }
boards = defaultBoards;
// Remove any existing elements // Remove any existing elements
$(".kanban-container-outer").remove(); $(".kanban-container-outer").remove();
@ -262,6 +268,8 @@ define([
jscolorL.fromString(currentColor); jscolorL.fromString(currentColor);
}, },
buttonClick: function (el, boardId, e) { buttonClick: function (el, boardId, e) {
return;
// XXX delete baord from modal only? or drag&drop
e.stopPropagation(); e.stopPropagation();
if (framework.isReadOnly() || framework.isLocked()) { return; } if (framework.isReadOnly() || framework.isLocked()) { return; }
UI.confirm(Messages.kanban_deleteBoard, function (yes) { UI.confirm(Messages.kanban_deleteBoard, function (yes) {
@ -512,7 +520,7 @@ define([
framework.setContentGetter(function () { framework.setContentGetter(function () {
if (!kanban) { if (!kanban) {
return { return {
content: [] content: {}
}; };
} }
var content = kanban.getBoardsJSON(); var content = kanban.getBoardsJSON();

@ -53,7 +53,11 @@
responsive: '700', responsive: '700',
colors: ["yellow", "green", "blue", "red", "orange"], colors: ["yellow", "green", "blue", "red", "orange"],
responsivePercentage: false, responsivePercentage: false,
boards: [], boards: {
data: {},
items: {},
list: []
},
dragBoards: true, dragBoards: true,
addItemButton: false, addItemButton: false,
buttonContent: '+', buttonContent: '+',
@ -87,7 +91,7 @@
self.drakeBoard = self.dragula([self.container], { self.drakeBoard = self.dragula([self.container], {
moves: function (el, source, handle, sibling) { moves: function (el, source, handle, sibling) {
if (self.options.readOnly) { return false; } if (self.options.readOnly) { return false; }
if (!self.options.dragBoards) return false; if (!self.options.dragBoards) { return false; }
return (handle.classList.contains('kanban-board-header') || handle.classList.contains('kanban-title-board')); return (handle.classList.contains('kanban-board-header') || handle.classList.contains('kanban-title-board'));
}, },
accepts: function (el, target, source, sibling) { accepts: function (el, target, source, sibling) {
@ -100,8 +104,9 @@
.on('drag', function (el, source) { .on('drag', function (el, source) {
el.classList.add('is-moving'); el.classList.add('is-moving');
self.options.dragBoard(el, source); self.options.dragBoard(el, source);
if (typeof (el.dragfn) === 'function') if (typeof (el.dragfn) === 'function') {
el.dragfn(el, source); el.dragfn(el, source);
}
}) })
.on('dragend', function (el) { .on('dragend', function (el) {
el.classList.remove('is-moving'); el.classList.remove('is-moving');
@ -112,32 +117,24 @@
.on('drop', function (el, target, source, sibling) { .on('drop', function (el, target, source, sibling) {
el.classList.remove('is-moving'); el.classList.remove('is-moving');
self.options.dropBoard(el, target, source, sibling); self.options.dropBoard(el, target, source, sibling);
if (typeof (el.dropfn) === 'function') if (typeof (el.dropfn) === 'function') {
el.dropfn(el, target, source, sibling); el.dropfn(el, target, source, sibling);
// TODO: update board object board order
console.log("Drop " + $(el).attr("data-id") + " just before " + (sibling ? $(sibling).attr("data-id") : " end "));
var index1, index2;
self.options.boards.some(function (element, index) {
if (element.id === $(el).attr("data-id")) {
index1 = index;
return true;
} }
});
var list = self.options.boards.list || [];
var index1 = list.indexOf($(el).attr("data-id"));
var index2;
if (sibling) { if (sibling) {
self.options.boards.some(function (element, index) { index2 = list.indexOf($(sibling).attr("data-id"));
if (element.id === $(sibling).attr("data-id")) {
index2 = index;
return true;
}
})
} else { } else {
index2 = self.options.boards.length; index2 = list.length;
} }
console.log("Switch " + index1 + " and " + index2); console.log("Switch " + index1 + " and " + index2);
if (index1 < index2) if (index1 < index2) {
index2 = index2 - 1; index2 = index2 - 1;
self.options.boards.splice(index2, 0, self.options.boards.splice(index1, 1)[0]); }
list.splice(index2, 0, list.splice(index1, 1)[0]);
// send event that board has changed // send event that board has changed
self.onChange(); self.onChange();
@ -164,31 +161,24 @@
self.dragItemPos = self.findElementPosition(el); self.dragItemPos = self.findElementPosition(el);
el.classList.add('is-moving'); el.classList.add('is-moving');
var boardJSON = __findBoardJSON(source.parentNode.dataset.id);
if (boardJSON.dragTo !== undefined) {
self.options.boards.map(function (board) {
if (boardJSON.dragTo.indexOf(board.id) === -1 && board.id !== source.parentNode.dataset.id) {
self.findBoard(board.id).classList.add('disabled-board');
}
})
}
self.options.dragEl(el, source); self.options.dragEl(el, source);
if (el !== null && typeof (el.dragfn) === 'function') if (el !== null && typeof (el.dragfn) === 'function') {
el.dragfn(el, source); el.dragfn(el, source);
}
}) })
.on('dragend', function (el) { .on('dragend', function (el) {
console.log("In dragend"); console.log("In dragend");
el.classList.remove('is-moving'); el.classList.remove('is-moving');
self.options.dragendEl(el); self.options.dragendEl(el);
if (el !== null && typeof (el.dragendfn) === 'function') if (el !== null && typeof (el.dragendfn) === 'function') {
el.dragendfn(el); el.dragendfn(el);
}
}) })
.on('cancel', function (el, container, source) { .on('cancel', function (el, container, source) {
console.log("In cancel"); console.log("In cancel");
el.classList.remove('is-moving'); el.classList.remove('is-moving');
// FIXME custom code var boardId = $(source).closest('kanban-board').data('id');
var boardId = source.parentNode.dataset.id;
self.options.dragcancelEl(el, boardId); self.options.dragcancelEl(el, boardId);
}) })
.on('drop', function(el, target, source, sibling) { .on('drop', function(el, target, source, sibling) {
@ -197,43 +187,24 @@
console.log("In drop"); console.log("In drop");
// TODO: update board object board order var sourceId = $(source).closest('.kanban-board').data('id');
var board1; var targetId = $(target).closest('.kanban-board').data('id');
self.options.boards.some(function (element) {
if (element.id === $(source.parentNode).attr("data-id")) { var board1 = __findBoardJSON(sourceId);
return board1 = element; var board2 = __findBoardJSON(targetId);
} console.log(source, target, sourceId, targetId, board1, board2);
});
var board2;
self.options.boards.some(function (element) {
if (element.id === $(target.parentNode).attr("data-id")) {
return board2 = element;
}
});
var pos1 = self.dragItemPos; var pos1 = self.dragItemPos;
var pos2 = (sibling) ? self.findElementPosition(sibling) : (board2.item.length + 1); var pos2 = (sibling) ? self.findElementPosition(sibling) : (board2.item.length + 1);
console.log("Drop element " + pos1 + " before " + pos2); console.log("Drop element " + pos1 + " before " + pos2);
// TODO: update board object item order
var allB = document.querySelectorAll('.kanban-board');
if (allB.length > 0 && allB !== undefined) {
for (var i = 0; i < allB.length; i++) {
allB[i].classList.remove('disabled-board');
}
}
var boardJSON = __findBoardJSON(source.parentNode.dataset.id);
if (boardJSON.dragTo !== undefined) {
if (boardJSON.dragTo.indexOf(target.parentNode.dataset.id) === -1 && target.parentNode.dataset.id !== source.parentNode.dataset.id) {
self.drake.cancel(true)
}
}
if (el !== null) { if (el !== null) {
self.options.dropEl(el, target, source, sibling); self.options.dropEl(el, target, source, sibling);
el.classList.remove('is-moving'); el.classList.remove('is-moving');
if (typeof (el.dropfn) === 'function') if (typeof (el.dropfn) === 'function') {
el.dropfn(el, target, source, sibling); el.dropfn(el, target, source, sibling);
} }
}
var item = board1.item[pos1]; var item = board1.item[pos1];
// if (board1==board2 && pos2<pos1) // if (board1==board2 && pos2<pos1)
@ -297,27 +268,25 @@
this.addBoards = function(boards) { this.addBoards = function(boards) {
if (self.options.responsivePercentage) {
self.container.style.width = '100%';
self.options.gutter = '1%';
if (window.innerWidth > self.options.responsive) {
var boardWidth = (100 - boards.length * 2) / boards.length;
} else {
var boardWidth = 100 - (boards.length * 2);
}
} else {
var boardWidth = self.options.widthBoard; var boardWidth = self.options.widthBoard;
}
var addButton = self.options.addItemButton; var addButton = self.options.addItemButton;
var buttonContent = self.options.buttonContent; var buttonContent = self.options.buttonContent;
//for on all the boards //for on all the boards
for (var boardkey in boards) { var old = self.options.boards;
boards.list = boards.list || [];
boards.data = boards.data || {};
for (var index in boards.list) {
// single board // single board
var board = boards[boardkey]; var boardkey = boards.list[index];
if (self.options.boards !== boards) var board = boards.data[boardkey];
self.options.boards.push(board); if (!board) { continue; } // XXX clean invalid data
// Remote changes, we had to reset our data
if (old !== boards && old.list.indexOf(boardKey === -1)) {
old.list.push(boardKey);
}
//create node //create node
var boardNode = document.createElement('div'); var boardNode = document.createElement('div');
@ -333,18 +302,23 @@
boardNode.style.marginRight = self.options.gutter; boardNode.style.marginRight = self.options.gutter;
// header board // header board
var headerBoard = document.createElement('header'); var headerBoard = document.createElement('header');
if (board.class !== '' && board.class !== undefined) if (board.class !== '' && board.class !== undefined) {
var allClasses = board.class.split(","); var allClasses = board.class.split(",");
else allClasses = []; } else {
allClasses = [];
}
headerBoard.classList.add('kanban-board-header'); headerBoard.classList.add('kanban-board-header');
allClasses.map(function (value) { allClasses.map(function (value) {
headerBoard.classList.add(value); headerBoard.classList.add(value);
}); });
if (board.color !== '' && board.color !== undefined) { if (board.color !== '' && board.color !== undefined) {
/*
headerBoard._jscLinkedInstance = undefined; headerBoard._jscLinkedInstance = undefined;
jscolorL = new jscolor(headerBoard,{showOnClick: false, valueElement:undefined}); jscolorL = new jscolor(headerBoard,{showOnClick: false, valueElement:undefined});
jscolorL.fromString(board.color); jscolorL.fromString(board.color);
headerBoard._jscLinkedInstance = undefined; headerBoard._jscLinkedInstance = undefined;
*/
// XXX fixed list of color: use class?
headerBoard.classList.add("kanban-header-" + board.color); headerBoard.classList.add("kanban-header-" + board.color);
} }
titleBoard = document.createElement('div'); titleBoard = document.createElement('div');
@ -354,24 +328,25 @@
titleBoard.clickfn = board.boardTitleClick; titleBoard.clickfn = board.boardTitleClick;
__onboardTitleClickHandler(titleBoard); __onboardTitleClickHandler(titleBoard);
headerBoard.appendChild(titleBoard); headerBoard.appendChild(titleBoard);
__onColorClickHandler(headerBoard, "board"); //__onColorClickHandler(headerBoard, "board"); // XXX color
// if add button is true, add button to the board // add button to the board
if (addButton) { /* // XXX delete board button ==> removed
var btn = document.createElement("BUTTON"); var btn = document.createElement("BUTTON");
btn.setAttribute("class", "kanban-title-button btn btn-default btn-xs fa fa-times"); btn.setAttribute("class", "kanban-title-button btn btn-default btn-xs fa fa-times");
//var buttonHtml = '<button class="kanban-title-button btn btn-default btn-xs">'+buttonContent+'</button>'
headerBoard.appendChild(btn); headerBoard.appendChild(btn);
__onButtonClickHandler(btn, board.id); __onButtonClickHandler(btn, board.id);
} */
//content board //content board
var contentBoard = document.createElement('main'); var contentBoard = document.createElement('main');
contentBoard.classList.add('kanban-drag'); contentBoard.classList.add('kanban-drag');
//add drag to array for dragula //add drag to array for dragula
self.boardContainer.push(contentBoard); self.boardContainer.push(contentBoard);
for (var itemkey in board.item) { (board.item || []).forEach(function (itemkey) {
//create item //create item
var itemKanban = board.item[itemkey]; var itemKanban = boards.items[itemkey];
if (!itemKanban) { return; } // XXX clean invalid data
var nodeItem = document.createElement('div'); var nodeItem = document.createElement('div');
nodeItem.classList.add('kanban-item'); nodeItem.classList.add('kanban-item');
nodeItem.dataset.eid = itemKanban.id; nodeItem.dataset.eid = itemKanban.id;
@ -387,24 +362,32 @@
nodeItemText.dropfn = itemKanban.drop; nodeItemText.dropfn = itemKanban.drop;
//add click handler of item //add click handler of item
__onclickHandler(nodeItemText); __onclickHandler(nodeItemText);
/*
// XXX color handle color differently
if (itemKanban.color !== '' && itemKanban.color !== undefined) { if (itemKanban.color !== '' && itemKanban.color !== undefined) {
jscolorL = new jscolor(nodeItem,{showOnClick: false, valueElement:undefined}); jscolorL = new jscolor(nodeItem,{
showOnClick: false, valueElement:undefined
});
jscolorL.fromString(itemKanban.color); jscolorL.fromString(itemKanban.color);
} }*/
__onColorClickHandler(nodeItem, "item"); //__onColorClickHandler(nodeItem, "item"); // XXX color
contentBoard.appendChild(nodeItem); contentBoard.appendChild(nodeItem);
} });
//footer board //footer board
var footerBoard = document.createElement('footer');
footerBoard.classList.add('kanban-board-footer');
//add button //add button
var addBoardItem = document.createElement('button'); var addBoardItem = document.createElement('button');
$(addBoardItem).addClass("kanban-title-button btn btn-default fa fa-plus"); $(addBoardItem).addClass("kanban-title-button btn btn-default fa fa-plus");
headerBoard.appendChild(addBoardItem); footerBoard.appendChild(addBoardItem);
__onAddItemClickHandler(addBoardItem); __onAddItemClickHandler(addBoardItem);
//board assembly //board assembly
boardNode.appendChild(headerBoard); boardNode.appendChild(headerBoard);
boardNode.appendChild(contentBoard); boardNode.appendChild(contentBoard);
boardNode.appendChild(footerBoard);
//board add //board add
self.container.appendChild(boardNode); self.container.appendChild(boardNode);
} }
@ -416,12 +399,16 @@
} }
this.setBoards = function (boards) { this.setBoards = function (boards) {
self.element //self.element
for (var boardkey in this.options.boards) { for (var boardkey in this.options.boards.list) {
var board = this.options.boards[boardkey]; //var board = this.options.boards[boardkey];
this.removeBoard(board.id); this.removeBoard(boardKey);
} }
this.options.boards = []; this.options.boards = {
list: [],
data: boards.data || {},
items: boards.items || {}
};
this.addBoards(boards); this.addBoards(boards);
} }
@ -508,13 +495,13 @@
var addBoard = document.createElement('div'); var addBoard = document.createElement('div');
addBoard.id = 'kanban-addboard'; addBoard.id = 'kanban-addboard';
addBoard.setAttribute('class', 'fa fa-plus'); addBoard.setAttribute('class', 'fa fa-plus');
boardContainer.appendChild(addBoard);
self.container = boardContainer; self.container = boardContainer;
//add boards //add boards
self.addBoards(self.options.boards); self.addBoards(self.options.boards);
//appends to container //appends to container
self.element.appendChild(boardContainerOuter); self.element.appendChild(boardContainerOuter);
self.element.appendChild(addBoard);
// send event that board has changed // send event that board has changed
self.onChange(); self.onChange();
@ -571,13 +558,7 @@
} }
function __findBoardJSON(id) { function __findBoardJSON(id) {
var el = [] return (self.options.boards.data || {})[id];
self.options.boards.map(function (board) {
if (board.id === id) {
return el.push(board)
}
})
return el[0]
} }

Loading…
Cancel
Save