Kick.js Draggable, droppable, and sortable list
by Ritesh Pahwa
HTML
<script src="https://cdn.jsdelivr.net/gh/radkick/kickjs/dist/kick.min.js"></script>
<div kick-app>
<div>
<div id="main">
<h2>High Priority Tasks</h2>
<div id="items1" class="items" :sort-list="highPriorityTasks">
<div class="item" *item="highPriorityTasks" :sort="setSort(item,highPriorityTasks)">
<a href="#" :="item.name" ^="selectTask(item)" -="show(item)"></a>
<input @="item.name" ^blur="blur(item)" +="show(item)" />
</div>
</div>
<!--<div class="container high" data-bind="template: { name: 'taskTmpl', foreach: highPriorityTasks, templateOptions: { parentList: highPriorityTasks} }, sortableList: highPriorityTasks"></div>-->
<h2>Tasks</h2>
<div id="items2" class="items" :sort-list="normalPriorityTasks">
<div class="item" *item="normalPriorityTasks" :sort="setSort(item,normalPriorityTasks)">
<a href="#" :="item.name" ^="selectTask(item)" -="item.show"></a>
<input @="item.name" ^blur="blur(item)" +="item.show" />
</div>
</div>
<a href="#" ^="addTask">Add Task</a>
<h2>Trash Bin</h2>
<div class="items container" :sort-list="trash">
</div>
</div>
<div id="results">
<h2>High Priority Tasks</h2>
<ul>
<li *item="highPriorityTasks" :="item.name" />
</ul>
<hr>
<h2>Tasks</h2>
<ul>
<li *item="normalPriorityTasks" :="item.name" />
</ul>
<h2>Bin</h2>
<ul>
<li *item="trash" :="item.name" />
</ul>
</div>
</div>
</div>
<!-- Not used from ko example -->
<script id="taskTmpl" type="text/html">
<div class="item" data-bind="sortableItem: { item: $data, parentList: $item.parentList }">
<a href="#" data-bind="text: name, click: function() { viewModel.selectTask($data); }, visible: $data !== viewModel.selectedTask()"></a>
<input data-bind="value: name, visibleAndSelect: $data === viewModel.selectedTask(), event: { blur: function() {...
CSS
body {
font-family: arial;
}
h2 {
font-weight: bold;
}
div {
padding: 5px;
margin: 5px;
border: #eee 1px solid;
}
p,
a {
font-size: .8em;
}
ul {
padding-bottom: 10px;
}
.container {
width: 125px;
min-height: 50px;
background-color: #AAA;
}
.high {
background-color: red;
}
.trash {
background-color: #000;
}
.item {
background-color: #DDD;
cursor: move;
}
.item input {
width: 100px;
}
#main {
float: left;
}
#results {
margin-left: 175px;
width: 150px;
}
JavaScript
var vm = {
highPriorityTasks: [{
name: "Get dog food"
},
{
name: "Mow lawn"
},
{
name: "Fix car"
}
],
normalPriorityTasks: [{
name: "Fix fence"
},
{
name: "Walk dog"
},
{
name: "Read book"
}
],
setSort: function(item, list) {
return {
item: item,
list: list
};
},
selectedTask: null,
blur: function(item) {
vm.selectTask = null;
item.show = false;
},
selectTask: function(task, sel) {
vm.selectedTask = task;
task && (task.show = true);
},
show: function(item) {
item !== vm.selectedTask;
},
addTask: function() {
var task = {
name: "new",
show: true
};
vm.selectedTask = task;
vm.normalPriorityTasks.push(task);
},
trash: []
};
kick.binders[':sort-list'] = function(el, list) {
$(el).data("list", list)
.sortable({
revert: true,
helper: function(e, u) {
return $('<div class="item"></div>')
},
stop: function(event, ui) {
var item = ui.item.data("item");
if (item) {
//identify parents
var originalParent = ui.item.data("list");
var newParent = ui.item.parent().data("list");
//figure out its new position
var position = ui.item.parent().children().index(ui.item);
if (position >= 0) {
// Cancel is important it helps in keeping the item attached to binder element
// https://stackoverflow.com/questions/14199681/jquery-ui-sortable-move-clone-but-keep-original
$(this).sortable('cancel');
originalParent.splice(originalParent.indexOf(item), 1);
if(newParent){newParent.splice(position, 0, item);}
ui.item.data("list", newParent);
}
ui.item.remove();
}
},
connectWith: '.items'
});
}
kick.binders[':sort'] = function(el, v) {
$(el).data("item", v.item);
$(el).data("list", v.list);
...