162 lines
4.9 KiB
HTML
162 lines
4.9 KiB
HTML
|
<!DOCTYPE html>
|
||
|
<html>
|
||
|
<head>
|
||
|
<meta charset="utf-8">
|
||
|
<title>Kanban Board</title>
|
||
|
<style>
|
||
|
#board {
|
||
|
display: table;
|
||
|
margin: 0;
|
||
|
padding: 0;
|
||
|
border-spacing: 5px;
|
||
|
}
|
||
|
.section {
|
||
|
display: table-cell;
|
||
|
margin: 0;
|
||
|
border: 1px solid #666;
|
||
|
padding: 5px;
|
||
|
width: 300px;
|
||
|
}
|
||
|
.section.droppable {
|
||
|
border: 1px dashed #666;
|
||
|
}
|
||
|
.section > h1 {
|
||
|
margin: 0;
|
||
|
border-bottom: 1px solid #999;
|
||
|
padding: 0;
|
||
|
font-size: 12pt;
|
||
|
text-align: center;
|
||
|
}
|
||
|
.card {
|
||
|
display: inline-block;
|
||
|
vertical-align: top;
|
||
|
margin: 10px 5px;
|
||
|
padding: 10px;
|
||
|
width: 100px;
|
||
|
height: 100px;
|
||
|
color: black;
|
||
|
background: #ff8;
|
||
|
cursor: move;
|
||
|
text-align: center;
|
||
|
font-family: "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif;
|
||
|
box-shadow: 2px 2px 2px #eee;
|
||
|
}
|
||
|
</style>
|
||
|
</head>
|
||
|
<body>
|
||
|
<h1>Kanban Board</h1>
|
||
|
|
||
|
<div id="board">
|
||
|
<div id="todo" class="section">
|
||
|
<h1>To Do</h1>
|
||
|
<div id="c2" class="card">Make Killer App</div>
|
||
|
<div id="c3" class="card"><em>Retire!</em></div>
|
||
|
</div>
|
||
|
<div id="doing" class="section">
|
||
|
<h1>Doing</h1>
|
||
|
<div id="c1" class="card">Learn HTML5</div>
|
||
|
</div>
|
||
|
<div id="done" class="section">
|
||
|
<h1>Done</h1>
|
||
|
</div>
|
||
|
</div>
|
||
|
|
||
|
<script>
|
||
|
var cards = document.querySelectorAll('.card');
|
||
|
|
||
|
for (var i = 0, n = cards.length; i < n; i++) {
|
||
|
var card = cards[i];
|
||
|
card.draggable = true;
|
||
|
};
|
||
|
|
||
|
var board = document.getElementById('board');
|
||
|
|
||
|
var hideMe;
|
||
|
|
||
|
board.onselectstart = function(e) {
|
||
|
e.preventDefault();
|
||
|
}
|
||
|
|
||
|
board.ondragstart = function(e) {
|
||
|
console.log('dragstart');
|
||
|
hideMe = e.target;
|
||
|
e.dataTransfer.setData('card', e.target.id);
|
||
|
e.dataTransfer.effectAllowed = 'move';
|
||
|
};
|
||
|
|
||
|
board.ondragend = function(e) {
|
||
|
e.target.style.visibility = 'visible';
|
||
|
};
|
||
|
|
||
|
var lastEneterd;
|
||
|
|
||
|
board.ondragenter = function(e) {
|
||
|
console.log('dragenter');
|
||
|
if (hideMe) {
|
||
|
hideMe.style.visibility = 'hidden';
|
||
|
hideMe = null;
|
||
|
}
|
||
|
// Save this to check in dragleave.
|
||
|
lastEntered = e.target;
|
||
|
var section = closestWithClass(e.target, 'section');
|
||
|
// TODO: Check that it's not the original section.
|
||
|
if (section) {
|
||
|
section.classList.add('droppable');
|
||
|
e.preventDefault(); // Not sure if these needs to be here. Maybe for IE?
|
||
|
return false;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
board.ondragover = function(e) {
|
||
|
// TODO: Check data type.
|
||
|
// TODO: Check that it's not the original section.
|
||
|
if (closestWithClass(e.target, 'section')) {
|
||
|
e.preventDefault();
|
||
|
}
|
||
|
};
|
||
|
|
||
|
board.ondragleave = function(e) {
|
||
|
// FF is raising this event on text nodes so only check elements.
|
||
|
if (e.target.nodeType === 1) {
|
||
|
// dragleave for outer elements can trigger after dragenter for inner elements
|
||
|
// so make sure we're really leaving by checking what we just entered.
|
||
|
// relatedTarget is missing in WebKit: https://bugs.webkit.org/show_bug.cgi?id=66547
|
||
|
var section = closestWithClass(e.target, 'section');
|
||
|
if (section && !section.contains(lastEntered)) {
|
||
|
section.classList.remove('droppable');
|
||
|
}
|
||
|
}
|
||
|
lastEntered = null; // No need to keep this around.
|
||
|
};
|
||
|
|
||
|
board.ondrop = function(e) {
|
||
|
var section = closestWithClass(e.target, 'section');
|
||
|
var id = e.dataTransfer.getData('card');
|
||
|
if (id) {
|
||
|
var card = document.getElementById(id);
|
||
|
// Might be a card from another window.
|
||
|
if (card) {
|
||
|
if (section !== card.parentNode) {
|
||
|
section.appendChild(card);
|
||
|
}
|
||
|
} else {
|
||
|
alert('couldn\'t find card #' + id);
|
||
|
}
|
||
|
}
|
||
|
section.classList.remove('droppable');
|
||
|
e.preventDefault();
|
||
|
};
|
||
|
|
||
|
function closestWithClass(target, className) {
|
||
|
while (target) {
|
||
|
if (target.nodeType === 1 &&
|
||
|
target.classList.contains(className)) {
|
||
|
return target;
|
||
|
}
|
||
|
target = target.parentNode;
|
||
|
}
|
||
|
return null;
|
||
|
}
|
||
|
</script>
|
||
|
</body>
|
||
|
</html>
|