LinkedIn Inbox "To"-field

Emulating the LinkedIn mailbox recipient field logic

by Asle Gundersby

HTML

<script src="http://knockoutjs.com/downloads/knockout-3.2.0.js"></script>
<div class="composeFrame">
    <ul class="composeForm">
    <li class="composeForm">
        <ul class="inline" data-bind="foreach: $root.Recipients">
            <!— recipientTemplate —>
		    <li class="inline recipient">
		    	<img data-bind="attr:{ src: profilePhoto()}"/>
		    	<span data-bind="text: displayName">name</span>
                <span class="remove" data-bind="click:$root.removeRecipient">&#10008;</span>
	    	</li>
        </ul>
        <!--
        <input size="1" placeholder="&lt;To &gt;" 
               class="recipient-input" 
               data-bind="autoComplete: { selected: selectedOption, options: $root.Users },
                   textInput: $root.recipient,
                   event: {keyup: $root.addRecipient}"/>    
        -->
        <input  class="recipient-input"  size="1" placeholder="&lt;To&gt;" data-bind="jqAuto: { autoFocus: true }, 
                                                              jqAutoSource: $root.Recipients, 
                                                              jqAutoValue: $root.recipient, 
                                                              jqAutoSourceLabel: 'displayName', 
                                                              jqAutoSourceInputValue: 'displayName', 
                                                              jqAutoSourceValue: 'displayName',
                                                              textInput: $root.recipient, 
                                                              event: {keyup: $root.addRecipient}" />   
    </li>
    
</ul>
</div>
<hr>
    
<div class="Frame">
    <ul data-bind="foreach: Recipients">
        <li>
            <img data-bind="attr:{ src: profilePhoto()}"/>
		    	<span data-bind="text: displayName">name</span>
                <span class="remove" data-bind="click:$root.removeRecipient">&#10008;</span>
        </li>
    </ul>        
    <input...

CSS

body{
    background: #efefef;
}
.composeFrame{
   padding:2px;
    border: 1px solid blue;
}
ul li {
    list-style: none;
}


li.composeForm{
    padding:5px;
    border: 1px solid red;
    margin-left: -40px;
    height: 30px;
    height: auto;
    display: block;
    background:white;
}

.inline {
    display:inline;
    float: left;
    padding: 0px;
    margin: 0px;
    margin-left: -3px;
}

li.inline.recipient{
    border: 1px solid #aaa;
    height: auto;
    width: auto;
    display: inline-block;
    background: lightyellow;
    font-weight: bold;
    margin-left:3px;
    margin-right:0px;
}
li.inline.recipient img{
    width: 24px;
    height: 24px;
    margin: 1px 3px 1px 1px;
    position: relative;
    float: left;
}
li.inline.recipient span{
    margin: 10px 0px 0px 0xp;
    line-height:26px
}
li.inline.recipient span.remove{
    content: '&#10008'; /* why doesn't this work? */
    font-size: 13px;
    color: red;
    background: #fff;
    width:14px;
    height: 14px;
    margin: 0px 2px 0px;
    border: 0px solid red;
    height: 16px;
    position:relative;
    top:-4px;    
    padding:0px; 
    cursor: pointer;
    background:transparent;
}

.recipient-input{
    height: 22px;
    min-width: 34px;
    max-width: 248px;
    z-index:12;
    margin-left: 5px;
    border:none;
    margin-top: 2px;
    font-size: 14px;
}
.recipient-input:focus{
    outline: 0;
}
/*-------------- Frame ------------*/
.Frame{
    position: relative;
    border: 1px solid blue;
    background: white;
    padding: 1px 2px;
    display: inline-block;
    width:100%;
}
.Frame ul{
    margin: 0px;
    padding: 0px
}
.Frame ul li{
    float: left;
    list-style: none;
    border: 1px solid #aaa;
    margin-top:2px; 
    margin-right:0px;
    margin-bottom:2px; 
    margin-left: 5px;
        background: lightyellow;
    height: 22px;
    height: auto;
    font-weight: bold;
}

.Frame ul li img{
    float: left;
    width: 24px;
    height: 24px;
    vertical-align:...

JavaScript

//--------------------------------------------------------------------------------------jqAuto (R. Niemeyer)......
    //
    // Usage:
    //
    //       <input data-bind="jqAuto: { autoFocus: true }, jqAutoSource: myPeople, jqAutoValue: mySelectedGuid, jqAutoSourceLabel: 'displayName', jqAutoSourceInputValue: 'name', jqAutoSourceValue: 'guid'" />
    //
    //
    //


    //jqAuto -- main binding (should contain additional options to pass to autocomplete)
    //jqAutoSource -- the array of choices
    //jqAutoValue -- where to write the selected value
    //jqAutoSourceLabel -- the property that should be displayed in the possible choices
    //jqAutoSourceInputValue -- the property that should be displayed in the input box
    //jqAutoSourceValue -- the property to use for the value
    ko.bindingHandlers.jqAuto = {
        init: function (element, valueAccessor, allBindingsAccessor, viewModel) {
            var options = valueAccessor() || {},
                allBindings = allBindingsAccessor(),
                unwrap = ko.utils.unwrapObservable,
                modelValue = allBindings.jqAutoValue,
                source = allBindings.jqAutoSource,
                valueProp = allBindings.jqAutoSourceValue,
                inputValueProp = allBindings.jqAutoSourceInputValue || valueProp,
                labelProp = allBindings.jqAutoSourceLabel || valueProp;

            //function that is shared by both select and change event handlers
            function writeValueToModel(valueToWrite) {
                if (ko.isWriteableObservable(modelValue)) {
                    modelValue(valueToWrite);
                } else {  //write to non-observable
                    if (allBindings['_ko_property_writers'] && allBindings['_ko_property_writers']['jqAutoValue'])
                        allBindings['_ko_property_writers']['jqAutoValue'](valueToWrite);
                }
            }

            //on a selection write the proper value to the model
           ...