Merge branch 'communities-kanban' into staging

pull/1/head
yflory 5 years ago
commit 195ee1f1e0

@ -277,7 +277,7 @@
margin-bottom: 15px; margin-bottom: 15px;
} }
button { button:not('.pure-button') {
display: inline-block; display: inline-block;
position: relative; position: relative;
margin: 6px 8px; margin: 6px 8px;
@ -293,6 +293,9 @@
&:not(:first-child) { &:not(:first-child) {
margin-left: @alertify_padding-base !important; margin-left: @alertify_padding-base !important;
} }
&.left {
float: left;
}
} }
} }
} }

@ -53,6 +53,49 @@
} }
} }
.markdown_cryptpad() {
word-wrap: break-word;
h1, h2, h3, h4, h5, h6 {
font-weight: bold;
padding-bottom: 0.3em;
border-bottom: 1px solid #eee;
}
li {
min-height: 22px;
}
.todo-list-item {
list-style: none;
position: relative;
.fa {
position: absolute;
margin-left: -17px;
margin-top: 4px;
&.fa-check-square {
font-size: 15px;
margin-top: 5px;
}
}
}
media-tag {
* {
max-width: 100%;
}
iframe[src$=".pdf"] {
width: 100%;
height: 80vh;
max-height: 90vh;
}
}
media-tag:empty {
width: 100px;
height: 100px;
display: inline-block;
border: 1px solid #BBB;
}
}
.markdown_preformatted-code (@color: #333) { .markdown_preformatted-code (@color: #333) {
pre > code { pre > code {
display: block; display: block;

@ -11,7 +11,6 @@
.tools_unselectable(); .tools_unselectable();
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
justify-content: space-around;
height: auto; height: auto;
min-height: 34px; min-height: 34px;
padding-bottom: 0px; padding-bottom: 0px;
@ -29,6 +28,7 @@
background-color: #ededed; background-color: #ededed;
white-space: nowrap; white-space: nowrap;
margin: 2px 0; margin: 2px 0;
margin-right: 5px;
height: 24px; height: 24px;
vertical-align: middle; vertical-align: middle;
cursor: default; cursor: default;

@ -168,6 +168,7 @@
position: relative; position: relative;
order: -2; order: -2;
resize: horizontal; resize: horizontal;
z-index: 1;
#cp-app-contacts-container { #cp-app-contacts-container {
height: 100%; height: 100%;
} }
@ -196,6 +197,7 @@
padding: 10px; padding: 10px;
box-sizing: border-box; box-sizing: border-box;
order: -3; order: -3;
z-index: 1;
.cp-toolbar-userlist-drawer-close { .cp-toolbar-userlist-drawer-close {
position: absolute; position: absolute;
margin-top: -10px; margin-top: -10px;

@ -65,47 +65,12 @@
box-sizing: border-box; box-sizing: border-box;
//font-family: Calibri,Ubuntu,sans-serif; //font-family: Calibri,Ubuntu,sans-serif;
font: @colortheme_app-font; font: @colortheme_app-font;
word-wrap: break-word;
position: relative; position: relative;
flex: 1; flex: 1;
h1, h2, h3, h4, h5, h6 {
font-weight: bold;
padding-bottom: 0.3em;
border-bottom: 1px solid #eee;
}
li {
min-height: 22px;
}
.todo-list-item {
list-style: none;
.fa {
position: absolute;
margin-left: -17px;
margin-top: 4px;
&.fa-check-square {
font-size: 15px;
margin-top: 5px;
}
}
}
media-tag {
* {
max-width:100%;
}
iframe[src$=".pdf"] {
width: 100%;
height: 80vh;
max-height: 90vh;
}
}
media-tag:empty {
width: 100px;
height: 100px;
display: inline-block;
border: 1px solid #BBB;
}
.markdown_main(); .markdown_main();
.markdown_cryptpad();
.cp-app-code-preview-empty { .cp-app-code-preview-empty {
display: none; display: none;
} }

@ -64,7 +64,7 @@ define([
editor._noCursorUpdate = false; editor._noCursorUpdate = false;
editor.scrollTo(scroll.left, scroll.top); editor.scrollTo(scroll.left, scroll.top);
if (!editor.state.focused) { return; } if (!editor.hasFocus()) { return; }
if(selects[0] === selects[1]) { if(selects[0] === selects[1]) {
editor.setCursor(posToCursor(selects[0], remoteDoc)); editor.setCursor(posToCursor(selects[0], remoteDoc));

@ -1,6 +1,8 @@
@import (reference) "../../customize/src/less2/include/browser.less"; @import (reference) "../../customize/src/less2/include/browser.less";
@import (reference) "../../customize/src/less2/include/framework.less"; @import (reference) "../../customize/src/less2/include/framework.less";
@import (reference) "../../customize/src/less2/include/tools.less"; @import (reference) "../../customize/src/less2/include/tools.less";
@import (reference) "../../customize/src/less2/include/markdown.less";
@import (reference) "../../customize/src/less2/include/avatar.less";
// body // body
&.cp-app-kanban { &.cp-app-kanban {
@ -14,11 +16,142 @@
flex-flow: column; flex-flow: column;
max-height: 100%; max-height: 100%;
min-height: auto; min-height: auto;
color: @cryptpad_text_col;
@board-bg: #eaeaea;
@palette0: #888; // Default bg color for header
@palette1: #FFD4D4;
@palette2: #FFDECA;
@palette3: #FFE69C;
@palette4: #DBFFB7;
@palette5: #AFFDC2;
@palette6: #C9FFFE;
@palette7: #C8D6FF;
@palette8: #E4CAFF;
.kanban-board-header {
background-color: #c9c9c9;
}
.kanban-board {
.kanban-board-inner {
background-color: @board-bg;
max-height: 100%;
display: flex;
flex-flow: column;
}
color: @cryptpad_text_col;
}
.cp-kanban-palette-nocolor {
background-color: @palette0;
}
.cp-kanban-palette-color1 {
background-color: @palette1;
&.kanban-board-inner {
background-color: lighten(@palette1, 5%);
}
}
.cp-kanban-palette-color2 {
background-color: @palette2;
&.kanban-board-inner {
background-color: lighten(@palette2, 5%);
}
}
.cp-kanban-palette-color3 {
background-color: @palette3;
&.kanban-board-inner {
background-color: lighten(@palette3, 10%);
}
}
.cp-kanban-palette-color4 {
background-color: @palette4;
&.kanban-board-inner {
background-color: lighten(@palette4, 10%);
}
}
.cp-kanban-palette-color5 {
background-color: @palette5;
&.kanban-board-inner {
background-color: lighten(@palette5, 10%);
}
}
.cp-kanban-palette-color6 {
background-color: @palette6;
&.kanban-board-inner {
background-color: lighten(@palette6, 5%);
}
}
.cp-kanban-palette-color7 {
background-color: @palette7;
&.kanban-board-inner {
background-color: lighten(@palette7, 5%);
}
}
.cp-kanban-palette-color8 {
background-color: @palette8;
&.kanban-board-inner {
background-color: lighten(@palette8, 5%);
}
}
.cp-kanban-edit-modal {
display: flex;
flex-flow: column;
overflow: hidden;
}
#cp-kanban-edit-conflicts {
padding: 5px;
background: #eee;
color: @cryptpad_text_col;
font-size: 14px;
.cp-kanban-cursors {
margin-top: 5px;
}
margin-bottom: 5px;
}
#cp-kanban-edit-body {
border: 1px solid @colortheme_modal-input;
.CodeMirror {
height: 105px;
}
.CodeMirror-scroll {
box-sizing: content-box;
}
.cp-markdown-toolbar {
background-color: #eee;
color: @cryptpad_text_col;
}
margin-bottom: 15px;
}
#cp-kanban-edit-colors {
display: flex;
justify-content: space-between;
.cp-kanban-palette {
display: inline-block;
border-radius: 50%;
height: 30px;
width: 30px;
text-align: center;
line-height: 30px;
color: @cryptpad_text_col;
}
.cp-kanban-palette-nocolor {
border: 1px solid @cryptpad_text_col;
}
}
#cp-kanban-edit-tags {
.tokenfield {
margin: 0;
}
margin-bottom: 15px;
}
#cp-app-kanban-container { #cp-app-kanban-container {
flex: 1; flex: 1;
display: flex; display: flex;
flex-flow: column; flex-flow: column;
overflow-x: hidden;
} }
#cp-app-kanban-editor { #cp-app-kanban-editor {
flex: 1; flex: 1;
@ -27,42 +160,94 @@
height: 100%; height: 100%;
overflow: hidden; overflow: hidden;
} }
#cp-app-kanban-content {
flex: 1; .kanban-edit-item {
overflow-y: auto; padding: 5px;
display: flex; }
flex-flow: column;
.kanban-container-outer { .cp-kanban-cursors {
flex: 1; &:empty { display: none; }
order: 2;
width: 100%;
&> span {
display: inline-block;
width: 20px;
height: 20px;
text-align: center;
line-height: 20px;
margin-right: 5px;
.tools_unselectable();
cursor: default;
}
}
.kanban-item {
display: flex; display: flex;
align-items: center; align-items: center;
min-height: -webkit-min-content; justify-content: space-between;
min-height: min-content; padding: 5px;
.kanban-container {
flex: 1;
display: flex;
flex-wrap: wrap; flex-wrap: wrap;
justify-content: space-around; .cp-kanban-cursors {
margin-top: 10px;
} }
.kanban-item-body, .kanban-item-tags {
.tools_unselectable();
width: 100%;
} }
.kanban-item-body {
.kanban-item { margin: 10px 0;
font-size: 0.8em;
:last-child {
margin-bottom: 0px;
}
.markdown_main();
.markdown_cryptpad();
.markdown_preformatted-code;
.markdown_gfm-table(black);
ul {
padding-left: 30px;
}
}
.kanban-item-tags {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; flex-wrap: wrap;
padding: 10px 5px 10px 10px; span {
padding: 0 5px;
margin-right: 5px;
margin-top: 5px;
background-color: rgba(0,0,0,0.1);
display: inline-block;
font-size: 12px;
}
}
&.new-item {
padding: 10px;
}
.kanban-item-text { .kanban-item-text {
.tools_unselectable();
cursor: text; cursor: text;
overflow-wrap: anywhere; overflow-wrap: anywhere;
flex: 1; flex: 1;
} }
&.kanban-item-hidden {
display: none;
}
} }
.kanban-board { .kanban-board {
main {
padding: 0 10px;
margin: 10px 0;
flex: 1;
overflow-y: auto;
justify-content: space-around;
min-height: 50px;
}
header { header {
display: flex; display: flex;
flex-wrap: wrap;
align-items: center; align-items: center;
padding: 13px 10px; padding: 5px 10px;
.kanban-title-board { .kanban-title-board {
flex: 1; flex: 1;
margin-right: 10px; margin-right: 10px;
@ -78,49 +263,192 @@
cursor: move; cursor: move;
} }
} }
footer {
margin: 10px;
margin-top: 0px;
span {
.tools_unselectable();
outline: none;
width: 100%;
border: 1px solid @cryptpad_text_col;
border-radius: 0px;
font-size: 40px;
display: inline-flex;
justify-content: center;
align-items: center;
line-height: 1;
cursor: pointer;
&:hover {
background-color: rgba(0,0,0,0.1);
}
}
}
} }
#kanban-edit { #cp-kanban-controls {
padding: 10px;
display: flex;
position: relative;
width: 100%; width: 100%;
background: transparent; justify-content: space-between;
border: 1px solid rgba(0,0,0,0.3); position: relative;
color: inherit; min-height: 50px;
.cp-kanban-filterTags {
display: inline-flex;
align-items: baseline;
flex: 1;
max-width: 80%;
min-width: 150px;
&> i {
cursor: pointer;
margin-left: 10px;
}
.cp-kanban-filterTags-name {
flex-shrink: 0;
}
.cp-kanban-filterTags-list {
margin-left: 10px;
display: flex;
flex-wrap: wrap;
em {
font-size: 14px;
color: lighten(@cryptpad_text_col, 10%);
} }
@button-size: 50px; span {
#kanban-addboard { .tools_unselectable();
margin: 30px; padding: 0 5px;
border: 1px solid; margin-right: 5px;
width: @button-size; margin-top: 5px;
height: @button-size; background-color: rgba(0,0,0,0.1);
line-height: @button-size; display: inline-block;
font-size: 14px;
cursor: pointer;
&.active {
background-color: @cryptpad_text_col;
color: #fff;
}
}
}
}
.cp-kanban-changeView {
right: 10px;
height: 30px;
width: 60px;
span {
height: 30px;
width: 30px;
line-height: 30px;
text-align: center; text-align: center;
background: @colortheme_kanban-bg; display: inline-block;
align-self: flex-start; background-color: @board-bg;
font-size: 30px;
cursor: pointer; cursor: pointer;
.tools_unselectable(); &:hover {
background-color: darken(@board-bg, 10%);
}
}
}
}
#cp-app-kanban-container {
&:not(.cp-kanban-quick) {
#cp-kanban-controls {
.cp-kanban-changeView {
span.cp-kanban-view {
background-color: @cryptpad_text_col !important;
color: white;
}
span.cp-kanban-view-small {
}
}
}
}
&.cp-kanban-quick {
#cp-kanban-controls {
.cp-kanban-changeView {
span.cp-kanban-view {
}
span.cp-kanban-view-small {
background-color: @cryptpad_text_col !important;
color: white;
}
}
}
.kanban-item {
.kanban-item-body, .kanban-item-tags {
display: none;
}
}
}
} }
.kanban-remove-item { #cp-app-kanban-content {
padding: 0 0.5em; flex: 1;
visibility: hidden; display: flex;
flex-flow: column;
max-height: 100%;
overflow-x: auto;
.kanban-container-outer {
flex: 1;
display: flex;
min-height: 0;
.kanban-container {
flex: 1;
display: flex;
max-height: 100%;
}
}
#kanban-trash {
height: 60px;
font-size: 40px;
display: flex;
align-items: center;
justify-content: center;
position: relative;
width: 100%;
//pointer-events: none;
i {
position: fixed;
}
div {
width: 100%;
height: 60px;
position: fixed;
right: 0;
} }
.kanban-item:hover { &.kanban-trash-active {
.kanban-remove-item { color: red;
visibility: visible; div {
background: rgba(255,0,0,0.5);
}
}
.kanban-item, .kanban-board {
display: none;
} }
} }
.kanban-additem { #kanban-edit {
float: right; width: 100%;
background: #EEE;
padding: 5px .5rem 4px;
line-height: 1;
margin-bottom: 5px;
margin-right: 5px;
&:hover {
background: transparent; background: transparent;
border: 1px solid rgba(0,0,0,0.3);
color: inherit;
}
#kanban-addboard {
order: 2;
width: 300px;
margin: 10px 5px;
border: 1px solid @cryptpad_text_col;
height: 40px;
display: inline-flex;
justify-content: center;
align-items: center;
align-self: flex-start;
font-size: 40px;
cursor: pointer;
.tools_unselectable();
&:hover {
background-color: rgba(0,0,0,0.1);
} }
} }
@ -176,6 +504,9 @@
.kanban-title-button, #kanban-addboard, .kanban-remove-item, .kanban-additem { .kanban-title-button, #kanban-addboard, .kanban-remove-item, .kanban-additem {
display: none !important; display: none !important;
} }
#kanban-trash {
display: none;
}
} }
} }

File diff suppressed because it is too large Load Diff

@ -4,13 +4,13 @@
.kanban-board { .kanban-board {
position: relative; position: relative;
float: left;
background: #E2E4E6;
transition: all 0.3s cubic-bezier(0.23, 1, 0.32, 1); transition: all 0.3s cubic-bezier(0.23, 1, 0.32, 1);
margin: 10px; margin: 10px;
vertical-align: top; vertical-align: top;
display: flex; display: flex;
flex-flow: column; flex-flow: column;
width: 300px;
margin: 10px 5px;
} }
.kanban-board.disabled-board { .kanban-board.disabled-board {
@ -19,6 +19,7 @@
.kanban-board.is-moving.gu-mirror { .kanban-board.is-moving.gu-mirror {
transform: rotate(3deg); transform: rotate(3deg);
opacity: 0.8;
} }
.kanban-board.is-moving.gu-mirror .kanban-drag { .kanban-board.is-moving.gu-mirror .kanban-drag {
@ -45,17 +46,11 @@
padding: .25rem .5rem; padding: .25rem .5rem;
} }
.kanban-board .kanban-drag {
min-height: 200px;
padding: 20px;
flex: 1;
}
.kanban-item { .kanban-item {
background: #fff; background: #fff;
padding: 15px; padding: 15px;
margin-bottom: 20px; margin-bottom: 10px;
transition: all 0.3s cubic-bezier(0.23, 1, 0.32, 1);
} }
.kanban-item:hover { .kanban-item:hover {
@ -69,6 +64,7 @@
.kanban-item.is-moving.gu-mirror { .kanban-item.is-moving.gu-mirror {
transform: rotate(3deg); transform: rotate(3deg);
height: auto !important; height: auto !important;
opacity: 0.8;
} }
/* Dragula CSS */ /* Dragula CSS */

@ -45,18 +45,23 @@
this.drake = ''; this.drake = '';
this.drakeBoard = ''; this.drakeBoard = '';
this.addItemButton = false; this.addItemButton = false;
this.buttonContent = '+';
defaults = { defaults = {
element: '', element: '',
gutter: '15px', gutter: '15px',
widthBoard: '250px', widthBoard: '250px',
responsive: '700', responsive: '700',
colors: ["yellow", "green", "blue", "red", "orange"],
responsivePercentage: false, responsivePercentage: false,
boards: [], boards: {
data: {},
items: {},
list: []
},
getAvatar: function () {},
getTextColor: function () { return '#000'; },
cursors: {},
tags: [],
dragBoards: true, dragBoards: true,
addItemButton: false, addItemButton: false,
buttonContent: '+',
readOnly: false, readOnly: false,
dragEl: function (el, source) {}, dragEl: function (el, source) {},
dragendEl: function (el) {}, dragendEl: function (el) {},
@ -67,9 +72,9 @@
dropBoard: function (el, target, source, sibling) {}, dropBoard: function (el, target, source, sibling) {},
click: function (el) {}, click: function (el) {},
boardTitleclick: function (el, boardId) {}, boardTitleclick: function (el, boardId) {},
buttonClick: function (el, boardId) {},
colorClick: function (el, type) {},
addItemClick: function (el, boardId) {}, addItemClick: function (el, boardId) {},
renderMd: function (md) {},
refresh: function () {},
onChange: function () {} onChange: function () {}
}; };
@ -80,19 +85,62 @@
this.init = function () { this.init = function () {
// set initial boards // set initial boards
__setBoard(); __setBoard();
// Scroll on drag
var $el = $(self.element)
var $inner = $el.find('.kanban-container');
var leftRegion = $el.position().left + 10;
var rightRegion = $(window).width() - 10;
var activeBoard;
var $aB;
var setActiveDrag = function (board) {
activeBoard = undefined;
if (!board) { return; }
if (!board.classList.contains('kanban-drag')) { return; }
activeBoard = board;
$aB = $(activeBoard);
};
var onMouseMove = function (isItem) {
return function (e) {
if (e.which !== 1) { return; } // left click
var distance = 20;
// If this is an item drag, check scroll
if (isItem && activeBoard) {
var rect = activeBoard.getBoundingClientRect();
if (e.pageX > rect.left && e.pageX < rect.right) {
if (e.pageY < (rect.top + 10)) {
distance *= -1;
$aB.scrollTop(distance + $aB.scrollTop()) ;
} else if (e.pageY > (rect.bottom - 10)) {
$aB.scrollTop(distance + $aB.scrollTop()) ;
}
}
}
// Itme or board: horizontal scroll if needed
if (e.pageX < leftRegion) {
distance *= -1;
$el.scrollLeft(distance + $el.scrollLeft()) ;
} else if (e.pageX >= rightRegion) {
$el.scrollLeft(distance + $el.scrollLeft()) ;
}
};
};
//set drag with dragula //set drag with dragula
if (window.innerWidth > self.options.responsive) { if (window.innerWidth > self.options.responsive) {
//Init Drag Board //Init Drag Board
self.drakeBoard = self.dragula([self.container], { self.drakeBoard = self.dragula([self.container, self.trashContainer], {
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) {
if (self.options.readOnly) { return false; } if (self.options.readOnly) { return false; }
return target.classList.contains('kanban-container'); if (sibling && sibling.getAttribute('id') === "kanban-addboard") { return false; }
return target.classList.contains('kanban-container') ||
target.classList.contains('kanban-trash');
}, },
revertOnSpill: true, revertOnSpill: true,
direction: 'horizontal', direction: 'horizontal',
@ -100,47 +148,66 @@
.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);
}
$(document).on('mousemove', onMouseMove());
}) })
.on('dragend', function (el) { .on('dragend', function (el) {
el.classList.remove('is-moving'); el.classList.remove('is-moving');
self.options.dragendBoard(el); self.options.dragendBoard(el);
$(document).off('mousemove');
if (typeof (el.dragendfn) === 'function') if (typeof (el.dragendfn) === 'function')
el.dragendfn(el); el.dragendfn(el);
}) })
.on('over', function (el, target, source) {
if (!target.classList.contains('kanban-trash')) { return false; }
$('.kanban-trash').addClass('kanban-trash-active');
})
.on('out', function (el, target) {
if (!target.classList.contains('kanban-trash')) { return false; }
$('.kanban-trash').removeClass('kanban-trash-active');
})
.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 var id = Number($(el).attr('data-id'));
console.log("Drop " + $(el).attr("data-id") + " just before " + (sibling ? $(sibling).attr("data-id") : " end ")); var list = self.options.boards.list || [];
var index1, index2;
self.options.boards.some(function (element, index) { var index1 = list.indexOf(id);
if (element.id === $(el).attr("data-id")) { if (index1 === -1) { return; }
index1 = index;
return true; // Move to trash?
if (target.classList.contains('kanban-trash')) {
list.splice(index1, 1);
delete self.options.boards.data[id];
self.onChange();
return;
} }
});
if (sibling) { var index2;
self.options.boards.some(function (element, index) { var id2 = Number($(sibling).attr("data-id"));
if (element.id === $(sibling).attr("data-id")) { if (sibling && id2) {
index2 = index; index2 = list.indexOf(id2);
return true;
} }
}) // If we can't find the drop position, drop at the end
} else { if (typeof(index2) === "undefined" || index2 === -1) {
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(index1, 1);
list.splice(index2, 0, id);
// send event that board has changed // send event that board has changed
self.onChange(); self.onChange();
self.setBoards(self.options.boards);
}); });
//Init Drag Item //Init Drag Item
@ -148,7 +215,7 @@
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 (el.classList.contains('new-item')) { return false; } if (el.classList.contains('new-item')) { return false; }
return handle.classList.contains('kanban-item'); return el.classList.contains('kanban-item');
}, },
accepts: function (el, target, source, sibling) { accepts: function (el, target, source, sibling) {
if (self.options.readOnly) { return false; } if (self.options.readOnly) { return false; }
@ -163,93 +230,121 @@
// we need to calculate the position before starting to drag // we need to calculate the position before starting to drag
self.dragItemPos = self.findElementPosition(el); self.dragItemPos = self.findElementPosition(el);
setActiveDrag();
el.classList.add('is-moving'); el.classList.add('is-moving');
var boardJSON = __findBoardJSON(source.parentNode.dataset.id); $(document).on('mousemove', onMouseMove(el));
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') $(document).off('mousemove');
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('over', function (el, target, source) {
setActiveDrag(target);
if (!target.classList.contains('kanban-trash')) { return false; }
target.classList.add('kanban-trash-active');
})
.on('out', function (el, target) {
setActiveDrag();
if (!target.classList.contains('kanban-trash')) { return false; }
target.classList.remove('kanban-trash-active');
})
.on('drop', function(el, target, source, sibling) { .on('drop', function(el, target, source, sibling) {
self.enableAllBoards(); self.enableAllBoards();
el.classList.remove('is-moving'); el.classList.remove('is-moving');
console.log("In drop"); console.log("In drop");
// TODO: update board object board order var id1 = Number($(el).attr('data-eid'));
var board1;
self.options.boards.some(function (element) { // Move to trash?
if (element.id === $(source.parentNode).attr("data-id")) { if (target.classList.contains('kanban-trash')) {
return board1 = element; self.moveItem(id1);
} self.onChange();
}); return;
var board2;
self.options.boards.some(function (element) {
if (element.id === $(target.parentNode).attr("data-id")) {
return board2 = element;
} }
});
var pos1 = self.dragItemPos;
var pos2 = (sibling) ? self.findElementPosition(sibling) : (board2.item.length + 1);
console.log("Drop element " + pos1 + " before " + pos2);
// TODO: update board object item order // Find the new board
var targetId = Number($(target).closest('.kanban-board').data('id'));
if (!targetId) { return; }
var board2 = __findBoardJSON(targetId);
var id2 = $(sibling).attr('data-eid');
if (id2) { id2 = Number(id2); }
var pos2 = id2 ? board2.item.indexOf(id2) : board2.item.length;
if (pos2 === -1) { pos2 = board2.item.length; }
var allB = document.querySelectorAll('.kanban-board'); // Remove the "move" effect
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);
el.classList.remove('is-moving'); el.classList.remove('is-moving');
if (typeof (el.dropfn) === 'function')
el.dropfn(el, target, source, sibling);
} }
var item = board1.item[pos1]; // Move the item
// if (board1==board2 && pos2<pos1) self.moveItem(id1, board2, pos2);
// pos2 = pos2;
// moving element to target array
board1.item.splice(pos1, 1);
board2.item.splice(pos2 - 1, 0, item);
// send event that board has changed // send event that board has changed
self.onChange(); self.onChange();
self.setBoards(self.options.boards);
}) })
} }
}; };
var findItem = function (eid) {
var boards = self.options.boards;
var list = boards.list || [];
var res = [];
list.forEach(function (id) {
var b = boards.data[id];
if (!b) { return; }
var items = b.item || [];
var idx = items.indexOf(eid);
if (idx === -1) { return; }
// This board contains our item...
res.push({
board: b,
pos: idx
});
});
return res;
};
this.moveItem = function (eid, board, pos) {
var boards = self.options.boards;
var list = boards.list || [];
var from = [];
var same = -1;
var from = findItem(eid);
// Remove the item from its board
from.forEach(function (obj) {
obj.board.item.splice(obj.pos, 1);
if (obj.board === board) { same = obj.pos; }
});
// If it's a deletion, remove the item data
if (!board) {
delete boards.items[eid];
return;
}
// If it's moved to the same board at a bigger index, decrement the index by one
// (we just removed one element)
if (same !== -1 && same < pos) {
pos = pos - 1;
}
board.item.splice(pos, 0, eid);
};
this.enableAllBoards = function() { this.enableAllBoards = function() {
var allB = document.querySelectorAll('.kanban-board'); var allB = document.querySelectorAll('.kanban-board');
if (allB.length > 0 && allB !== undefined) { if (allB.length > 0 && allB !== undefined) {
@ -259,31 +354,84 @@
} }
}; };
this.addElement = function (boardID, element) { var getElementNode = function (element) {
// add Element to JSON
var boardJSON = __findBoardJSON(boardID);
boardJSON.item.push({
title: element.title
});
var board = self.element.querySelector('[data-id="' + boardID + '"] .kanban-drag');
var nodeItem = document.createElement('div'); var nodeItem = document.createElement('div');
nodeItem.classList.add('kanban-item'); nodeItem.classList.add('kanban-item');
if (element.id) { nodeItem.dataset.eid = element.id;
nodeItem.setAttribute('data-eid', element.id) if (element.color) {
} if (/color/.test(element.color)) {
// Palette color
nodeItem.classList.add('cp-kanban-palette-'+element.color);
} else {
// Hex color code
var textColor = self.options.getTextColor(element.color);
nodeItem.setAttribute('style', 'background-color:#'+element.color+';color:'+textColor+';');
}
}
var nodeCursors = document.createElement('div');
nodeCursors.classList.add('cp-kanban-cursors');
Object.keys(self.options.cursors).forEach(function (id) {
var c = self.options.cursors[id];
if (Number(c.item) !== Number(element.id)) { return; }
var el = self.options.getAvatar(c);
nodeCursors.appendChild(el);
});
var nodeItemText = document.createElement('div'); var nodeItemText = document.createElement('div');
nodeItemText.classList.add('kanban-item-text'); nodeItemText.classList.add('kanban-item-text');
nodeItemText.innerHTML = element.title; nodeItemText.dataset.eid = element.id;
nodeItemText.innerText = element.title;
nodeItem.appendChild(nodeItemText); nodeItem.appendChild(nodeItemText);
// Check if this card is filtered out
if (Array.isArray(self.options.tags) && self.options.tags.length) {
var hide = !Array.isArray(element.tags) ||
!element.tags.some(function (tag) {
return self.options.tags.indexOf(tag) !== -1;
});
if (hide) {
nodeItem.classList.add('kanban-item-hidden');
}
}
if (element.body) {
var html = self.renderMd(element.body);
var nodeBody = document.createElement('div');
nodeBody.classList.add('kanban-item-body');
nodeBody.onclick = function (e) {
e.preventDefault();
};
nodeBody.innerHTML = html;
nodeItem.appendChild(nodeBody);
}
if (Array.isArray(element.tags)) {
var nodeTags = document.createElement('div');
nodeTags.classList.add('kanban-item-tags');
element.tags.forEach(function (_tag) {
var tag = document.createElement('span');
tag.innerText = _tag;
nodeTags.appendChild(tag);
});
nodeItem.appendChild(nodeTags);
}
nodeItem.appendChild(nodeCursors);
//add function //add function
nodeItem.clickfn = element.click; nodeItem.clickfn = element.click;
nodeItem.dragfn = element.drag; nodeItem.dragfn = element.drag;
nodeItem.dragendfn = element.dragend; nodeItem.dragendfn = element.dragend;
nodeItem.dropfn = element.drop; nodeItem.dropfn = element.drop;
__onclickHandler(nodeItemText); __onclickHandler(nodeItemText);
__onColorClickHandler(nodeItem, "item"); return nodeItem;
board.appendChild(nodeItem); };
this.addElement = function (boardID, element) {
// add Element to JSON
var boardJSON = __findBoardJSON(boardID);
boardJSON.item.push(element.id);
self.options.boards.items = self.options.boards.items || {};
self.options.boards.items[element.id] = element;
var board = self.element.querySelector('[data-id="' + boardID + '"] .kanban-drag');
board.appendChild(getElementNode(element));
// send event that board has changed // send event that board has changed
self.onChange(); self.onChange();
return self; return self;
@ -295,34 +443,15 @@
return self; return self;
}; };
var getBoardNode = function (board) {
this.addBoards = function(boards) { var boards = self.options.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 buttonContent = self.options.buttonContent;
//for on all the boards
for (var boardkey in boards) {
// single board
var board = boards[boardkey];
if (self.options.boards !== boards)
self.options.boards.push(board);
//create node //create node
var boardNode = document.createElement('div'); var boardNode = document.createElement('div');
boardNode.dataset.id = board.id; boardNode.dataset.id = board.id;
boardNode.classList.add('kanban-board'); boardNode.classList.add('kanban-board');
var boardNodeInner = document.createElement('div');
boardNodeInner.classList.add('kanban-board-inner');
//set style //set style
if (self.options.responsivePercentage) { if (self.options.responsivePercentage) {
boardNode.style.width = boardWidth + '%'; boardNode.style.width = boardWidth + '%';
@ -333,78 +462,106 @@
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; if (/color/.test(board.color)) {
jscolorL = new jscolor(headerBoard,{showOnClick: false, valueElement:undefined}); // Palette color
jscolorL.fromString(board.color); headerBoard.classList.add('cp-kanban-palette-'+board.color);
headerBoard._jscLinkedInstance = undefined; boardNodeInner.classList.add('cp-kanban-palette-'+board.color);
} else if (!/^[0-9a-f]{6}$/.test(board.color)) {
// "string" color (red, blue, etc.)
headerBoard.classList.add("kanban-header-" + board.color); headerBoard.classList.add("kanban-header-" + board.color);
} else {
// Hex color code
var textColor = self.options.getTextColor(board.color);
headerBoard.setAttribute('style', 'background-color:#'+board.color+';color:'+textColor+';');
}
} }
titleBoard = document.createElement('div'); titleBoard = document.createElement('div');
titleBoard.classList.add('kanban-title-board'); titleBoard.classList.add('kanban-title-board');
titleBoard.innerHTML = board.title; titleBoard.innerText = board.title;
//titleBoard.setAttribute('title', board.title);
titleBoard.clickfn = board.boardTitleClick; titleBoard.clickfn = board.boardTitleClick;
__onboardTitleClickHandler(titleBoard); __onboardTitleClickHandler(titleBoard);
headerBoard.appendChild(titleBoard); headerBoard.appendChild(titleBoard);
__onColorClickHandler(headerBoard, "board");
// if add button is true, add button to the board var nodeCursors = document.createElement('div');
if (addButton) { nodeCursors.classList.add('cp-kanban-cursors');
var btn = document.createElement("BUTTON"); Object.keys(self.options.cursors).forEach(function (id) {
btn.setAttribute("class", "kanban-title-button btn btn-default btn-xs fa fa-times"); var c = self.options.cursors[id];
//var buttonHtml = '<button class="kanban-title-button btn btn-default btn-xs">'+buttonContent+'</button>' if (Number(c.board) !== Number(board.id)) { return; }
headerBoard.appendChild(btn); var el = self.options.getAvatar(c);
__onButtonClickHandler(btn, board.id); nodeCursors.appendChild(el);
} });
headerBoard.appendChild(nodeCursors);
//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];
var nodeItem = document.createElement('div'); if (!itemKanban) { return; } // XXX clean invalid data
nodeItem.classList.add('kanban-item'); var nodeItem = getElementNode(itemKanban);
nodeItem.dataset.eid = itemKanban.id;
var nodeItemText = document.createElement('div');
nodeItemText.classList.add('kanban-item-text');
nodeItemText.dataset.eid = itemKanban.id;
nodeItemText.innerHTML = itemKanban.title;
nodeItem.appendChild(nodeItemText);
//add function
nodeItemText.clickfn = itemKanban.click;
nodeItemText.dragfn = itemKanban.drag;
nodeItemText.dragendfn = itemKanban.dragend;
nodeItemText.dropfn = itemKanban.drop;
//add click handler of item
__onclickHandler(nodeItemText);
if (itemKanban.color !== '' && itemKanban.color !== undefined) {
jscolorL = new jscolor(nodeItem,{showOnClick: false, valueElement:undefined});
jscolorL.fromString(itemKanban.color);
}
__onColorClickHandler(nodeItem, "item");
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('span');
$(addBoardItem).addClass("kanban-title-button btn btn-default fa fa-plus"); addBoardItem.classList.add('kanban-title-button');
headerBoard.appendChild(addBoardItem); addBoardItem.innerText = '+';
footerBoard.appendChild(addBoardItem);
__onAddItemClickHandler(addBoardItem); __onAddItemClickHandler(addBoardItem);
//board assembly //board assembly
boardNode.appendChild(headerBoard); boardNode.appendChild(boardNodeInner);
boardNode.appendChild(contentBoard); boardNodeInner.appendChild(headerBoard);
boardNodeInner.appendChild(contentBoard);
boardNodeInner.appendChild(footerBoard);
return boardNode;
};
this.addBoard = function (board) {
if (!board || !board.id) { return; }
var boards = self.options.boards;
boards.data = boards.data || {};
boards.list = boards.list || [];
// If it already there, abort
boards.data[board.id] = board;
if (boards.list.indexOf(board.id) !== -1) { return; }
boards.list.push(board.id);
var boardNode = getBoardNode(board);
self.container.appendChild(boardNode);
};
this.addBoards = function() {
//for on all the boards
var boards = self.options.boards;
boards.list = boards.list || [];
boards.data = boards.data || {};
for (var index in boards.list) {
// single board
var boardkey = boards.list[index];
var board = boards.data[boardkey];
if (!board) { continue; } // XXX clean invalid data
var boardNode = getBoardNode(board);
//board add //board add
self.container.appendChild(boardNode); self.container.appendChild(boardNode);
} }
@ -416,13 +573,14 @@
} }
this.setBoards = function (boards) { this.setBoards = function (boards) {
self.element //self.element
for (var boardkey in this.options.boards) { for (var i in this.options.boards.list) {
var board = this.options.boards[boardkey]; var boardkey = this.options.boards.list[i];
this.removeBoard(board.id); this.removeBoard(boardkey);
} }
this.options.boards = []; this.options.boards = boards;
this.addBoards(boards); this.addBoards();
self.options.refresh();
} }
this.findBoard = function (id) { this.findBoard = function (id) {
@ -457,8 +615,13 @@
}; };
this.removeBoard = function (board) { this.removeBoard = function (board) {
if (typeof (board) === 'string') var id;
if (typeof (board) === 'string' || typeof (board) === "number") {
id = board;
board = self.element.querySelector('[data-id="' + board + '"]'); board = self.element.querySelector('[data-id="' + board + '"]');
} else if (board) {
id = board.id;
}
if (board) { if (board) {
board.remove(); board.remove();
@ -466,14 +629,15 @@
self.onChange(); self.onChange();
} }
// Remove duplicates
if (id) { $(self.element).find('.kanban-board[data-id="' + board + '"]').remove(); }
return self; return self;
} }
// board button on click function this.renderMd = function (md) {
this.onButtonClick = function (el) { return self.options.renderMd(md);
} }
this.onChange = function () { this.onChange = function () {
self.options.onChange(); self.options.onChange();
} }
@ -485,6 +649,9 @@
this.getBoardJSON = function (id) { this.getBoardJSON = function (id) {
return __findBoardJSON(id); return __findBoardJSON(id);
} }
this.getItemJSON = function (id) {
return (self.options.boards.items || {})[id];
};
//PRIVATE FUNCTION //PRIVATE FUNCTION
function __extendDefaults(source, properties) { function __extendDefaults(source, properties) {
@ -507,14 +674,24 @@
boardContainerOuter.appendChild(boardContainer); boardContainerOuter.appendChild(boardContainer);
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.innerText = '+';
boardContainer.appendChild(addBoard);
var trash = self.trashContainer = document.createElement('div');
trash.setAttribute('id', 'kanban-trash');
trash.setAttribute('class', 'kanban-trash');
var trashBg = document.createElement('div');
var trashIcon = document.createElement('i');
trashIcon.setAttribute('class', 'fa fa-trash');
trash.appendChild(trashIcon);
trash.appendChild(trashBg);
self.boardContainer.push(trash);
self.container = boardContainer; self.container = boardContainer;
//add boards //add boards
self.addBoards(self.options.boards); self.addBoards();
//appends to container //appends to container
self.element.appendChild(boardContainerOuter); self.element.appendChild(boardContainerOuter);
self.element.appendChild(addBoard); self.element.appendChild(trash);
// send event that board has changed // send event that board has changed
self.onChange(); self.onChange();
@ -539,17 +716,6 @@
}); });
} }
function __onColorClickHandler(nodeItem, type) {
nodeItem.addEventListener('click', function (e) {
if (Array.prototype.slice.call(nodeItem.classList).indexOf('is-moving') !== -1) {
return;
}
e.preventDefault;
e.stopPropagation();
self.options.colorClick(this, type);
});
}
function __onAddItemClickHandler(nodeItem, clickfn) { function __onAddItemClickHandler(nodeItem, clickfn) {
nodeItem.addEventListener('click', function (e) { nodeItem.addEventListener('click', function (e) {
e.preventDefault; e.preventDefault;
@ -560,24 +726,8 @@
}); });
} }
function __onButtonClickHandler(nodeItem, boardId) {
nodeItem.addEventListener('click', function (e) {
e.stopPropagation();
e.preventDefault;
self.options.buttonClick(this, boardId, e);
// if(typeof(this.clickfn) === 'function')
// this.clickfn(this);
});
}
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