JSFiddle - React, Tailwind, and code Playground

by pj_js15

HTML

<script src="//code.jquery.com/jquery-1.9.1.js"></script>
<script src="//code.jquery.com/ui/1.10.3/jquery-ui.js"></script>
<link rel="stylesheet" href="//code.jquery.com/ui/1.10.3/themes/smoothness/jquery-ui.css">
<div>
    <div class="sortable connectedSortable sortable-list" data-bind="sortable: firstList"></div>
    <div class="sortable connectedSortable sortable-list" data-bind="sortable: secondList"></div>
</div>

<div>
    <ul data-bind="foreach: firstList" class="sortable-list">
        <li data-bind="text: $data"></li>
    </ul>
    <ul data-bind="foreach: secondList" class="sortable-list">
        <li data-bind="text: $data"></li>
    </ul>
</div>

<div><pre data-bind="text: ko.toJSON($root, censor, '\t')"></pre></div>

CSS

.sortable-list {
    list-style-type: none;
    margin: 0;
    padding: 0 0 2.5em;
    float: left;
    margin-right: 10px;
    min-width: 100px;
    min-height: 20px;
}
.sortable-list li {
    margin: 0 5px 5px 5px;
    padding: 5px;
    font-size: 1.2em;
    width: 120px;
}
div:after {
    content:'';
    display:block;
    clear: both;
}
div {
    border: 1px dashed black;
    margin: 1em;
    padding: 1em;
}

JavaScript

ko.bindingHandlers.sortable = {
    init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
        var observable = valueAccessor();
        var $element = $(element);
        for (var i = 0; i < observable().length; i++) {
            $('<div>').addClass("ui-state-default").text(observable()[i]).appendTo($(element));
        }

        $element.sortable({
            connectWith: ".connectedSortable",
            update: function (event, ui) {
                var buffer = [];
                $element.children().each(function () {
                    buffer.push($(this).html());
                });
                observable(buffer);
            }
        }).disableSelection();
    },
    update: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
        // This will be called once when the binding is first applied to an element,
        // and again whenever the associated observable changes value.
        // Update the DOM element based on the supplied values here.
    }
};

function ViewModel() {
    var self = this;
    self.firstList = ko.observableArray(['item 1', 'item 2', 'item 3', 'item 4', 'item 5']);
    self.secondList = ko.observableArray(['item 6', 'item 7', 'item 8', 'item 9', 'item 10']);
    self.foo = { 'not-needed': 'this is not needed'};

    self.censor = function (key, value) {
        switch(key) {
            case 'secondList':
                return value;
            default:
                return undefined;
        }
    }
}

ko.applyBindings(new ViewModel());