Accordion 2ways draggable-droppable

Finally!!!! :D

by Asle Gundersby

HTML

<link rel="stylesheet" href="http://jqueryui.com/resources/demos/style.css">
<link rel="stylesheet" href="http://code.jquery.com/ui/1.11.2/themes/smoothness/jquery-ui.css">
<script src="http://knockoutjs.com/downloads/knockout-2.2.1.js"></script>
Main array:
<div id="accordion" class="group ui-widget ui-helper-clearfix" data-bind="jqAccordion: { target: '#parking', source: '#accordion' },template: { name: 'scene-template', foreach: Scenes}"></div>

Park scene(s) here:
<div id="parking" class="group ui-widget ui-helper-clearfix" data-bind="jqAccordion: { target: '#accordion', source: '#parking' },template: { name: 'scene-template', foreach: parkedScenes}"></div>
<hr/>

Items in parkedScenes: <span data-bind="text: $root.parkedScenes().length"></span>


<pre data-bind="text: ko.toJSON($root, null, 2)"></pre>
<!---------------- scene-template: begin --------------------------->
<script type="text/html" id="scene-template"><div data-bind="attr: {'id': 'scene' + sceneID}" class="ui-widget-content">
        <div class="accordion-header ui-widget-header" > 
            <span data-bind="text:sceneID"></span>
            <input data-bind="value:title"></input>
        </div>
		<div class="ui-widget-content">
            <textarea data-bind="text:text"></textarea>
        </div>                    
    </div></script>
<!------------------ scene-template: end ---------------------------->

CSS

#accordion{
    min-height: 40px; 
    border: 2px solid blue;
    margin: 0px 0px 10px 0px;
}
#parking{
    min-height: 40px;
    border: 2px solid red;
    margin: 0px 0px 10px 0px;
    background: cornflowerblue;
}

#droppable { 
    width: 150px; height: 150px; 
    padding: 0.5em; float: left; 
    margin: 10px; 
}
#draggable, #draggable-nonvalid { 
    width: 100px; height: 100px; 
    padding: 0.5em; float: left; 
    margin: 10px 10px 10px 0px; 
}

JavaScript

(function () {
    
    var ITEMKEY = "ko_sortItem",
        INDEXKEY = "ko_sourceIndex",
        LISTKEY = "ko_sortList",
        PARENTKEY = "ko_parentList",
        DRAGKEY = "ko_dragItem",
        unwrap = ko.utils.unwrapObservable,
        dataGet = ko.utils.domData.get,
        dataSet = ko.utils.domData.set;

    //internal afterRender that adds meta-data to children
    var addMetaDataAfterRender = function (elements, data) {
        ko.utils.arrayForEach(elements, function (element) {
            if (element.nodeType === 1) {
                dataSet(element, ITEMKEY, data);
                dataSet(element, PARENTKEY, dataGet(element.parentNode, LISTKEY));
            }
        });
    };

    //prepare the proper options for the template binding
    var prepareTemplateOptions = function (valueAccessor, dataName) {
        var result = {},
            options = unwrap(valueAccessor()),
            actualAfterRender;

        //build our options to pass to the template engine
        if (options.data) {
            result[dataName] = options.data;
            result.name = options.template;
        } else {
            result[dataName] = valueAccessor();
        }

        ko.utils.arrayForEach(["afterAdd", "afterRender", "as", "beforeRemove", "includeDestroyed", "templateEngine", "templateOptions"], function (option) {
            result[option] = options[option] || ko.bindingHandlers.jqAccordion[option];
        });

        //use an afterRender function to add meta-data
        if (dataName === "foreach") {
            if (result.afterRender) {
                //wrap the existing function, if it was passed
                actualAfterRender = result.afterRender;
                result.afterRender = function (element, data) {
                    addMetaDataAfterRender.call(data, element, data);
                    actualAfterRender.call(data, element, data);
                };
            } else {
                result.afterRender =...