knockout + jQuery UI sortable
by mgrcic
HTML
<script src="https://github.com/downloads/SteveSanderson/knockout/knockout-2.0.0.debug.js"></script>
<script src="https://github.com/downloads/rniemeyer/knockout-sortable/knockout-sortable.js"></script>
<link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.17/themes/cupertino/jquery-ui.css">
<div class="demo">
<div class="column-parent">
<h1 class="column-header">High</h1>
<div class="column" data-bind="sortable: highPriorityTasks">
<div class="portlet">
<div class="portlet-header" data-bind="text: name"></div>
<div class="portlet-content"></div>
</div>
</div>
</div>
<div class="column-parent">
<h1 class="column-header">Normal</h1>
<div class="column" data-bind="sortable: normalPriorityTasks">
<div class="portlet">
<div class="portlet-header" data-bind="text: name"></div>
<div class="portlet-content"></div>
</div>
</div>
</div>
</div>
<hr/>
<ul data-bind="foreach: allTasks">
<li>
<span data-bind="text: name"></span> -
<span data-bind="text: priority"></span>
</li>
</ul>
CSS
.demo { font-size:12px; font-family:sans-serif; width:80%; margin:auto; }
.column-parent { width: 100px; float: left; padding-bottom: 100px; }
.column { padding-bottom: 100px; }
.column-header { text-align:center; font-size: 14px; }
.portlet { margin: 0 1em 1em 0; }
.portlet-header { margin: 0.3em; padding-bottom: 4px; padding-left: 0.2em; }
.blocked { background: #F38585; border: red !important;}
.portlet-header .ui-icon { float: right; }
.portlet-content { padding: 0.4em; }
.ui-sortable-placeholder { border: 1px dotted black; visibility: visible !important; height: 50px !important; }
#status {position: fixed; top:0px, left:0px; background: gray; padding: 5px;}
.ui-sortable-placeholder * { visibility: hidden; }
JavaScript
var Task = function (name, priority) {
this.name = ko.observable(name);
this.priority = ko.observable(priority);
};
var initialData = [
new Task("Get dog food", "high"),
new Task("Mow lawn", "high"),
new Task("Fix car", "high"),
new Task("Fix fence", "normal"),
new Task("Walk dog", "normal"),
new Task("Read book", "normal")
];
var ViewModel = function () {
var self = this;
self.highPriorityTasks = ko.observableArray(ko.utils.arrayFilter(initialData, function(task) {
return task.priority() === "high";
}));
self.highPriorityTasks.priority = "high";
self.normalPriorityTasks = ko.observableArray(ko.utils.arrayFilter(initialData, function(task) {
return task.priority() === "normal";
}));
self.normalPriorityTasks.priority = "normal";
self.allTasks = ko.computed(function() {
var result = [];
ko.utils.arrayPushAll(result, self.highPriorityTasks());
ko.utils.arrayPushAll(result, self.normalPriorityTasks());
return result;
});
};
$( ".portlet" ).addClass( "ui-widget ui-widget-content ui-helper-clearfix ui-corner-all" )
.find( ".portlet-header" )
.addClass( "ui-widget-header ui-corner-all" )
.prepend( "<span class='ui-icon ui-icon-minusthick'></span>")
.end()
.find( ".portlet-content" );
$( ".portlet-header .ui-icon" ).click(function() {
$( this ).toggleClass( "ui-icon-minusthick" ).toggleClass( "ui-icon-plusthick" );
$( this ).parents( ".portlet:first" ).find( ".portlet-content" ).toggle();
});
$( ".column" ).disableSelection();
ko.bindingHandlers.sortable.afterMove = function(arg) {
arg.item.priority(arg.targetParent.priority);
};
ko.applyBindings(new ViewModel());