D´n´D-TAGS v4 The Tomalak rewrite ASG-adapted

https://github.com/rniemeyer/knockout-sortable

by Asle Gundersby

HTML

<script src="http://knockoutjs.com/downloads/knockout-3.2.0.js"></script>
<script src="https://rawgithub.com/rniemeyer/knockout-sortable/master/build/knockout-sortable.js"></script>
<div class="tag-container">
    <input class="taginput" placeholder="&lt;add a tag&gt;" data-bind="
        autoComplete: { selected: selectedOption, options: options },
        textInput: tagname, 
        event: {keyup: inputTag}
    " />
    <h3>Selected Tags</h3>
    <!-- ko template: {
        name: 'template-taglist',
        data: {
            taglist: selectedTags(),
            updateHandler: selectViajQUI
        }
    } --><!-- /ko -->
</div>

<div class="tag-container">
    <h3>Available Tags</h3>
    <!-- ko template: {
        name: 'template-taglist',
        data: {
            taglist: availableTags(),
            updateHandler: deselectViajQUI
        }
    } --><!-- /ko -->
</div>

<script type="text/html" id="template-tag">
    <div class="tag" data-bind="css: {selected: isSelected}">
        <span class="tag-action" data-bind="click: toggleSelected, text: isSelected() ? 'x' : '+'"></span>
        <span class="tag-text" data-bind="text: text"></span>
    </div>
</script>

<script type="text/html" id="template-taglist">
    <div class="tag-table">
        <div class="tag-list" data-bind="
            sortable: {
                template: 'template-tag',
                data: taglist,
                allowDrop: true,
                options: { update: updateHandler }
            }
        "></div>
    </div>
</script>


<pre data-bind="text: ko.toJSON($root.tagname, null, 2)"></pre>

CSS

body {
    font-family: arial;
    background: lightgrey;
}
p, a, input {
    font-size: .8em;
}
.ko_container {
    width: auto;
    min-width: 25px;
    min-height: 25px;
    border: 1px dotted;
    padding: 2px;
}
.tag-container {
    width: 350px;
    margin-top: 5px;
    margin-left: 5px;
    padding: 2px;
    border: black 1px solid;
}
.tag-container h3 {
    text-align: left;
    font-weight: bold;
    margin-bottom: 4px;
}
.tag-container input.taginput {
    float: right;
    position: relative;
    background: lightyellow;
    font-size: 10px;
    min-width: 20px;
    width: auto;
    max-width: 80px;
    margin: 0px 1px 2px 10px;
    border: 1px solid grey;
    padding: 1px;
}
.tag-table {
    background-color: lightblue;
    margin: -2px;
    padding: 1px;
    border-radius: 0px;
}
.tag-list {
    height: auto;
    margin: 1px;
    padding: 1px;
    overflow-y: auto;
    clear: both;
}
.tag {
    float: left;
    background-color: #444;
    color: #fff;
    border-radius: 3px;
    margin: 1px;
    padding: 2px 3px;
    cursor: move;
    white-space: nowrap;
}
.tag .tag-action {
    display: inline-block;
    width: 0.5em;
    cursor: pointer;
    text-align: center;
    vertical-align: middle;
    /* text-shadow: rgba(255,255,255,0.5) 1px 1px;*/
     font-size: 12px;
}
.tag .tag-action {
    color: lime;
    font-weight:400;
}
.tag.selected .tag-action {
    color: red;
    font-weight:400;
    vertical-align: top;
}

JavaScript

ko.bindingHandlers.autoComplete = {
    // Only using init event because the Jquery.UI.AutoComplete widget will take care of the update callbacks
    init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
        var settings = valueAccessor();
        var selectedOption = settings.selected;
        var options = settings.options;

        var updateElementValueWithLabel = function (event, ui) {
            // Stop the default behavior
            event.preventDefault();

            // Update the value of the html element with the label of the activated option (ui.item)
            //$(element).val(ui.item.label); // This does not udate our 'tagname' observable 
            bindingContext.$root.tagname(ui.item.label);
            
            // Update our SelectedOption observable
            if(typeof ui.item !== "undefined") {
                // ui.item - label|value|...
                selectedOption(ui.item);
            }
        };

        $(element).autocomplete({
            source: options,
            select: function (event, ui) {
                updateElementValueWithLabel(event, ui);
                //alert("select: event,ui.item.label="+event+"/"+ui.item.label);         
            },
            focus: function (event, ui) {
                updateElementValueWithLabel(event, ui);
            },
            change: function (event, ui) {
                updateElementValueWithLabel(event, ui);
            }
        });
    },
    update: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
    //what to do here?
    // this is never called after initialization... hmm
        
    // Update the observable with the label of the activated option (ui.item)
         //$(element).val(ui.item.label);
        //bindingContext.$root.tagname(ui.item.label);
    }
};
//----------------------------------------- bindingHandlers above….

/* global ko */

String.prototype.trim = function () {
    return...