List Builder

This is a javascript plugin for adding a slightly better UI to a multi-select field. This plugin can be found on GitHub at https://github.com/matt-bernhardt/ListBuilder

by matt_bernhardt

HTML

<form method="get">
    <label for="filter">Show only these departments:
        <br />
        <select id="filter" name="filter" multiple="true" class="listbuilder">
            <option value="astronomy">Astronomy</option>
            <option value="biology">Biology</option>
            <option value="chemistry">Chemistry</option>
            <option value="dentistry">Dentistry</option>
            <option value="energy">Energy</option>
        </select>
    </label>
    <input type="submit" />
</form>
<p>This plugin can be found on GitHub at <a href="https://github.com/matt-bernhardt/ListBuilder">https://github.com/matt-bernhardt/ListBuilder</a>.</p>

CSS

.listhidden {
    display: none;
}
.listcontainer {
}
.bucket {
    padding: .2em;
    margin: .2em;
    display: inline-block;
    width: 48%;
    height: 10em;
    overflow: auto;
}
.unselected {
    border: .1em solid gray;
    background-color: #cdcdcd;
}
.unselected .label {
    background-color: #bcbcbc;
    padding: 0.2em;
    margin: -0.2em;
    margin-bottom: 0.25em;
}
.unselected .label label {
    width: 20%;
    padding-right: 0.2em;
}
.unselected input {
    background-color: #dedede;
    border: none;
    width: 70%;
}
.unselected .option:before {
    content:'+ ';
}
.unselected .option.hidden {
    display: none;
}
.unselected a.reset {
    display: inline-block;
    padding-left: 0.2em;
    width: 10%;
}
.selected {
    border: .1em solid gray;
    background-color: #cdcdcd;
}
.selected .label {
    background-color: #bcbcbc;
    padding: 0.2em;
    margin: -0.2em;
    margin-bottom: 0.25em;
}
.selected .option:before {
    content:'- ';
}

JavaScript

/*
 * Namespace
 */
window.app = window.app || {};

/*
 * ListBuilder object
 */
window.app.listbuilder = {

    /*
     * Initialize
     */
    initialize: function (config) {
        config = config || {};
        this.list = config.listElement || $(".listbuilder");
        // check for console
        if (!window.console) console = {
            log: function () {}
        };
        this.debugFlag = config.debugFlag || true;
        this.debug('init called');
        // build list container after identified select list
        listcontainer = document.createElement("div");
        original = this.list;
        $(listcontainer).attr("class", "listcontainer");
        $(this.list).after(listcontainer);
        // build "unselected" and "selected" buckets
        unselected = document.createElement("div");
        $(unselected).attr("class", "unselected bucket");
        $(unselected).attr("data-bucket", "unselected");
        // build filter input
        $(unselected).append("<div class='label'><label for='listfilter'>Search:</label><input type='text' name='listfilter' id='listfilter'><a class='reset'>Clear</a></div>");
        $(listcontainer).append(unselected);
        selected = document.createElement("div");
        $(selected).attr("class", "selected bucket");
        $(selected).attr("data-bucket", "selected");
        $(selected).append("<div class='label'>Show:</div>");
        $(listcontainer).append(selected);
        this.populateList();
        // append hidden class to original select list, hiding it
        $(this.list).addClass("listhidden");
        this.debug('init finished');
    },

    /*
     * This is the listener for new interactions with the element
     */
    getClick: function (bucket) {
        this.debug('click ' + bucket.attr('data-value'));
        from = bucket.parent().attr('data-bucket');
        this.debug('from ' + from);
        to = from == "unselected" ? "selected" : "unselected";
        // Swap
       ...