<!DOCTYPE html>
<html>
  <head>
  </head>
  <body>
    <application></application>
    
    <script type="text/javascript" src="https://rawgit.com/riot/riot/master/riot+compiler.js"></script>
    <script type="riot/tag" src="./picker.js"></script>
    <script type="riot/tag" src="./application.js"></script>
    
    <script src="./arrayhelper.js"></script>
    
    <link rel="stylesheet" href="./style.css">
    
    <script type="text/javascript">
      riot.mount('*');
    </script>

  </body>
</html>
<picker>
	<div class="picked-items">
		<span if={item.selected} each={item in items}>
			{item[mainLabel]}
		</span>
		<input onkeyup={filter} onfocus={openList} type="text">
	</div>
	<div if={isPicking} class="picker-list">
		<a onclick={closeList}>&times;</a>
        <table>
        	<tr>
        		<th each={label in labels}>{label}</th>
        	</tr>
        	<tr if={!item.filtered} class={selected: item.selected} onclick={pick} each={item in items}>
        		<td each={label in labels}>
        			{item[label]}
        		</td>
        	</tr>
        </table>
	</div>
	<script>
	    this.mixin(arrayhelper)
	    
		this.isPicking = false
		openList() {
			this.isPicking = true
		}

		closeList() {
			this.isPicking = false
		}
		
		pick(event) {
		    event.item.item.selected = !event.item.item.selected
		    this.trigger('picked', this.items.filter(function(item){return item.selected}))
		}
		
		filter(event) {
            this.filterByLabels(this.items, this.labels, event.target.value)
            this.trigger('filtered', this.items.filter(function(item){return !item.filtered}))
		}
		
		
        this.items = opts.items
        this.labels = opts.labels || Object.keys(this.items[0])
        this.mainLabel = opts.mainLabel || this.labels[0]
	</script>
</picker>
body
{
    font-family: verdana;
    padding: 2em;
}

.picker-list a
{
    position: absolute;
    cursor: pointer;
    font-size: 1.25em;
    right: .5em;
    top: .5em;
}

.picker-list
{
    position: relative;
    display: inline-block;
    background: #EEE;
}

.picker-list table
{
    cursor: pointer;
    margin-top: 1em;
}

.picker-list table tr:nth-child(odd)
{
    background: #DDD;
}

table td
{
    padding: .4em;
}

.picker-list table
{
    border-collapse: collapse;
}

.picked-items span
{
    margin-right: .5em;
    margin-bottom: .2em;
    padding: .1em;
    display: inline-block;
}

.selected, .picked-items span
{
    background: #3377B5;
    color: #F1F1F1;
}

.picker-list .selected:nth-child(odd)
{
    background: #4488C6;
}

input
{
    display: block;
}
<application>
    <h2>Select Authors for this lesson</h2>
    <small if={authorFilter.length}>filtered {authorFilter.length}</small>
    <small if={authorPicks.length}>picked {authorPicks.length}</small>
    <picker name="authorPicker" items={lessonUsers} labels={['name', 'email', 'country']}></picker>
    
    <h2>Select People for hire</h2>
    <picker name="employeePicker" items={lessonUsers} labels={['id', 'name', 'job']}></picker>
    
	<script>
	
	    this.authorFilter = false
	    this.tags.authorPicker.on(
	        'filtered', function(data)
    	    {
    	        this.authorFilter = data
    	        this.update()
    	    }.bind(this)
	    )
	    
	    this.tags.authorPicker.on(
	        'picked', function(data)
    	    {
    	        this.authorPicks = data
    	        this.update()
    	    }.bind(this)
	    )
		this.lessonUsers = [
		    {"id":1,"name":"Jack Stevens","email":"jstevens0@cdbaby.com","country":"France","job":"Payment Adjustment Coordinator"},
            {"id":2,"name":"Teresa Lawson","email":"tlawson1@meetup.com","country":"Indonesia","job":"Computer Systems Analyst I"},
            {"id":3,"name":"Timothy Alvarez","email":"talvarez2@chicagotribune.com","country":"Russia","job":"Software Test Engineer I"},
            {"id":4,"name":"Ernest Lawrence","email":"elawrence3@google.com.au","country":"Philippines","job":"Software Engineer II"},
            {"id":5,"name":"Lois Patterson","email":"lpatterson4@forbes.com","country":"Indonesia","job":"Assistant Professor"},
            {"id":6,"name":"Tina Nelson","email":"tnelson5@ihg.com","country":"Myanmar","job":"Occupational Therapist"},
            {"id":7,"name":"Carlos Torres","email":"ctorres6@sfgate.com","country":"Mexico","job":"Analog Circuit Design manager"},
            {"id":8,"name":"Donna Henderson","email":"dhenderson7@liveinternet.ru","country":"China","job":"Safety Technician I"},
            {"id":9,"name":"Randy Grant","email":"rgrant8@blogs.com","country":"Japan","job":"Pharmacist"},
            {"id":10,"name":"Denise Campbell","email":"dcampbell9@illinois.edu","country":"Pakistan","job":"Analyst Programmer"},
            {"id":11,"name":"Pamela Cooper","email":"pcoopera@sitemeter.com","country":"China","job":"Software Engineer I"},
            {"id":12,"name":"Stephen Rogers","email":"srogersb@sogou.com","country":"Netherlands","job":"Payment Adjustment Coordinator"},
            {"id":13,"name":"Helen Powell","email":"hpowellc@accuweather.com","country":"United States","job":"Budget/Accounting Analyst III"},
            {"id":14,"name":"Fred Wheeler","email":"fwheelerd@marketwatch.com","country":"Portugal","job":"Staff Scientist"},
            {"id":15,"name":"Bonnie Bradley","email":"bbradleye@privacy.gov.au","country":"Thailand","job":"Engineer IV"},
            {"id":16,"name":"Michelle Medina","email":"mmedinaf@theguardian.com","country":"Nicaragua","job":"Physical Therapy Assistant"},
            {"id":17,"name":"Henry Howell","email":"hhowellg@mlb.com","country":"France","job":"Recruiting Manager"},
            {"id":18,"name":"Jose Ross","email":"jrossh@livejournal.com","country":"Ukraine","job":"Account Executive"},
            {"id":19,"name":"Jesse Hart","email":"jharti@joomla.org","country":"Republic of the Congo","job":"Community Outreach Specialist"},
            {"id":20,"name":"Margaret Simpson","email":"msimpsonj@de.vu","country":"Russia","job":"Database Administrator III"},
            {"id":21,"name":"Carol Warren","email":"cwarrenk@devhub.com","country":"Japan","job":"Media Manager III"},
            {"id":22,"name":"Shirley Ray","email":"srayl@ca.gov","country":"Russia","job":"Marketing Assistant"},
            {"id":23,"name":"Kenneth Wood","email":"kwoodm@google.fr","country":"Indonesia","job":"Junior Executive"},
            {"id":24,"name":"Ruth Bailey","email":"rbaileyn@zimbio.com","country":"France","job":"Design Engineer"},
            {"id":25,"name":"James Morales","email":"jmoraleso@aol.com","country":"Honduras","job":"Senior Sales Associate"},
            {"id":26,"name":"Bobby Bradley","email":"bbradleyp@webeden.co.uk","country":"Philippines","job":"Environmental Specialist"},
            {"id":27,"name":"Peter Henry","email":"phenryq@printfriendly.com","country":"Vietnam","job":"Budget/Accounting Analyst III"},
            {"id":28,"name":"Benjamin Banks","email":"bbanksr@prlog.org","country":"Peru","job":"Teacher"},
            {"id":29,"name":"Stephanie Kelley","email":"skelleys@mayoclinic.com","country":"China","job":"Recruiting Manager"},
            {"id":30,"name":"Roger Wells","email":"rwellst@google.com.hk","country":"China","job":"Safety Technician III"}
        ]
	</script>
</application>
var arrayhelper = {
    filterByLabels : function(items, labels, filter)
    {
        for (var item in items)
        {
            item = items[item]
            // We need a combinedvalue, consisting out of the itemvalues with the labels that exist
            // We search in a string that combines the value of each data row.
            var combinedValue = ''
            for (var label in labels)
            {
                label = labels[label]
                // concatenating the item value
                combinedValue += item[label]
            }
            // !~ means: If NOT -1, we lowercase everything so searching is easier.
            item.filtered = !~combinedValue.toLowerCase().indexOf(filter.toLowerCase())
        }
    }
}