KnockOut JS drag drop
by amitava82
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>
<script src="http://ajax.cdnjs.com/ajax/libs/json2/20110223/json2.js"></script>
<a href="#" data-bind="viewer: $root">Debug</a>
<hr/>
<div>Seating Assignments</div>
<div class="note">Rules: no more than 4 students per table. Must have at least one student of each gender at a full table.</div>
<div id="main" data-bind="foreach: tables">
<div class="table">
<span data-bind="text: students.id"></span>
<div class="seats" data-bind="sortable: { data: students, allowDrop: $root.isTableFull }">
<div class="student" data-bind="text: name"></div>
</div>
<div class="count" data-bind="text: students().length + '/' + $root.maximumStudents, css: { ready: students().length < $root.maximumStudents }"></div>
</div>
</div>
<div id="extra">
<div>Available Students</div>
<div class="new" data-bind="sortable: availableStudents">
<div class="student" data-bind="text: name"></div>
</div>
</div>
<div id="message" data-bind="flash: lastAction"></div>
<div id="error" data-bind="flash: lastError"></div>
CSS
body {
font-family: arial;
}
.table {
float: left;
text-align: center;
margin-right: 5px;
}
.table span {
font-size: .75em;
}
.seats {
border: solid 3px #666;
width: 75px;
height: 100px;
background-color: #666;
margin: 5px;
padding: 2px;
border-radius: 5px;
box-shadow: 2px 2px 2px #999;
}
.ko_container {
border: solid 3px green;
}
.student {
background-color: #444;
color: #fff;
border-radius: 3px;
margin: 2px;
padding: 1px;
text-align: center;
width: 70px;
cursor: move;
}
.new {
border: solid 1px #444;
background-color: #ccc;
height: 25px;
width: 500px;
padding: 2px;
border-radius: 5px;
}
.new div {
float: left;
}
.note {
font-style: italic;
font-size: .75em;
color: #888;
margin-bottom: 10px;
}
.count {
color: #666;
}
.ready {
color: green;
}
#extra {
clear: both;
padding-top: 20px;
}
#master {
margin-top: 40px;
}
#master td, th {
font-size: .75em;
text-align: center;
padding: 1px;
border: solid 1px black;
}
#master th {
color: #666;
}
#message, #error {
font-size: .75em;
margin-top: 10px;
background-color: orange;
color: #444;
padding: 2px;
width: 500px;
text-align: center;
border-radius: 5px;
box-shadow: 2px 2px 2px #999;
position: absolute;
}
#error {
background-color: #ff3333;
color: #ddd;
}
JavaScript
ko.bindingHandlers.viewer = {
init: function(element, valueAccessor) {
var win,
updateText = function(content) {
var el = win.document.getElementById("output");
el['innerText' in el ? 'innerText' : 'textContent'] = content;
};
ko.utils.registerEventHandler(element, "click", function(event) {
win = win || window.open();
win.document.writeln("<pre id='output'></pre>");
updateText(JSON.stringify(ko.toJS(valueAccessor()), null, 2));
});
//set up a throttled computed observable to handle updates
ko.computed({
read: function() {
//make sure we have a subscription to all observables in valueAccessor()
var content = JSON.stringify(ko.toJS(valueAccessor()), null, 2);
if (win) {
if (!win.closed) {
updateText(content);
} else {
//clear it out
win = null;
}
}
},
disposeWhenNodeIsRemoved: element
}).extend({ throttle: 1 });
}
};
ko.bindingHandlers.flash = {
init: function(element) {
$(element).hide();
},
update: function(element, valueAccessor) {
var value = ko.utils.unwrapObservable(valueAccessor());
if (value) {
$(element).stop().hide().text(value).fadeIn(function() {
clearTimeout($(element).data("timeout"));
$(element).data("timeout", setTimeout(function() {
$(element).fadeOut();
valueAccessor()(null);
}, 3000));
});
}
},
timeout: null
};
var Student = function(id, name, gender) {
this.id = id;
this.name = ko.observable(name);
this.gender = gender;
};
var Table = function(id,...