/home/mip/mip/public/vendor/laravel-filemanager/files/folder-1/821668/bootstrap-tokenfield.tar
bootstrap-tokenfield.jquery.json000066400000001447152434262010013123 0ustar00{
  "name": "bootstrap-tokenfield",
  "version": "0.12.1",
  "title": "bootstrap-tokenfield",
  "author": {
    "name": "ragulka",
    "url": "https://github.com/ragulka"
  },
  "licenses": [
    {
      "type": "MIT",
      "url": "http://opensource.org/licenses/MIT"
    }
  ],
  "dependencies": {
    "jquery": "*"
  },
  "description": "Advanced tagging/tokenizing plugin for input fields with a focus on keyboard and copy-paste support.",
  "keywords": [
    "jquery",
    "javascript",
    "bootstrap",
    "tokenfield",
    "tags",
    "token",
    "input",
    "select",
    "form"
  ],
  "homepage": "http://sliptree.github.io/bootstrap-tokenfield/",
  "docs": "http://sliptree.github.io/bootstrap-tokenfield/",
  "bugs": {
    "url": "https://github.com/sliptree/bootstrap-tokenfield/issues"
  }
}LICENSE.md000066400000002273152434262010006155 0ustar00#### Sliptree
- by Illimar Tambek for [Sliptree](http://sliptree.com)
- Copyright (c) 2013 by Sliptree

Available for use under the [MIT License](http://en.wikipedia.org/wiki/MIT_License)

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.index.html000066400000102142152434262010006542 0ustar00---
title: Tokenfield for Bootstrap
---

<!DOCTYPE html>
<html lang="en">
  <head>
    <!-- Meta, title, CSS, favicons, etc. -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="description" content="">
    <meta name="author" content="">

    <title>Tokenfield for Bootstrap</title>

    <!-- Bootstrap core CSS -->
    <link href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css" rel="stylesheet">
    <!-- jQuery UI CSS -->
    <link href="//code.jquery.com/ui/1.10.3/themes/smoothness/jquery-ui.css" type="text/css" rel="stylesheet">
    <!-- Bootstrap styling for Typeahead -->
    <link href="dist/css/tokenfield-typeahead.css" type="text/css" rel="stylesheet">
    <!-- Tokenfield CSS -->
    <link href="dist/css/bootstrap-tokenfield.css" type="text/css" rel="stylesheet">
    <!-- Docs CSS -->
    <link href="docs-assets/css/pygments-manni.css" type="text/css" rel="stylesheet">
    <link href="docs-assets/css/docs.css" type="text/css" rel="stylesheet">

    <!--[if lt IE 9]>
      <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
      <script src="http://cdnjs.cloudflare.com/ajax/libs/respond.js/1.2.0/respond.min.js"></script>
    <![endif]-->

  </head>
  <body>

    <div class="bs-header" id="content">
      <div class="container">
        <h1>Tokenfield for Bootstrap</h1>
        <p>Advanced tagging/tokenizing plugin for jQuery and Twitter Bootstrap with a focus on keyboard and copy-paste support.</p>
        <ul id="feature-highlights">
          <li>Copy &amp; paste support</li>
          <li>Keyboard navigation</li>
          <li>Edit existing tokens</li>
          <li>Multiple lines of tokens</li>
          <li>Responsive</li>
        </ul>
        <div id="main-links">
          <a id="download-master" href="https://github.com/sliptree/bootstrap-tokenfield/zipball/master" class="btn btn-primary">Download Development</a>
        </div>
      </div>
    </div>

    <div class="container bs-docs-container">
      <div class="row">

        <div class="col-md-3">
          <div class="bs-sidebar hidden-print affix-top" role="complementary">
            <ul class="nav bs-sidenav">
              <li><a href="#examples">Examples</a></li>
              <li><a href="#usage">Usage</a></li>
              <li><a href="#options">Options</a></li>
              <li><a href="#methods">Methods</a></li>
              <li><a href="#events">Events</a></li>
              <li><a href="#keyboard">Keyboard support</a></li>
              <li><a href="#copy-paste">Copy &amp; paste support</a></li>
              <li><a href="#validation-states">Validation states</a></li>
              <li><a href="#various-examples">Various examples</a></li>
            </ul>
          </div>
        </div>

        <div class="col-md-9" role="main">
            <!-- Glyphicons
            ================================================== -->
            <div class="bs-docs-section">
              <div class="page-header">
                <h1 id="tokenfield">Tokenfield <small>%VERSION%</small></h1>
              </div>

              <h2 id="examples">Examples</h2>
              <p>Create elegant taggable fields with copy/paste and keyboard support.</p>

              <p><strong>Using jQuery UI Autocomplete</strong></p>

              <div class="bs-example">
                <div class="form-group">
                  <input type="text" class="form-control" id="tokenfield-1" value="red,green,blue" placeholder="Type something and hit enter" />
                </div>
              </div>
{% highlight html %}
<input type="text" class="form-control" id="tokenfield" value="red,green,blue" />
{% endhighlight %}

{% highlight js %}
$('#tokenfield').tokenfield({
  autocomplete: {
    source: ['red','blue','green','yellow','violet','brown','purple','black','white'],
    delay: 100
  },
  showAutocompleteOnFocus: true
})
{% endhighlight %}

              <p><strong>Using Twitter Typeahead</strong></p>

              <div class="bs-example">
                <div class="form-group">
                  <input type="text" class="form-control" id="tokenfield-typeahead" value="red,green,blue" placeholder="Type something and hit enter" />
                </div>
              </div>
{% highlight html %}
<input type="text" class="form-control" id="tokenfield-typeahead" value="red,green,blue" />
{% endhighlight %}

{% highlight js %}
var engine = new Bloodhound({
  local: [{value: 'red'}, {value: 'blue'}, {value: 'green'} , {value: 'yellow'}, {value: 'violet'}, {value: 'brown'}, {value: 'purple'}, {value: 'black'}, {value: 'white'}],
  datumTokenizer: function(d) {
    return Bloodhound.tokenizers.whitespace(d.value);
  },
  queryTokenizer: Bloodhound.tokenizers.whitespace
});

engine.initialize();

$('#tokenfield-typeahead').tokenfield({
  typeahead: [null, { source: engine.ttAdapter() }]
});
{% endhighlight %}

              <h2 id="usage">Usage</h2>

              <h3>Trigger tokenfield via JavaScript:</h3>
{% highlight js %}
$('.tokenfield').tokenfield()
{% endhighlight %}

              <h3 id="options">Options</h3>

              <p>Options can be passed via data attributes or JavaScript. For data attributes, append the option name to <code>data-</code>, as in <code>data-minLength=""</code>.</p>

              <div class="table-responsive">
                <table class="table table-bordered table-striped">
                  <thead>
                   <tr>
                     <th style="width: 100px;">Name</th>
                     <th style="width: 50px;">type</th>
                     <th style="width: 100px;">default</th>
                     <th>description</th>
                   </tr>
                  </thead>
                  <tbody>
                    <tr>
                      <td>tokens</td>
                      <td>string, array</td>
                      <td><code>[]</code></td>
                      <td>Tokens (or tags). Can be a string with comma-separated values (<code>"one,two,three"</code>), an array of strings (<code>["one","two","three"]</code>), or an array of objects (<code>[{ value: "one", label: "Einz" }, { value: "two", label: "Zwei" }]</code>)</td>
                    </tr>
                    <tr>
                      <td>limit</td>
                      <td>int</td>
                      <td><code>0</code></td>
                      <td>Maximum number of tokens allowed. 0 = unlimited.</td>
                    </tr>
                    <tr>
                      <td>minLength</td>
                      <td>int</td>
                      <td><code>0</code></td>
                      <td>Minimum length required for token value.</td>
                    </tr>
                    <tr>
                      <td>minWidth</td>
                      <td>int</td>
                      <td><code>60</code></td>
                      <td>Minimum input field width. In pixels.</td>
                    </tr>
                    <tr>
                      <td>autocomplete</td>
                      <td>object</td>
                      <td><code>{}</code></td>
                      <td>jQuery UI Autocomplete options</td>
                    </tr>
                    <tr>
                      <td>showAutocompleteOnFocus</td>
                      <td>boolean</td>
                      <td><code>false</code></td>
                      <td>Whether to show autocomplete suggestions menu on focus or not. Works only for jQuery UI Autocomplete, as Typeahead has no support for this kind of behavior.</td>
                    </tr>
                    <tr>
                      <td>typeahead</td>
                      <td>array</td>
                      <td><code>[]</code></td>
                      <td>Arguments for Twitter Typeahead. The first argument should be an options hash (or <code>null</code> if you want to use the defaults). The second argument should be a dataset. You can add multiple datasets: <code>typeahead: [options, dataset1, dataset2]</code></td>
                    </tr>
                    <tr>
                      <td>createTokensOnBlur</td>
                      <td>boolean</td>
                      <td><code>false</code></td>
                      <td>Whether to turn input into tokens when tokenfield loses focus or not.</td>
                    </tr>
                    <tr>
                      <td>delimiter</td>
                      <td>string, array</td>
                      <td><code>','</code></td>
                      <td>A character or an array of characters that will trigger token creation on keypress event. Defaults to ',' (comma). Note - this does not affect Enter or Tab keys, as they are handled in the keydown event. The first delimiter will be used as a separator when getting the list of tokens or copy-pasting tokens.</td>
                    </tr>
                    <tr>
                      <td>beautify</td>
                      <td>boolean</td>
                      <td><code>true</code></td>
                      <td>Whether to insert spaces after each token when getting a comma-separated list of tokens. This affects both value returned by <code>getTokensList()<code> and the value of the original input field.</td>
                    </tr>
                    <tr>
                      <td>inputType</td>
                      <td>string</td>
                      <td><code>'text'</code></td>
                      <td>HTML type attribute for the token input. This is useful for specifying an HTML5 input type like <code>'email'</code>, <code>'url'</code> or <code>'tel'</code> which allows mobile browsers to show a specialized virtual keyboard optimized for different types of input. This only sets the type of the visible token input but does not touch the original input field. So you may set the original input to have <code>type="text"</code> but set this inputType option to <code>'email'</code> if you only want to take advantage of the email style keyboard on mobile, but don't want to enable HTML5 native email validation on the original hidden input.</td>
                    </tr>
                  </tbody>
                </table>
              </div>

              <div class="bs-callout bs-callout-info">
                <h4>Data attributes for individual tokenfields</h4>
                <p>Options for individual tokenfields can alternatively be specified through the use of data attributes, as explained above.</p>
              </div>

              <div class="bs-callout bs-callout-info">
                <h4>Styling Twitter Typeahead </h4>
                <p>Twitter Typeahead comes with no default styling. Make sure to include <a href="https://gist.github.com/ragulka/6388201">tokenfield-typeahead.css</a> on your page.</p>
              </div>

              <h3 id="methods">Methods</h3>
              <h4>.tokenfield(options)</h4>
              <p>Initializes an input with a tokenfield.</p>
{% highlight js %}
$('#myField').tokenfield();
{% endhighlight %}

              <h4>.tokenfield('setTokens', tokens)</h4>
              <p>Manually set the tokenfield content (replacing the old content)</p>
{% highlight js %}
$('#myField').tokenfield('setTokens', 'blue,red,white');
$('#myField').tokenfield('setTokens', ['blue','red','white']);
$('#myField').tokenfield('setTokens', [{ value: "blue", label: "Blau" }, { value: "red", label: "Rot" }]);
{% endhighlight %}

              <h4>.tokenfield('createToken', token)</h4>
              <p>Manually create a token and append it to the input</p>
{% highlight js %}
$('#myField').tokenfield('createToken', 'purple');
$('#myField').tokenfield('createToken', { value: 'violet', label: 'Violet' });
{% endhighlight %}

              <h4>.tokenfield('getTokens', active)</h4>
              <p>Get an array of tokens from the input. Set <code>active</code> to true to return only selected tokens.</p>
{% highlight js %}
$('#myField').tokenfield('getTokens');
{% endhighlight %}

              <h4>.tokenfield('getTokensList', delimiter, beautify, active)</h4>
              <p>Get a comma-separated list of the tokens from the input. You can use an alternative separator by supplying also a <code>delimiter</code> argument. Setting <code>beautify</code> to false will prevent adding a space after each token. Set <code>active</code> to true to return only selected tokens.</p>
{% highlight js %}
$('#myField').tokenfield('getTokensList');
$('#myField').tokenfield('getTokensList', '; ');
{% endhighlight %}

              <h4>.tokenfield('disable')</h4>
              <p>Disable tokenfield (just like a normal input field)</p>
{% highlight js %}
$('#myField').tokenfield('disable');
{% endhighlight %}

              <h4>.tokenfield('enable')</h4>
              <p>Enable tokenfield (just like a normal input field)</p>
{% highlight js %}
$('#myField').tokenfield('enable');
{% endhighlight %}

              <h4>.tokenfield('readonly')</h4>
              <p>Make tokenfield a readonly field (just like a normal input field)</p>
{% highlight js %}
$('#myField').tokenfield('readonly');
{% endhighlight %}

              <h4>.tokenfield('writeable')</h4>
              <p>Make tokenfield writeable (just like a normal input field)</p>
{% highlight js %}
$('#myField').tokenfield('writeable');
{% endhighlight %}

              <h4>.tokenfield('destroy')</h4>
              <p>Destroy tokenfield and restore original input</p>
{% highlight js %}
$('#myField').tokenfield('destroy');
{% endhighlight %}

              <div class="bs-callout bs-callout-info">
                <h4>Accessing original input</h4>
                <p>Though not recommended, you can access the original input field like so: <code>$('#tokenfield').data('bs.tokenfield').$input</code></p>
                <p>You can also set new options for the autocomplete or typehead objects from the original input above like so: <code>$('#tokenfield').data('bs.tokenfield').$input.autocomplete({source: new_array})</code></p>
              </div>

              <h3 id="events">Events</h3>
              <p>Tokenfield exposes a few events for hooking into it's functionality.</p>

              <div class="table-responsive">
                <table class="table table-bordered table-striped">
                  <thead>
                   <tr>
                     <th style="width: 150px;">Event</th>
                     <th>Description</th>
                   </tr>
                  </thead>
                  <tbody>
                   <tr>
                     <td>tokenfield:initialize</td>
                     <td>Fires after Tokenfield has been initialized.</td>
                   </tr>
                   <tr>
                     <td>tokenfield:createtoken</td>
                     <td>This event fires when a token is all set up to be created, but before it is inserted into the DOM and event listeners are attached. You can use this event to manipulate token value and label by changing the appropriate values of <code>attrs</code> property of the event. See below for an example. Calling <code>event.preventDefault()</code> or doing <code>return false</code> in the event handler will prevent the token from being created.</td>
                   </tr>
                   <tr>
                     <td>tokenfield:createdtoken</td>
                     <td>This event is fired after the token has been created. Here, <code>attrs</code> property of the event is also available, but is basically read-only. You can also get a direct reference to the token DOM object via <code>e.relatedTarget</code>. The example below uses this to set an 'invalid' class on the newly created token if it does not pass validation.</td>
                   </tr>
                   <tr>
                     <td>tokenfield:edittoken</td>
                     <td>This event is fired just before a token is about to be edited. This allows you to manipluate the input field value before it is created. Again, to do this, manipluate the <code>attrs</code> property of the event. Here you can also access the token DOM object with <code>e.relatedTarget</code>. Calling <code>event.preventDefault()</code> or doing <code>return false</code> in the event handler will prevent the token from being edited.</td>
                   </tr>
                   <tr>
                     <td>tokenfield:editedtoken</td>
                     <td>This event is fired when a token is ready for being edited. It means that the token has been replaced by an input field.</td>
                   </tr>
                   <tr>
                     <td>tokenfield:removetoken</td>
                     <td>This event is fired right before a token is removed. Here you can also access the token DOM object with <code>e.relatedTarget</code>. Calling <code>event.preventDefault()</code> or doing <code>return false</code> in the event handler will prevent the token from being removed. You can access token label and value by checking the <code>attrs</code> property of the event. Also, <code>e.relatedTarget</code> is a reference to the token DOM object.</td>
                   </tr>
                   <tr>
                     <td>tokenfield:removedtoken</td>
                     <td>This event is fired right after a token is removed from the DOM. You can access token label and value by checking the <code>attrs</code> property of the event.</td>
                   </tr>
                  </tbody>
                </table>
              </div>

              <p>The example below is pretty comprehensive. Here, we split user input into two parts: name and email. Then, we validate the email and if it is not valid, we add an <code>invalid</code> class to the token.</p>
              <p>When the user starts to edit the token, we merge token value and label together again.</p>

              <div class="bs-example">
                <input type="text" class="form-control" id="tokenfield-2" data-tokens="me|me@example.com,you@example.com,not really an email" />
              </div>

{% highlight js %}
$('#tokenfield')

  .on('tokenfield:createtoken', function (e) {
    var data = e.attrs.value.split('|')
    e.attrs.value = data[1] || data[0]
    e.attrs.label = data[1] ? data[0] + ' (' + data[1] + ')' : data[0]
  })

  .on('tokenfield:createdtoken', function (e) {
    // Über-simplistic e-mail validation
    var re = /\S+@\S+\.\S+/
    var valid = re.test(e.attrs.value)
    if (!valid) {
      $(e.relatedTarget).addClass('invalid')
    }
  })

  .on('tokenfield:edittoken', function (e) {
    if (e.attrs.label !== e.attrs.value) {
      var label = e.attrs.label.split(' (')
      e.attrs.value = label[0] + '|' + e.attrs.value
    }
  })

  .on('tokenfield:removedtoken', function (e) {
    alert('Token removed! Token value was: ' + e.attrs.value)
  })

  .tokenfield()
{% endhighlight %}

              <h3 id="keyboard">Keyboard support</h3>
              <p>Tokenfield includes support for manipulating tokens via keyboard</p>
              <h4>left, right arrow keys</h4>
              <p>Arrow keys will move between active tokens. Try it out: click on one of the tokens and press left and right arrow keys</p>
              <h4>Backspace and delete</h4>
              <p>You can delete a selected token with backspace or delete keys. Try it out now:</p>
              <h4>Ctrl + A / Cmd + A, Ctrl + C / Cmd + C, Ctrl + V, Cmd + V</h4>
              <p>If You have one token selected, you can select all tokens with the keyboard. Then, you can copy the tokens using keyboard. You can also paste tokens to another field.</p>

              <div class="bs-example">
                <input type="text" class="form-control token-example-field" value="try,pressing,backspace" />
              </div>

              <h3 id="copy-paste">Copy &amp; paste support</h3>
              <p>You can copy tokens from a tokenfield and paste them to any other field as comma-separated values. When you paste to another tokenfield, they will become tokens there, aswell!</p>
              <p>Try it out, copy the following to the field below: violet,yellow,brown</p>

              <div class="bs-example">
                <input type="text" class="form-control token-example-field" value="copy,and,paste" />
              </div>

              <h3 id="validation-states">Validation states</h3>
              <p>Tokenfield also supports all the default validation states from Bootstrap</p>

              <form class="bs-example">

                <div class="form-group has-success">
                  <label class="control-label" for="inputSuccess">Input with success</label>
                  <input type="text" class="form-control token-example-field" id="inputSuccess" value="red,green,blue" />
                </div>

                <div class="form-group has-warning">
                  <label class="control-label" for="inputWarning">Input with warning</label>
                  <input type="text" class="form-control token-example-field" id="inputWarning" value="red,green,blue">
                </div>

                <div class="form-group has-error">
                  <label class="control-label" for="inputError">Input with error</label>
                  <input type="text" class="form-control token-example-field" id="inputError" value="red,green,blue">
                </div>

              </form>

              <h3 id="various-examples">Various examples of using tokenfield</h3>
              <p>Using tokenfield with input groups</p>

              <form class="bs-example bs-example-form" role="form">
                <div class="input-group">
                  <span class="input-group-addon">Tags:</span>
                  <input type="text" class="form-control token-example-field" value="cool,nice,great" />
                </div>
                <br>
                <div class="input-group">
                  <input type="text" class="form-control token-example-field" value="red,green,blue" />
                  <span class="input-group-addon"><span class="glyphicon glyphicon-star"></span></span>
                </div>
                <br>
                <div class="input-group">
                  <span class="input-group-addon">Tags:</span>
                  <input type="text" class="form-control token-example-field" value="red,green,blue" />
                  <span class="input-group-addon"><span class="glyphicon glyphicon-star"></span></span>
                </div>
              </form>

              <p>Using tokenfield with input group checkboxes and radio buttons</p>

              <form class="bs-example bs-example-form" role="form">
                <div class="row">
                  <div class="col-lg-6">
                    <div class="input-group">
                      <span class="input-group-addon">
                        <input type="checkbox">
                      </span>
                      <input type="text" class="form-control token-example-field" value="red,green,blue" />
                    </div><!-- /input-group -->
                  </div><!-- /.col-lg-6 -->
                  <div class="col-lg-6">
                    <div class="input-group">
                      <span class="input-group-addon">
                        <input type="radio">
                      </span>
                      <input type="text" class="form-control token-example-field" value="red,green,blue" />
                    </div><!-- /input-group -->
                  </div><!-- /.col-lg-6 -->
                </div>
              </form>

              <p>Using tokenfield with buttons in input groups</p>

              <form class="bs-example bs-example-form" role="form">
                <div class="input-group">
                  <input type="text" class="form-control token-example-field" value="red,green,blue" />
                  <span class="input-group-btn">
                    <button class="btn btn-default" type="button">Go!</button>
                  </span>
                </div>
                <br>
                <div class="input-group">
                  <input type="text" class="form-control token-example-field" value="red,green,blue" />
                  <div class="input-group-btn">
                    <button type="button" class="btn btn-default" tabindex="-1">Action</button>
                    <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" tabindex="-1">
                      <span class="caret"></span>
                    </button>
                    <ul class="dropdown-menu pull-right" role="menu">
                      <li><a href="#">Action</a></li>
                      <li><a href="#">Another action</a></li>
                      <li><a href="#">Something else here</a></li>
                      <li class="divider"></li>
                      <li><a href="#">Separated link</a></li>
                    </ul>
                  </div>
                </div>
              </form>

              <p>Using tokenfield with different sizes</p>

              <form class="bs-example bs-example-form" role="form">
                <input type="text" class="form-control input-lg token-example-field" value="red,green,blue" />
                <input type="text" class="form-control token-example-field" value="red,green,blue" />
                <input type="text" class="form-control input-sm token-example-field" value="red,green,blue" />
                <br>
                <div class="input-group input-group-lg">
                  <span class="input-group-addon">@</span>
                  <input type="text" class="form-control token-example-field" value="red,green,blue" />
                </div>
                <div class="input-group">
                  <span class="input-group-addon">@</span>
                  <input type="text" class="form-control token-example-field" value="red,green,blue" />
                </div>
                <div class="input-group input-group-sm">
                  <span class="input-group-addon">@</span>
                  <input type="text" class="form-control token-example-field" value="red,green,blue" />
                </div>
              </form>

              <p>Disabled tokenfield</p>

              <form class="bs-example bs-example-form" role="form">
                <input type="text" class="form-control token-example-field" value="red,green,blue" disabled="disabled" />
              </form>

              <p>Disabled fieldset with tokenfield</p>

              <form class="bs-example bs-example-form" role="form">
                <fieldset disabled>
                  <div class="form-group">
                    <label for="disabledTextInput">Disabled input</label>
                    <input type="text" id="disabledTextInput" class="form-control" placeholder="Disabled input">
                  </div>
                  <div class="form-group">
                    <label for="disabledTokenfield">Disabled tokenfield</label>
                    <input type="text" id="disabledTokenfield" class="form-control token-example-field" value="red,green,blue" />
                  </div>
                </fieldset>
              </form>

              <p>Tokenfield in inline form</p>

              <form class="bs-example form-inline" role="form">
                <div class="form-group">
                  <label class="sr-only" for="exampleInlineTags">Tags</label>
                  <input type="text" id="exampleInlineTags" class="form-control token-example-field" value="red,green,blue" placeholder="Enter tags" />
                </div>
                <button type="submit" class="btn btn-default">Search</button>
              </form>

              <p>Tokenfield in horizontal form</p>

              <form class="bs-example form-horizontal">
                <div class="form-group">
                  <label for="inputEmail1" class="col-lg-2 control-label">Email</label>
                  <div class="col-lg-10">
                    <input type="email" class="form-control" id="inputEmail1" placeholder="Email">
                  </div>
                </div>
                <div class="form-group">
                  <label for="inputPassword1" class="col-lg-2 control-label">Password</label>
                  <div class="col-lg-10">
                    <input type="password" class="form-control" id="inputPassword1" placeholder="Password">
                  </div>
                </div>
                <div class="form-group">
                  <label for="inputTags1" class="col-lg-2 control-label">Tags</label>
                  <div class="col-lg-10">
                    <input type="text" class="form-control token-example-field" id="inputTags1" placeholder="Tags" value="some,tags">
                  </div>
                </div>
                <div class="form-group">
                  <div class="col-lg-offset-2 col-lg-10">
                    <button type="submit" class="btn btn-default">Sign in</button>
                  </div>
                </div>
              </form>

              <p>Tokenfield with fluid and fixed widths (50%, 300px, etc...)</p>

              <form class="bs-example bs-example-form" role="form">
                <div class="form-group">
                  <label for="example-fluid-tokenfield">Width: 50% (from stylesheet)</label>
                  <input type="text" id="example-fluid-tokenfield" class="form-control token-example-field fluid-tokenfield" value="red,green,blue" />
                </div>
                <div class="form-group">
                  <label for="example-fixed-tokenfield">Width: 300px (from stylesheet)</label>
                  <input type="text" id="example-fixed-tokenfield" class="form-control token-example-field fixed-tokenfield" value="red,green,blue" />
                </div>
                <div class="form-group">
                  <label for="example-fixed-tokenfield-2">Width: 400px (inline)</label>
                  <input type="text" id="example-fixed-tokenfield-2" class="form-control token-example-field" value="red,green,blue" style="width:400px;" />
                </div>
              </form>

              <p>Tokenfield with RTL direction</p>

              <form class="bs-example bs-example-form" role="form">
                <input type="text" class="form-control token-example-field" value="red,green,blue" style="direction:rtl" />
              </form>

        </div>

      </div><!-- // row -->

    </div><!-- //container -->

    <footer class="bs-footer" role="contentinfo">
      <div class="container">
        <div class="bs-social">
          <ul class="bs-social-buttons">
            <li>
              <iframe class="github-btn" src="http://ghbtns.com/github-btn.html?user=sliptree&amp;repo=bootstrap-tokenfield&amp;type=watch&amp;count=true" width="100" height="20" title="Star on GitHub"></iframe>
            </li>
            <li>
              <iframe class="github-btn" src="http://ghbtns.com/github-btn.html?user=sliptree&amp;repo=bootstrap-tokenfield&amp;type=fork&amp;count=true" width="102" height="20" title="Fork on GitHub"></iframe>
            </li>
            <li class="follow-btn">
              <a href="https://twitter.com/sliptree" class="twitter-follow-button" data-show-count="false">Follow @sliptree</a>
              <script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0],p=/^http:/.test(d.location)?'http':'https';if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src=p+'://platform.twitter.com/widgets.js';fjs.parentNode.insertBefore(js,fjs);}}(document, 'script', 'twitter-wjs');</script>
            </li>
            <li class="tweet-btn">
              <a href="https://twitter.com/share" class="twitter-share-button" data-via="sliptree" data-hashtags="bootstrap-tokenfield">Tweet</a>
              <script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0],p=/^http:/.test(d.location)?'http':'https';if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src=p+'://platform.twitter.com/widgets.js';fjs.parentNode.insertBefore(js,fjs);}}(document, 'script', 'twitter-wjs');</script>
            </li>
          </ul>
        </div>

        <p>Built by <a href="https://github.com/ragulka" target="_blank">@ragulka</a> from <a href="https://sliptree.com" target="_blank">Sliptree</a>
        <p>Sliptree 2013</p>
        <ul class="footer-links">
          <li><a href="https://github.com/sliptree/bootstrap-tokenfield/issues?state=open">Issues</a></li>
          <li class="muted">&middot;</li>
          <li><a href="https://github.com/sliptree/bootstrap-tokenfield">Fork</a></li>
        </ul>
      </div>
    </footer>

    <script type="text/javascript" src="//code.jquery.com/jquery-1.9.1.js"></script>
    <script type="text/javascript" src="//code.jquery.com/ui/1.10.3/jquery-ui.js"></script>
    <script type="text/javascript" src="dist/bootstrap-tokenfield.js" charset="UTF-8"></script>
    <script type="text/javascript" src="docs-assets/js/scrollspy.js" charset="UTF-8"></script>
    <script type="text/javascript" src="docs-assets/js/affix.js" charset="UTF-8"></script>
    <script type="text/javascript" src="docs-assets/js/typeahead.bundle.min.js" charset="UTF-8"></script>
    <script type="text/javascript" src="docs-assets/js/docs.min.js" charset="UTF-8"></script>

    <script type="text/javascript">
      (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
      (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
      m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
      })(window,document,'script','https://www.google-analytics.com/analytics.js','ga');

      ga('create', 'UA-22737379-5', 'sliptree.github.io');
      ga('send', 'pageview');
    </script>

  </body>
</html>
package.json000066400000002573152434262010007042 0ustar00{
  "name": "bootstrap-tokenfield",
  "title": "Bootstrap Tokenfield",
  "description": "Advanced tagging/tokenizing plugin for input fields with a focus on keyboard and copy-paste support.",
  "version": "0.12.1",
  "main": "dist/bootstrap-tokenfield.js",
  "homepage": "http://sliptree.github.io/bootstrap-tokenfield/",
  "author": {
    "name": "ragulka",
    "url": "https://github.com/ragulka"
  },
  "repository": {
    "type": "git",
    "url": "git://github.com/sliptree/bootstrap-tokenfield.git"
  },
  "keywords": [
    "jquery",
    "javascript",
    "bootstrap",
    "tokenfield",
    "tags",
    "token",
    "input",
    "select",
    "form"
  ],
  "bugs": {
    "url": "https://github.com/sliptree/bootstrap-tokenfield/issues"
  },
  "licenses": [
    {
      "type": "MIT",
      "url": "https://github.com/jquery/jquery/blob/2.1.0/MIT-LICENSE.txt"
    }
  ],
  "scripts": {
    "test": "mocha --ui bdd --recursive --reporter spec --require must"
  },
  "devDependencies": {
    "grunt": "~0.4.2",
    "grunt-contrib-less": "~0.8.3",
    "grunt-contrib-uglify": "~0.2.7",
    "grunt-contrib-copy": "~0.4.1",
    "grunt-contrib-watch": "~0.5.3",
    "grunt-jekyll": "~0.4.1",
    "mocha": "^1.17.1",
    "must": "^0.11.0",
    "jsdom": "^0.10.1",
    "jquery-simulate-ext": "^1.3.0",
    "grunt-exec": "^0.4.5",
    "semver": "^2.2.1"
  },
  "dependencies": {
    "jquery": "^2.1.0"
  }
}.gitignore000066400000000133152434262010006532 0ustar00/_site/
/bower_components/
/node_modules/
/tmp/
*.tgz
*.sublime-project
*.sublime-workspaceGruntfile.js000066400000012005152434262010007040 0ustar00module.exports = function (grunt) {

  var semver = require('semver'),
      f = require('util').format;

  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    version: '<%= pkg.version %>',

    banner: [
      '/*!',
      ' * bootstrap-tokenfield <%= version %>',
      ' * https://github.com/sliptree/bootstrap-tokenfield',
      ' * Copyright 2013-2014 Sliptree and other contributors; Licensed MIT',
      ' */\n\n'
    ].join('\n'),    
    
    copy: {
      dist: {
        files: {
          'dist/<%= pkg.name %>.js': 'js/<%= pkg.name %>.js'
        }
      },
      assets: {
        files: [{
          expand: true,
          flatten: true,
          src: [
            'bower_components/bootstrap/js/affix.js',
            'bower_components/bootstrap/js/scrollspy.js',
            'bower_components/typeahead.js/dist/typeahead.bundle.min.js'
          ],
          dest: 'docs-assets/js/'
        }]
      }
    },

    uglify: {
      options: {
        banner: '<%= banner %>'
      },
      dist: {
        files: {
          'dist/<%= pkg.name %>.min.js': 'dist/<%= pkg.name %>.js'
        }
      },
      docs: {
        files: {
          'docs-assets/js/docs.min.js': 'docs-assets/js/docs.js'
        }
      }
    },

    less: {
      compile: {
        files: {
          'dist/css/<%= pkg.name %>.css': 'less/<%= pkg.name %>.less',
          'dist/css/tokenfield-typeahead.css': 'less/tokenfield-typeahead.less'
        }
      },
      minify: {
        options: {
          cleancss: true,
          report: 'min'
        },
        files: {
          'dist/css/<%= pkg.name %>.min.css': 'dist/css/<%= pkg.name %>.css',
          'dist/css/tokenfield-typeahead.min.css': 'dist/css/tokenfield-typeahead.css'
        }
      }
    },

    jekyll: {
      docs: {}
    },

    watch: {
      copy: {
        files: 'js/**/*',
        tasks: ['copy']
      },
      less: {
        files: 'less/**/*',
        tasks: ['less']
      },
      jekyll: {
        files: ['dist/**/*', 'index.html', 'docs-assets/**/*'],
        tasks: ['uglify:docs', 'jekyll']
      },
      livereload: {
        options: { livereload: true },
        files: ['dist/**/*'],
      }
    },

    exec: {
      git_is_clean: {
        cmd: 'test -z "$(git status --porcelain)"'
      },
      git_on_master: {
        cmd: 'test $(git symbolic-ref --short -q HEAD) = master'
      },
      git_add: {
        cmd: 'git add .'
      },
      git_commit: {
        cmd: function(m) { return f('git commit -m "%s"', m); }
      },
      git_tag: {
        cmd: function(v) { return f('git tag v%s -am "%s"', v, v); }
      },
      git_push: {
        cmd: 'git push && git push --tags'
      },
      update_docs: {
        cmd: [
          'git checkout gh-pages',
          'git reset master --hard',
          'sed -i.bak \'s/%VERSION%/v<%= version %>/\' index.html',
          'rm -rf index.html.bak',
          'git add index.html',
          'git commit -m "Update docs to <%= version %>"',
          'git checkout master'
        ].join(' && ')
      },
      npm_publish: {
        cmd: 'npm publish'
      }
    }

  });

  grunt.loadNpmTasks('grunt-contrib-copy');
  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('grunt-contrib-less');
  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-jekyll');
  grunt.loadNpmTasks('grunt-sed');
  grunt.loadNpmTasks('grunt-exec');

  grunt.registerTask('manifests', 'Update manifests.', function(version) {
    var _ = grunt.util._,
        pkg = grunt.file.readJSON('package.json'),
        bower = grunt.file.readJSON('bower.json'),
        jqueryPlugin = grunt.file.readJSON('bootstrap-tokenfield.jquery.json');

    bower = JSON.stringify(_.extend(bower, {
      name: pkg.name,
      version: version
    }), null, 2);

    jqueryPlugin = JSON.stringify(_.extend(jqueryPlugin, {
      name: pkg.name,
      title: pkg.name,
      version: version,
      author: pkg.author,
      description: pkg.description,
      keywords: pkg.keywords,
      homepage: pkg.homepage,
      bugs: pkg.bugs,
      maintainers: pkg.contributors
    }), null, 2);

    pkg = JSON.stringify(_.extend(pkg, {
      version: version
    }), null, 2);

    grunt.file.write('package.json', pkg);
    grunt.file.write('bower.json', bower);
    grunt.file.write('bootstrap-tokenfield.jquery.json', jqueryPlugin);
  });

  grunt.registerTask('release', 'Ship it.', function(version) {
    var curVersion = grunt.config.get('version');

    version = semver.inc(curVersion, version) || version;

    if (!semver.valid(version) || semver.lte(version, curVersion)) {
      grunt.fatal('invalid version dummy');
    }

    grunt.config.set('version', version);

    grunt.task.run([
      'exec:git_on_master',
      'exec:git_is_clean',
      'manifests:' + version,
      'build',
      'exec:git_add',
      'exec:git_commit:' + version,
      'exec:git_tag:' + version,
      'exec:update_docs'
      //'exec:git_push',
      //'exec:npm_publish',
    ]);
  });  

  // Build task
  grunt.registerTask('build', ['copy', 'uglify', 'less']);
}.npmignore000066400000000064152434262010006544 0ustar00/_site/
/bower_components/
/*.tgz
/tmp/
/.travis.ymldocs-assets/css/pygments-manni.css000066400000005674152434262010013261 0ustar00.hll { background-color: #ffffcc }
 /*{ background: #f0f3f3; }*/
.c { color: #999; } /* Comment */
.err { color: #AA0000; background-color: #FFAAAA } /* Error */
.k { color: #006699; } /* Keyword */
.o { color: #555555 } /* Operator */
.cm { color: #0099FF; font-style: italic } /* Comment.Multiline */
.cp { color: #009999 } /* Comment.Preproc */
.c1 { color: #999; } /* Comment.Single */
.cs { color: #999; } /* Comment.Special */
.gd { background-color: #FFCCCC; border: 1px solid #CC0000 } /* Generic.Deleted */
.ge { font-style: italic } /* Generic.Emph */
.gr { color: #FF0000 } /* Generic.Error */
.gh { color: #003300; } /* Generic.Heading */
.gi { background-color: #CCFFCC; border: 1px solid #00CC00 } /* Generic.Inserted */
.go { color: #AAAAAA } /* Generic.Output */
.gp { color: #000099; } /* Generic.Prompt */
.gs { } /* Generic.Strong */
.gu { color: #003300; } /* Generic.Subheading */
.gt { color: #99CC66 } /* Generic.Traceback */
.kc { color: #006699; } /* Keyword.Constant */
.kd { color: #006699; } /* Keyword.Declaration */
.kn { color: #006699; } /* Keyword.Namespace */
.kp { color: #006699 } /* Keyword.Pseudo */
.kr { color: #006699; } /* Keyword.Reserved */
.kt { color: #007788; } /* Keyword.Type */
.m { color: #FF6600 } /* Literal.Number */
.s { color: #d44950 } /* Literal.String */
.na { color: #4f9fcf } /* Name.Attribute */
.nb { color: #336666 } /* Name.Builtin */
.nc { color: #00AA88; } /* Name.Class */
.no { color: #336600 } /* Name.Constant */
.nd { color: #9999FF } /* Name.Decorator */
.ni { color: #999999; } /* Name.Entity */
.ne { color: #CC0000; } /* Name.Exception */
.nf { color: #CC00FF } /* Name.Function */
.nl { color: #9999FF } /* Name.Label */
.nn { color: #00CCFF; } /* Name.Namespace */
.nt { color: #2f6f9f; } /* Name.Tag */
.nv { color: #003333 } /* Name.Variable */
.ow { color: #000000; } /* Operator.Word */
.w { color: #bbbbbb } /* Text.Whitespace */
.mf { color: #FF6600 } /* Literal.Number.Float */
.mh { color: #FF6600 } /* Literal.Number.Hex */
.mi { color: #FF6600 } /* Literal.Number.Integer */
.mo { color: #FF6600 } /* Literal.Number.Oct */
.sb { color: #CC3300 } /* Literal.String.Backtick */
.sc { color: #CC3300 } /* Literal.String.Char */
.sd { color: #CC3300; font-style: italic } /* Literal.String.Doc */
.s2 { color: #CC3300 } /* Literal.String.Double */
.se { color: #CC3300; } /* Literal.String.Escape */
.sh { color: #CC3300 } /* Literal.String.Heredoc */
.si { color: #AA0000 } /* Literal.String.Interpol */
.sx { color: #CC3300 } /* Literal.String.Other */
.sr { color: #33AAAA } /* Literal.String.Regex */
.s1 { color: #CC3300 } /* Literal.String.Single */
.ss { color: #FFCC33 } /* Literal.String.Symbol */
.bp { color: #336666 } /* Name.Builtin.Pseudo */
.vc { color: #003333 } /* Name.Variable.Class */
.vg { color: #003333 } /* Name.Variable.Global */
.vi { color: #003333 } /* Name.Variable.Instance */
.il { color: #FF6600 } /* Literal.Number.Integer.Long */

.css .o,
.css .o + .nt,
.css .nt + .nt { color: #999; }docs-assets/css/docs.css000066400000226670152434262010011244 0ustar00/*
 * Bootstrap Tokenfield Documentation
 * Special styles for presenting Bootstrap's documentation and code examples.
 *
 * Table of contents:
 *
 * Scaffolding
 * Main navigation
 * Footer
 * Social buttons
 * Homepage
 * Page headers
 * Old docs callout
 * Ads
 * Side navigation
 * Docs sections
 * Callouts
 * Grid styles
 * Examples
 * Code snippets (highlight)
 * Responsive tests
 * Glyphicons
 * Customizer
 * Miscellaneous
 */


/*
 * Scaffolding
 *
 * Update the basics of our documents to prep for docs content.
 */

body {
  position: relative; /* For scrollyspy */
}

/* Keep code small in tables on account of limited space */
.table code {
  font-size: 13px;
  font-weight: normal;
}

/* Outline button for use within the docs */
.btn-outline {
  color: #563d7c;
  background-color: #fff;
  border-color: #e5e5e5;
}
.btn-outline:hover,
.btn-outline:focus,
.btn-outline:active {
  color: #fff;
  background-color: #563d7c;
  border-color: #563d7c;
}

/* Inverted outline button (white on dark) */
.btn-outline-inverse {
  color: #fff;
  background-color: transparent;
  border-color: #cdbfe3;
}
.btn-outline-inverse:hover,
.btn-outline-inverse:focus,
.btn-outline-inverse:active {
  color: #563d7c;
  text-shadow: none;
  background-color: #fff;
  border-color: #fff;
}


/*
 * Main navigation
 *
 * Turn the `.navbar` at the top of the docs purple.
 */

.bs-docs-nav {
  text-shadow: 0 -1px 0 rgba(0,0,0,.15);
  background-color: #563d7c;
  border-color: #463265;
  box-shadow: 0 1px 0 rgba(255,255,255,.1);
}
.bs-docs-nav .navbar-collapse {
  border-color: #463265;
}
.bs-docs-nav .navbar-brand {
  color: #fff;
}
.bs-docs-nav .navbar-nav > li > a {
  color: #cdbfe3;
}
.bs-docs-nav .navbar-nav > li > a:hover {
  color: #fff;
}
.bs-docs-nav .navbar-nav > .active > a,
.bs-docs-nav .navbar-nav > .active > a:hover {
  color: #fff;
  background-color: #463265;
}
.bs-docs-nav .navbar-toggle {
  border-color: #563d7c;
}
.bs-docs-nav .navbar-toggle:hover {
  background-color: #463265;
  border-color: #463265;
}


/*
 * Footer
 *
 * Separated section of content at the bottom of all pages, save the homepage.
 */

.bs-footer {
  padding-top: 40px;
  padding-bottom: 30px;
  margin-top: 100px;
  color: #777;
  text-align: center;
  border-top: 1px solid #e5e5e5;
}
.footer-links {
  margin: 10px 0;
  padding-left: 0;
}
.footer-links li {
  display: inline;
  padding: 0 2px;
}
.footer-links li:first-child {
  padding-left: 0;
}

@media (min-width: 768px) {
  .bs-footer {
    text-align: left;
  }
  .bs-footer p {
    margin-bottom: 0;
  }
}


/*
 * Social buttons
 *
 * Twitter and GitHub social action buttons (for homepage and footer).
 */

.bs-social {
  margin-top: 20px;
  margin-bottom: 20px;
  text-align: center;
}
.bs-social-buttons {
  display: inline-block;
  margin-bottom: 0;
  padding-left: 0;
  list-style: none;
}
.bs-social-buttons li {
  display: inline-block;
  line-height: 1;
  padding: 5px 8px;
}
.bs-social-buttons .twitter-follow-button {
  width: 225px !important;
}
.bs-social-buttons .twitter-share-button {
  width: 98px !important;
}
/* Style the GitHub buttons via CSS instead of inline attributes */
.github-btn {
  border: 0;
  overflow: hidden;
}

@media screen and (min-width: 768px) {
  .bs-social {
    text-align: left;
  }
  .bs-social-buttons li:first-child {
    padding-left: 0;
  }
}


/*
 * Topography, yo!
 *
 * Apply the map background via base64 and relevant colors where we need 'em.
 */

.bs-docs-home,
.bs-header {
  color: #cdbfe3;
  background-color: #563d7c;
  background-image: url(data:image/png;base64,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);
}


/*
 * Homepage
 *
 * Tweaks to the custom homepage and the masthead (main jumbotron).
 */

 /* Masthead (headings and download button) */
 .bs-masthead {
  position: relative;
  padding: 30px 15px;
  text-align: center;
  text-shadow: 0 1px 0 rgba(0,0,0,.15);
}
.bs-masthead h1 {
  font-size: 50px;
  line-height: 1;
  color: #fff;
}
.bs-masthead .btn-outline {
  margin-top: 20px;
  margin-bottom: 20px;
  padding: 18px 24px;
  font-size: 21px;
}

/* Links to project-level content like the repo, Expo, etc */
.bs-masthead-links {
  margin-top: 20px;
  margin-bottom: 20px;
  padding: 0 15px;
  list-style: none;
  text-align: center;
}
.bs-masthead-links li {
  display: inline;
}
.bs-masthead-links li + li {
  margin-left: 20px;
}
.bs-masthead-links a {
  color: #fff;
}

@media screen and (min-width: 768px) {
  .bs-masthead {
    text-align: left;
    padding-top:    140px;
    padding-bottom: 140px;
  }
  .bs-masthead h1 {
    font-size: 100px;
  }
  .bs-masthead .lead {
    margin-right: 25%;
    font-size: 30px;
  }
  .bs-masthead-links {
    padding: 0;
    text-align: left;
  }
}


/*
 * Page headers
 *
 * Jumbotron-esque headers at the top of every page that's not the homepage.
 */


/* Page headers */
.bs-header {
  padding: 30px 15px 40px; /* side padding builds on .container 15px, so 30px */
  font-size: 16px;
  text-align: center;
  text-shadow: 0 1px 0 rgba(0,0,0,.15);
}
.bs-header h1 {
  color: #fff;
}
.bs-header p {
  font-weight: 300;
  line-height: 1.5;
}
.bs-header .container {
  position: relative;
}

@media screen and (min-width: 768px) {
  .bs-header {
    font-size: 21px;
    text-align: left;
  }
  .bs-header h1 {
    font-size: 60px;
    line-height: 1;
  }
}

@media screen and (min-width: 992px) {
  .bs-header h1,
  .bs-header p {
    margin-right: 380px;
  }
}


/*
 * Carbon ads
 *
 * Single display ad that shows on all pages (except homepage) in page headers.
 * The hella `!important` is required for any pre-set property.
 */

.carbonad {
  width: auto !important;
  margin: 50px -30px -40px !important;
  padding: 20px !important;
  overflow: hidden; /* clearfix */
  height: auto !important;
  font-size: 13px !important;
  line-height: 16px !important;
  text-align: left;
  background: #463265 !important;
  border: 0 !important;
  box-shadow: inset 0 3px 5px rgba(0,0,0,.075);
}
.carbonad-img {
  margin: 0 !important;
}
.carbonad-text,
.carbonad-tag {
  float: none !important;
  display: block !important;
  width: auto !important;
  height: auto !important;
  margin-left: 145px !important;
  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif !important;
}
.carbonad-text {
  padding-top: 0 !important;
}
.carbonad-tag {
  color: #cdbfe3 !important;
  text-align: left !important;
}
.carbonad-text a,
.carbonad-tag a {
  color: #fff !important;
}
.carbonad #azcarbon > img {
  display: none; /* hide what I assume are tracking images */
}

@media screen and (min-width: 768px) {
  .carbonad {
    margin: 0 !important;
    border-radius: 4px;
    box-shadow: inset 0 3px 5px rgba(0,0,0,.075), 0 1px 0 rgba(255,255,255,.1);
  }
}

@media screen and (min-width: 992px) {
  .carbonad {
    position: absolute;
    top: 20px;
    right: 0;
    padding: 15px !important;
    width: 330px !important;
    min-height: 132px;
  }
}


/*
 * Callout for 2.3.2 docs
 *
 * Only appears below page headers (not on the homepage). The homepage gets its
 * own link with the masthead links.
 */

.bs-old-docs {
  padding: 15px 20px;
  color: #777;
  background-color: #fafafa;
  border-top: 1px solid #fff;
  border-bottom: 1px solid #e5e5e5;
}
.bs-old-docs strong {
  color: #555;
}


/*
 * Side navigation
 *
 * Scrollspy and affixed enhanced navigation to highlight sections and secondary
 * sections of docs content.
 */

/* By default it's not affixed in mobile views, so undo that */
.bs-sidebar.affix {
  position: static;
}

/* First level of nav */
.bs-sidenav {
  margin-top: 30px;
  margin-bottom: 30px;
  padding-top:    10px;
  padding-bottom: 10px;
  text-shadow: 0 1px 0 #fff;
  background-color: #f7f5fa;
  border-radius: 5px;
}

/* All levels of nav */
.bs-sidebar .nav > li > a {
  display: block;
  color: #716b7a;
  padding: 5px 20px;
}
.bs-sidebar .nav > li > a:hover,
.bs-sidebar .nav > li > a:focus {
  text-decoration: none;
  background-color: #e5e3e9;
  border-right: 1px solid #dbd8e0;
}
.bs-sidebar .nav > .active > a,
.bs-sidebar .nav > .active:hover > a,
.bs-sidebar .nav > .active:focus > a {
  font-weight: bold;
  color: #563d7c;
  background-color: transparent;
  border-right: 1px solid #563d7c;
}

/* Nav: second level (shown on .active) */
.bs-sidebar .nav .nav {
  display: none; /* Hide by default, but at >768px, show it */
  margin-bottom: 8px;
}
.bs-sidebar .nav .nav > li > a {
  padding-top:    3px;
  padding-bottom: 3px;
  padding-left: 30px;
  font-size: 90%;
}

/* Show and affix the side nav when space allows it */
@media screen and (min-width: 992px) {
  .bs-sidebar .nav > .active > ul {
    display: block;
  }
  /* Widen the fixed sidebar */
  .bs-sidebar.affix,
  .bs-sidebar.affix-bottom {
    width: 213px;
  }
  .bs-sidebar.affix {
    position: fixed; /* Undo the static from mobile first approach */
    top: 30px;
  }
  .bs-sidebar.affix-bottom {
    position: absolute; /* Undo the static from mobile first approach */
  }
  .bs-sidebar.affix-bottom .bs-sidenav,
  .bs-sidebar.affix .bs-sidenav {
    margin-top: 0;
    margin-bottom: 0;
  }
}
@media screen and (min-width: 1200px) {
  /* Widen the fixed sidebar again */
  .bs-sidebar.affix-bottom,
  .bs-sidebar.affix {
    width: 263px;
  }
}


/*
 * Docs sections
 *
 * Content blocks for each component or feature.
 */

/* Space things out */
.bs-docs-section + .bs-docs-section {
  padding-top: 40px;
}

/* Janky fix for preventing navbar from overlapping */
h1[id] {
  padding-top: 80px;
  margin-top: -45px;
}


/*
 * Callouts
 *
 * Not quite alerts, but custom and helpful notes for folks reading the docs.
 * Requires a base and modifier class.
 */

/* Common styles for all types */
.bs-callout {
  margin: 20px 0;
  padding: 15px 30px 15px 15px;
  border-left: 5px solid #eee;
}
.bs-callout h4 {
  margin-top: 0;
}
.bs-callout p:last-child {
  margin-bottom: 0;
}
.bs-callout code,
.bs-callout .highlight {
  background-color: #fff;
}

/* Variations */
.bs-callout-danger {
  background-color: #fcf2f2;
  border-color: #dFb5b4;
}
.bs-callout-warning {
  background-color: #fefbed;
  border-color: #f1e7bc;
}
.bs-callout-info {
  background-color: #f0f7fd;
  border-color: #d0e3f0;
}


/*
 * Grid examples
 *
 * Highlight the grid columns within the docs so folks can see their padding,
 * alignment, sizing, etc.
 */

.show-grid {
  margin-bottom: 15px;
}
.show-grid [class^="col-"] {
  padding-top: 10px;
  padding-bottom: 10px;
  background-color: #eee;
  border: 1px solid #ddd;
  background-color: rgba(86,61,124,.15);
  border: 1px solid rgba(86,61,124,.2);
}


/*
 * Examples
 *
 * Isolated sections of example content for each component or feature. Usually
 * followed by a code snippet.
 */

.bs-example {
  position: relative;
  padding: 45px 15px 15px;
  margin: 0 -15px 15px;
  background-color: #fafafa;
  box-shadow: inset 0 3px 6px rgba(0,0,0,.05);
  border-color: #e5e5e5 #eee #eee;
  border-style: solid;
  border-width: 1px 0;
}
/* Echo out a label for the example */
.bs-example:after {
  content: "Example";
  position: absolute;
  top:  15px;
  left: 15px;
  font-size: 12px;
  font-weight: bold;
  color: #bbb;
  text-transform: uppercase;
  letter-spacing: 1px;
}

/* Tweak display of the code snippets when following an example */
.bs-example + .highlight {
  margin: -15px -15px 15px;
  border-radius: 0;
  border-width: 0 0 1px;
}

/* Make the examples and snippets not full-width */
@media screen and (min-width: 768px) {
  .bs-example {
    margin-left: 0;
    margin-right: 0;
    background-color: #fff;
    border-width: 1px;
    border-color: #ddd;
    border-radius: 4px 4px 0 0;
    box-shadow: none;
  }
  .bs-example + .highlight {
    margin-top: -16px;
    margin-left: 0;
    margin-right: 0;
    border-width: 1px;
    border-bottom-left-radius: 4px;
    border-bottom-right-radius: 4px;
  }
}

/* Tweak content of examples for optimum awesome */
.bs-example > p:last-child,
.bs-example > ul:last-child,
.bs-example > ol:last-child,
.bs-example > blockquote:last-child,
.bs-example > .form-control:last-child,
.bs-example > .table:last-child,
.bs-example > .navbar:last-child,
.bs-example > .jumbotron:last-child,
.bs-example > .alert:last-child,
.bs-example > .panel:last-child,
.bs-example > .list-group:last-child,
.bs-example > .well:last-child,
.bs-example > .progress:last-child,
.bs-example > .table-responsive:last-child > .table {
  margin-bottom: 0;
}
.bs-example > p > .close {
  float: none;
}

/* Typography */
.bs-example-type .table td:last-child {
  color: #999;
  vertical-align: middle;
}
.bs-example-type .table td {
  padding: 15px 0;
  border-color: #eee;
}
.bs-example-type .table tr:first-child td {
  border-top: 0;
}
.bs-example-type h1,
.bs-example-type h2,
.bs-example-type h3,
.bs-example-type h4,
.bs-example-type h5,
.bs-example-type h6 {
  margin: 0;
}

/* Images */
.bs-example > .img-circle,
.bs-example > .img-rounded,
.bs-example > .img-thumbnail {
  margin: 5px;
}

/* Buttons */
.bs-example > .btn,
.bs-example > .btn-group {
  margin-top: 5px;
  margin-bottom: 5px;
}
.bs-example > .btn-toolbar + .btn-toolbar {
  margin-top: 10px;
}

/* Forms */
.bs-example-control-sizing select,
.bs-example-control-sizing input[type="text"] + input[type="text"] {
  margin-top: 10px;
}
.bs-example-form .input-group {
  margin-bottom: 10px;
}
.bs-example > textarea.form-control {
  resize: vertical;
}

/* List groups */
.bs-example > .list-group {
  max-width: 400px;
}

/* Navbars */
.bs-example .navbar:last-child {
  margin-bottom: 0;
}
.bs-navbar-top-example,
.bs-navbar-bottom-example {
  z-index: 1;
  padding: 0;
  overflow: hidden; /* cut the drop shadows off */
}
.bs-navbar-top-example .navbar-header,
.bs-navbar-bottom-example .navbar-header {
  margin-left: 0;
}
.bs-navbar-top-example .navbar-fixed-top,
.bs-navbar-bottom-example .navbar-fixed-bottom {
  position: relative;
  margin-left: 0;
  margin-right: 0;
}
.bs-navbar-top-example {
  padding-bottom: 45px;
}
.bs-navbar-top-example:after {
  top: auto;
  bottom: 15px;
}
.bs-navbar-top-example .navbar-fixed-top {
  top: -1px;
}
.bs-navbar-bottom-example {
  padding-top: 45px;
}
.bs-navbar-bottom-example .navbar-fixed-bottom {
  bottom: -1px;
}
.bs-navbar-bottom-example .navbar {
  margin-bottom: 0;
}
@media (min-width: 768px) {
  .bs-navbar-top-example .navbar-fixed-top,
  .bs-navbar-bottom-example .navbar-fixed-bottom {
    position: absolute;
  }
  .bs-navbar-top-example {
    border-radius: 0 0 4px 4px;
  }
  .bs-navbar-bottom-example {
    border-radius: 4px 4px 0 0;
  }
}

/* Pagination */
.bs-example .pagination {
  margin-top: 10px;
  margin-bottom: 10px;
}

/* Pager */
.bs-example > .pager {
  margin-top: 0;
}

/* Example modals */
.bs-example-modal {
  background-color: #f5f5f5;
}
.bs-example-modal .modal {
  position: relative;
  top: auto;
  right: auto;
  left: auto;
  bottom: auto;
  z-index: 1;
  display: block;
}
.bs-example-modal .modal-dialog {
  left: auto;
  margin-left: auto;
  margin-right: auto;
}

/* Example dropdowns */
.bs-example > .dropdown > .dropdown-menu {
  position: static;
  display: block;
  margin-bottom: 5px;
}

/* Example tabbable tabs */
.bs-example-tabs .nav-tabs {
  margin-bottom: 15px;
}

/* Tooltips */
.bs-example-tooltips {
  text-align: center;
}
.bs-example-tooltips > .btn {
  margin-top: 5px;
  margin-bottom: 5px;
}

/* Popovers */
.bs-example-popover {
  padding-bottom: 24px;
  background-color: #f9f9f9;
}
.bs-example-popover .popover {
  position: relative;
  display: block;
  float: left;
  width: 260px;
  margin: 20px;
}

/* Scrollspy demo on fixed height div */
.scrollspy-example {
  position: relative;
  height: 200px;
  margin-top: 10px;
  overflow: auto;
}


/*
 * Code snippets
 *
 * Generated via Pygments and Jekyll, these are snippets of HTML, CSS, and JS.
 */

.highlight {
  display: none; /* hidden by default, until >480px */
  padding: 9px 14px;
  margin-bottom: 14px;
  background-color: #f7f7f9;
  border: 1px solid #e1e1e8;
  border-radius: 4px;
}
.highlight pre {
  padding: 0;
  margin-top: 0;
  margin-bottom: 0;
  background-color: transparent;
  border: 0;
  white-space: nowrap;
}
.highlight pre code {
  font-size: inherit;
  color: #333; /* Effectively the base text color */
}
.highlight pre .lineno {
  display: inline-block;
  width: 22px;
  padding-right: 5px;
  margin-right: 10px;
  text-align: right;
  color: #bebec5;
}

/* Show code snippets when we have the space */
@media screen and (min-width: 481px) {
  .highlight {
    display: block;
  }
}


/*
 * Responsive tests
 *
 * Generate a set of tests to show the responsive utilities in action.
 */

/* Responsive (scrollable) doc tables */
.table-responsive .highlight pre {
  white-space: normal;
}

/* Utility classes table  */
.bs-table th small,
.responsive-utilities th small {
  display: block;
  font-weight: normal;
  color: #999;
}
.responsive-utilities tbody th {
  font-weight: normal;
}
.responsive-utilities td {
  text-align: center;
}
.responsive-utilities td.is-visible {
  color: #468847;
  background-color: #dff0d8 !important;
}
.responsive-utilities td.is-hidden {
  color: #ccc;
  background-color: #f9f9f9 !important;
}

/* Responsive tests */
.responsive-utilities-test {
  margin-top: 5px;
}
.responsive-utilities-test .col-xs-6 {
  margin-bottom: 10px;
}
.responsive-utilities-test span {
  padding: 15px 10px;
  font-size: 14px;
  font-weight: bold;
  line-height: 1.1;
  text-align: center;
  border-radius: 4px;
}
.visible-on .col-xs-6 .hidden-xs,
.visible-on .col-xs-6 .hidden-sm,
.visible-on .col-xs-6 .hidden-md,
.visible-on .col-xs-6 .hidden-lg,
.hidden-on .col-xs-6 .visible-xs,
.hidden-on .col-xs-6 .visible-sm,
.hidden-on .col-xs-6 .visible-md,
.hidden-on .col-xs-6 .visible-lg {
  color: #999;
  border: 1px solid #ddd;
}
.visible-on .col-xs-6 .visible-xs,
.visible-on .col-xs-6 .visible-sm,
.visible-on .col-xs-6 .visible-md,
.visible-on .col-xs-6 .visible-lg,
.hidden-on .col-xs-6 .hidden-xs,
.hidden-on .col-xs-6 .hidden-sm,
.hidden-on .col-xs-6 .hidden-md,
.hidden-on .col-xs-6 .hidden-lg {
  color: #468847;
  background-color: #dff0d8;
  border: 1px solid #d6e9c6;
}


/*
 * Glyphicons
 *
 * Special styles for displaying the icons and their classes in the docs.
 */

.bs-glyphicons {
  padding-left: 0;
  padding-bottom: 1px;
  margin-bottom: 20px;
  list-style: none;
  overflow: hidden;
}
.bs-glyphicons li {
  float: left;
  width: 25%;
  height: 115px;
  padding: 10px;
  margin: 0 -1px -1px 0;
  font-size: 12px;
  line-height: 1.4;
  text-align: center;
  border: 1px solid #ddd;
}
.bs-glyphicons .glyphicon {
  display: block;
  margin: 5px auto 10px;
  font-size: 24px;
}
.bs-glyphicons li:hover {
  background-color: rgba(86,61,124,.1);
}

@media (min-width: 768px) {
  .bs-glyphicons li {
    width: 12.5%;
  }
}


/*
 * Customizer
 *
 * Since this is so form control heavy, we have quite a few styles to customize
 * the display of inputs, headings, and more. Also included are all the download
 * buttons and actions.
 */

.bs-customizer .toggle {
  float: right;
  margin-top: 85px; /* On account of ghetto navbar fix */
}

/* Headings and form contrls */
.bs-customizer label {
  margin-top: 10px;
  font-weight: 500;
  color: #444;
}
.bs-customizer h2 {
  margin-top: 0;
  margin-bottom: 5px;
  padding-top: 30px;
}
.bs-customizer h4 {
  margin-top: 15px;
}
.bs-customizer input[type="text"] {
  font-family: Menlo, Monaco, Consolas, "Courier New", monospace;
  background-color: #fafafa;
}
.bs-customizer .help-block {
  font-size: 12px;
}

/* For the variables, use regular weight */
#less-section label {
  font-weight: normal;
}

/* Downloads */
.bs-customize-download .btn-outline {
  padding: 20px;
}

/* Error handling */
.bs-customizer-alert {
  position: fixed;
  top: 51px;
  left: 0;
  right: 0;
  z-index: 1030;
  padding: 15px 0;
  color: #fff;
  background-color: #d9534f;
  box-shadow: inset 0 1px 0 rgba(255,255,255,.25);
  border-bottom: 1px solid #b94441;
}
.bs-customizer-alert .close {
  margin-top: -4px;
  font-size: 24px;
}
.bs-customizer-alert p {
  margin-bottom: 0;
}
.bs-customizer-alert .glyphicon {
  margin-right: 5px;
}
.bs-customizer-alert pre {
  margin: 10px 0 0;
  color: #fff;
  background-color: #a83c3a;
  border-color: #973634;
  box-shadow: inset 0 2px 4px rgba(0,0,0,.05), 0 1px 0 rgba(255,255,255,.1);
}


/*
 * Miscellaneous
 *
 * Odds and ends for optimum docs display.
 */

/* Examples gallery: space out content better */
.bs-examples h4 {
  margin-bottom: 5px;
}
.bs-examples p {
  margin-bottom: 20px;
}

/* Pseudo :focus state for showing how it looks in the docs */
#focusedInput {
  border-color: rgba(82,168,236,.8);
  outline: 0;
  outline: thin dotted \9; /* IE6-9 */
  -moz-box-shadow: 0 0 8px rgba(82,168,236,.6);
       box-shadow: 0 0 8px rgba(82,168,236,.6);
}

/* Better spacing on download options in getting started */
.bs-docs-dl-options h4 {
  margin-top: 15px;
  margin-bottom: 5px;
}

/* Feature highlights */

#feature-highlights {
  font-size: 0.7em;
  list-style: none;
  padding: 0;
}
#exampleInlineTags {
  width: 400px;
}
@media (min-width: 768px) {
  #feature-highlights {
    padding: inherit;
    list-style: disc
  }
}
@media (min-width: 992px) {
  #feature-highlights {
    list-style: disc;
    position: absolute;
    top: 20px;
    right: 0;
    font-size: 0.9em;
  }
}

/* Fixed width input examples */
.fluid-tokenfield {
  width: 50%;
}
.fixed-tokenfield {
  width: 300px;
}docs-assets/js/affix.js000066400000007707152434262010011057 0ustar00/* ========================================================================
 * Bootstrap: affix.js v3.1.1
 * http://getbootstrap.com/javascript/#affix
 * ========================================================================
 * Copyright 2011-2014 Twitter, Inc.
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
 * ======================================================================== */


+function ($) {
  'use strict';

  // AFFIX CLASS DEFINITION
  // ======================

  var Affix = function (element, options) {
    this.options = $.extend({}, Affix.DEFAULTS, options)
    this.$window = $(window)
      .on('scroll.bs.affix.data-api', $.proxy(this.checkPosition, this))
      .on('click.bs.affix.data-api',  $.proxy(this.checkPositionWithEventLoop, this))

    this.$element     = $(element)
    this.affixed      =
    this.unpin        =
    this.pinnedOffset = null

    this.checkPosition()
  }

  Affix.RESET = 'affix affix-top affix-bottom'

  Affix.DEFAULTS = {
    offset: 0
  }

  Affix.prototype.getPinnedOffset = function () {
    if (this.pinnedOffset) return this.pinnedOffset
    this.$element.removeClass(Affix.RESET).addClass('affix')
    var scrollTop = this.$window.scrollTop()
    var position  = this.$element.offset()
    return (this.pinnedOffset = position.top - scrollTop)
  }

  Affix.prototype.checkPositionWithEventLoop = function () {
    setTimeout($.proxy(this.checkPosition, this), 1)
  }

  Affix.prototype.checkPosition = function () {
    if (!this.$element.is(':visible')) return

    var scrollHeight = $(document).height()
    var scrollTop    = this.$window.scrollTop()
    var position     = this.$element.offset()
    var offset       = this.options.offset
    var offsetTop    = offset.top
    var offsetBottom = offset.bottom

    if (this.affixed == 'top') position.top += scrollTop

    if (typeof offset != 'object')         offsetBottom = offsetTop = offset
    if (typeof offsetTop == 'function')    offsetTop    = offset.top(this.$element)
    if (typeof offsetBottom == 'function') offsetBottom = offset.bottom(this.$element)

    var affix = this.unpin   != null && (scrollTop + this.unpin <= position.top) ? false :
                offsetBottom != null && (position.top + this.$element.height() >= scrollHeight - offsetBottom) ? 'bottom' :
                offsetTop    != null && (scrollTop <= offsetTop) ? 'top' : false

    if (this.affixed === affix) return
    if (this.unpin) this.$element.css('top', '')

    var affixType = 'affix' + (affix ? '-' + affix : '')
    var e         = $.Event(affixType + '.bs.affix')

    this.$element.trigger(e)

    if (e.isDefaultPrevented()) return

    this.affixed = affix
    this.unpin = affix == 'bottom' ? this.getPinnedOffset() : null

    this.$element
      .removeClass(Affix.RESET)
      .addClass(affixType)
      .trigger($.Event(affixType.replace('affix', 'affixed')))

    if (affix == 'bottom') {
      this.$element.offset({ top: scrollHeight - offsetBottom - this.$element.height() })
    }
  }


  // AFFIX PLUGIN DEFINITION
  // =======================

  var old = $.fn.affix

  $.fn.affix = function (option) {
    return this.each(function () {
      var $this   = $(this)
      var data    = $this.data('bs.affix')
      var options = typeof option == 'object' && option

      if (!data) $this.data('bs.affix', (data = new Affix(this, options)))
      if (typeof option == 'string') data[option]()
    })
  }

  $.fn.affix.Constructor = Affix


  // AFFIX NO CONFLICT
  // =================

  $.fn.affix.noConflict = function () {
    $.fn.affix = old
    return this
  }


  // AFFIX DATA-API
  // ==============

  $(window).on('load', function () {
    $('[data-spy="affix"]').each(function () {
      var $spy = $(this)
      var data = $spy.data()

      data.offset = data.offset || {}

      if (data.offsetBottom) data.offset.bottom = data.offsetBottom
      if (data.offsetTop)    data.offset.top    = data.offsetTop

      $spy.affix(data)
    })
  })

}(jQuery);
docs-assets/js/typeahead.bundle.js000066400000201300152434262010013157 0ustar00/*!
 * typeahead.js 0.10.1
 * https://github.com/twitter/typeahead.js
 * Copyright 2013 Twitter, Inc. and other contributors; Licensed MIT
 */

(function($) {
    var _ = {
        isMsie: function() {
            return /(msie|trident)/i.test(navigator.userAgent) ? navigator.userAgent.match(/(msie |rv:)(\d+(.\d+)?)/i)[2] : false;
        },
        isBlankString: function(str) {
            return !str || /^\s*$/.test(str);
        },
        escapeRegExChars: function(str) {
            return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
        },
        isString: function(obj) {
            return typeof obj === "string";
        },
        isNumber: function(obj) {
            return typeof obj === "number";
        },
        isArray: $.isArray,
        isFunction: $.isFunction,
        isObject: $.isPlainObject,
        isUndefined: function(obj) {
            return typeof obj === "undefined";
        },
        bind: $.proxy,
        each: function(collection, cb) {
            $.each(collection, reverseArgs);
            function reverseArgs(index, value) {
                return cb(value, index);
            }
        },
        map: $.map,
        filter: $.grep,
        every: function(obj, test) {
            var result = true;
            if (!obj) {
                return result;
            }
            $.each(obj, function(key, val) {
                if (!(result = test.call(null, val, key, obj))) {
                    return false;
                }
            });
            return !!result;
        },
        some: function(obj, test) {
            var result = false;
            if (!obj) {
                return result;
            }
            $.each(obj, function(key, val) {
                if (result = test.call(null, val, key, obj)) {
                    return false;
                }
            });
            return !!result;
        },
        mixin: $.extend,
        getUniqueId: function() {
            var counter = 0;
            return function() {
                return counter++;
            };
        }(),
        templatify: function templatify(obj) {
            return $.isFunction(obj) ? obj : template;
            function template() {
                return String(obj);
            }
        },
        defer: function(fn) {
            setTimeout(fn, 0);
        },
        debounce: function(func, wait, immediate) {
            var timeout, result;
            return function() {
                var context = this, args = arguments, later, callNow;
                later = function() {
                    timeout = null;
                    if (!immediate) {
                        result = func.apply(context, args);
                    }
                };
                callNow = immediate && !timeout;
                clearTimeout(timeout);
                timeout = setTimeout(later, wait);
                if (callNow) {
                    result = func.apply(context, args);
                }
                return result;
            };
        },
        throttle: function(func, wait) {
            var context, args, timeout, result, previous, later;
            previous = 0;
            later = function() {
                previous = new Date();
                timeout = null;
                result = func.apply(context, args);
            };
            return function() {
                var now = new Date(), remaining = wait - (now - previous);
                context = this;
                args = arguments;
                if (remaining <= 0) {
                    clearTimeout(timeout);
                    timeout = null;
                    previous = now;
                    result = func.apply(context, args);
                } else if (!timeout) {
                    timeout = setTimeout(later, remaining);
                }
                return result;
            };
        },
        noop: function() {}
    };
    var VERSION = "0.10.1";
    var LruCache = function(root, undefined) {
        function LruCache(maxSize) {
            this.maxSize = maxSize || 100;
            this.size = 0;
            this.hash = {};
            this.list = new List();
        }
        _.mixin(LruCache.prototype, {
            set: function set(key, val) {
                var tailItem = this.list.tail, node;
                if (this.size >= this.maxSize) {
                    this.list.remove(tailItem);
                    delete this.hash[tailItem.key];
                }
                if (node = this.hash[key]) {
                    node.val = val;
                    this.list.moveToFront(node);
                } else {
                    node = new Node(key, val);
                    this.list.add(node);
                    this.hash[key] = node;
                    this.size++;
                }
            },
            get: function get(key) {
                var node = this.hash[key];
                if (node) {
                    this.list.moveToFront(node);
                    return node.val;
                }
            }
        });
        function List() {
            this.head = this.tail = null;
        }
        _.mixin(List.prototype, {
            add: function add(node) {
                if (this.head) {
                    node.next = this.head;
                    this.head.prev = node;
                }
                this.head = node;
                this.tail = this.tail || node;
            },
            remove: function remove(node) {
                node.prev ? node.prev.next = node.next : this.head = node.next;
                node.next ? node.next.prev = node.prev : this.tail = node.prev;
            },
            moveToFront: function(node) {
                this.remove(node);
                this.add(node);
            }
        });
        function Node(key, val) {
            this.key = key;
            this.val = val;
            this.prev = this.next = null;
        }
        return LruCache;
    }(this);
    var PersistentStorage = function() {
        var ls, methods;
        try {
            ls = window.localStorage;
            ls.setItem("~~~", "!");
            ls.removeItem("~~~");
        } catch (err) {
            ls = null;
        }
        function PersistentStorage(namespace) {
            this.prefix = [ "__", namespace, "__" ].join("");
            this.ttlKey = "__ttl__";
            this.keyMatcher = new RegExp("^" + this.prefix);
        }
        if (ls && window.JSON) {
            methods = {
                _prefix: function(key) {
                    return this.prefix + key;
                },
                _ttlKey: function(key) {
                    return this._prefix(key) + this.ttlKey;
                },
                get: function(key) {
                    if (this.isExpired(key)) {
                        this.remove(key);
                    }
                    return decode(ls.getItem(this._prefix(key)));
                },
                set: function(key, val, ttl) {
                    if (_.isNumber(ttl)) {
                        ls.setItem(this._ttlKey(key), encode(now() + ttl));
                    } else {
                        ls.removeItem(this._ttlKey(key));
                    }
                    return ls.setItem(this._prefix(key), encode(val));
                },
                remove: function(key) {
                    ls.removeItem(this._ttlKey(key));
                    ls.removeItem(this._prefix(key));
                    return this;
                },
                clear: function() {
                    var i, key, keys = [], len = ls.length;
                    for (i = 0; i < len; i++) {
                        if ((key = ls.key(i)).match(this.keyMatcher)) {
                            keys.push(key.replace(this.keyMatcher, ""));
                        }
                    }
                    for (i = keys.length; i--; ) {
                        this.remove(keys[i]);
                    }
                    return this;
                },
                isExpired: function(key) {
                    var ttl = decode(ls.getItem(this._ttlKey(key)));
                    return _.isNumber(ttl) && now() > ttl ? true : false;
                }
            };
        } else {
            methods = {
                get: _.noop,
                set: _.noop,
                remove: _.noop,
                clear: _.noop,
                isExpired: _.noop
            };
        }
        _.mixin(PersistentStorage.prototype, methods);
        return PersistentStorage;
        function now() {
            return new Date().getTime();
        }
        function encode(val) {
            return JSON.stringify(_.isUndefined(val) ? null : val);
        }
        function decode(val) {
            return JSON.parse(val);
        }
    }();
    var Transport = function() {
        var pendingRequestsCount = 0, pendingRequests = {}, maxPendingRequests = 6, requestCache = new LruCache(10);
        function Transport(o) {
            o = o || {};
            this._send = o.transport ? callbackToDeferred(o.transport) : $.ajax;
            this._get = o.rateLimiter ? o.rateLimiter(this._get) : this._get;
        }
        Transport.setMaxPendingRequests = function setMaxPendingRequests(num) {
            maxPendingRequests = num;
        };
        Transport.resetCache = function clearCache() {
            requestCache = new LruCache(10);
        };
        _.mixin(Transport.prototype, {
            _get: function(url, o, cb) {
                var that = this, jqXhr;
                if (jqXhr = pendingRequests[url]) {
                    jqXhr.done(done);
                } else if (pendingRequestsCount < maxPendingRequests) {
                    pendingRequestsCount++;
                    pendingRequests[url] = this._send(url, o).done(done).always(always);
                } else {
                    this.onDeckRequestArgs = [].slice.call(arguments, 0);
                }
                function done(resp) {
                    cb && cb(resp);
                    requestCache.set(url, resp);
                }
                function always() {
                    pendingRequestsCount--;
                    delete pendingRequests[url];
                    if (that.onDeckRequestArgs) {
                        that._get.apply(that, that.onDeckRequestArgs);
                        that.onDeckRequestArgs = null;
                    }
                }
            },
            get: function(url, o, cb) {
                var that = this, resp;
                if (_.isFunction(o)) {
                    cb = o;
                    o = {};
                }
                if (resp = requestCache.get(url)) {
                    _.defer(function() {
                        cb && cb(resp);
                    });
                } else {
                    this._get(url, o, cb);
                }
                return !!resp;
            }
        });
        return Transport;
        function callbackToDeferred(fn) {
            return function customSendWrapper(url, o) {
                var deferred = $.Deferred();
                fn(url, o, onSuccess, onError);
                return deferred;
                function onSuccess(resp) {
                    _.defer(function() {
                        deferred.resolve(resp);
                    });
                }
                function onError(err) {
                    _.defer(function() {
                        deferred.reject(err);
                    });
                }
            };
        }
    }();
    var SearchIndex = function() {
        function SearchIndex(o) {
            o = o || {};
            if (!o.datumTokenizer || !o.queryTokenizer) {
                $.error("datumTokenizer and queryTokenizer are both required");
            }
            this.datumTokenizer = o.datumTokenizer;
            this.queryTokenizer = o.queryTokenizer;
            this.datums = [];
            this.trie = newNode();
        }
        _.mixin(SearchIndex.prototype, {
            bootstrap: function bootstrap(o) {
                this.datums = o.datums;
                this.trie = o.trie;
            },
            add: function(data) {
                var that = this;
                data = _.isArray(data) ? data : [ data ];
                _.each(data, function(datum) {
                    var id, tokens;
                    id = that.datums.push(datum) - 1;
                    tokens = normalizeTokens(that.datumTokenizer(datum));
                    _.each(tokens, function(token) {
                        var node, chars, ch, ids;
                        node = that.trie;
                        chars = token.split("");
                        while (ch = chars.shift()) {
                            node = node.children[ch] || (node.children[ch] = newNode());
                            node.ids.push(id);
                        }
                    });
                });
            },
            get: function get(query) {
                var that = this, tokens, matches;
                tokens = normalizeTokens(this.queryTokenizer(query));
                _.each(tokens, function(token) {
                    var node, chars, ch, ids;
                    if (matches && matches.length === 0) {
                        return false;
                    }
                    node = that.trie;
                    chars = token.split("");
                    while (node && (ch = chars.shift())) {
                        node = node.children[ch];
                    }
                    if (node && chars.length === 0) {
                        ids = node.ids.slice(0);
                        matches = matches ? getIntersection(matches, ids) : ids;
                    } else {
                        matches = [];
                        return false;
                    }
                });
                return matches ? _.map(unique(matches), function(id) {
                    return that.datums[id];
                }) : [];
            },
            serialize: function serialize() {
                return {
                    datums: this.datums,
                    trie: this.trie
                };
            }
        });
        return SearchIndex;
        function normalizeTokens(tokens) {
            tokens = _.filter(tokens, function(token) {
                return !!token;
            });
            tokens = _.map(tokens, function(token) {
                return token.toLowerCase();
            });
            return tokens;
        }
        function newNode() {
            return {
                ids: [],
                children: {}
            };
        }
        function unique(array) {
            var seen = {}, uniques = [];
            for (var i = 0; i < array.length; i++) {
                if (!seen[array[i]]) {
                    seen[array[i]] = true;
                    uniques.push(array[i]);
                }
            }
            return uniques;
        }
        function getIntersection(arrayA, arrayB) {
            var ai = 0, bi = 0, intersection = [];
            arrayA = arrayA.sort(compare);
            arrayB = arrayB.sort(compare);
            while (ai < arrayA.length && bi < arrayB.length) {
                if (arrayA[ai] < arrayB[bi]) {
                    ai++;
                } else if (arrayA[ai] > arrayB[bi]) {
                    bi++;
                } else {
                    intersection.push(arrayA[ai]);
                    ai++;
                    bi++;
                }
            }
            return intersection;
            function compare(a, b) {
                return a - b;
            }
        }
    }();
    var oParser = function() {
        return {
            local: getLocal,
            prefetch: getPrefetch,
            remote: getRemote
        };
        function getLocal(o) {
            var local = o.local || null;
            if (_.isFunction(local)) {
                local = local.call(null);
            }
            return local;
        }
        function getPrefetch(o) {
            var prefetch, defaults;
            defaults = {
                url: null,
                thumbprint: "",
                ttl: 24 * 60 * 60 * 1e3,
                filter: null,
                ajax: {}
            };
            if (prefetch = o.prefetch || null) {
                prefetch = _.isString(prefetch) ? {
                    url: prefetch
                } : prefetch;
                prefetch = _.mixin(defaults, prefetch);
                prefetch.thumbprint = VERSION + prefetch.thumbprint;
                prefetch.ajax.type = prefetch.ajax.type || "GET";
                prefetch.ajax.dataType = prefetch.ajax.dataType || "json";
                !prefetch.url && $.error("prefetch requires url to be set");
            }
            return prefetch;
        }
        function getRemote(o) {
            var remote, defaults;
            defaults = {
                url: null,
                wildcard: "%QUERY",
                replace: null,
                rateLimitBy: "debounce",
                rateLimitWait: 300,
                send: null,
                filter: null,
                ajax: {}
            };
            if (remote = o.remote || null) {
                remote = _.isString(remote) ? {
                    url: remote
                } : remote;
                remote = _.mixin(defaults, remote);
                remote.rateLimiter = /^throttle$/i.test(remote.rateLimitBy) ? byThrottle(remote.rateLimitWait) : byDebounce(remote.rateLimitWait);
                remote.ajax.type = remote.ajax.type || "GET";
                remote.ajax.dataType = remote.ajax.dataType || "json";
                delete remote.rateLimitBy;
                delete remote.rateLimitWait;
                !remote.url && $.error("remote requires url to be set");
            }
            return remote;
            function byDebounce(wait) {
                return function(fn) {
                    return _.debounce(fn, wait);
                };
            }
            function byThrottle(wait) {
                return function(fn) {
                    return _.throttle(fn, wait);
                };
            }
        }
    }();
    var Bloodhound = window.Bloodhound = function() {
        var keys;
        keys = {
            data: "data",
            protocol: "protocol",
            thumbprint: "thumbprint"
        };
        function Bloodhound(o) {
            if (!o || !o.local && !o.prefetch && !o.remote) {
                $.error("one of local, prefetch, or remote is required");
            }
            this.limit = o.limit || 5;
            this.sorter = getSorter(o.sorter);
            this.dupDetector = o.dupDetector || ignoreDuplicates;
            this.local = oParser.local(o);
            this.prefetch = oParser.prefetch(o);
            this.remote = oParser.remote(o);
            this.cacheKey = this.prefetch ? this.prefetch.cacheKey || this.prefetch.url : null;
            this.index = new SearchIndex({
                datumTokenizer: o.datumTokenizer,
                queryTokenizer: o.queryTokenizer
            });
            this.storage = this.cacheKey ? new PersistentStorage(this.cacheKey) : null;
        }
        Bloodhound.tokenizers = {
            whitespace: function whitespaceTokenizer(s) {
                return s.split(/\s+/);
            },
            nonword: function nonwordTokenizer(s) {
                return s.split(/\W+/);
            }
        };
        _.mixin(Bloodhound.prototype, {
            _loadPrefetch: function loadPrefetch(o) {
                var that = this, serialized, deferred;
                if (serialized = this._readFromStorage(o.thumbprint)) {
                    this.index.bootstrap(serialized);
                    deferred = $.Deferred().resolve();
                } else {
                    deferred = $.ajax(o.url, o.ajax).done(handlePrefetchResponse);
                }
                return deferred;
                function handlePrefetchResponse(resp) {
                    var filtered;
                    filtered = o.filter ? o.filter(resp) : resp;
                    that.add(filtered);
                    that._saveToStorage(that.index.serialize(), o.thumbprint, o.ttl);
                }
            },
            _getFromRemote: function getFromRemote(query, cb) {
                var that = this, url, uriEncodedQuery;
                query = query || "";
                uriEncodedQuery = encodeURIComponent(query);
                url = this.remote.replace ? this.remote.replace(this.remote.url, query) : this.remote.url.replace(this.remote.wildcard, uriEncodedQuery);
                return this.transport.get(url, this.remote.ajax, handleRemoteResponse);
                function handleRemoteResponse(resp) {
                    var filtered = that.remote.filter ? that.remote.filter(resp) : resp;
                    cb(filtered);
                }
            },
            _saveToStorage: function saveToStorage(data, thumbprint, ttl) {
                if (this.storage) {
                    this.storage.set(keys.data, data, ttl);
                    this.storage.set(keys.protocol, location.protocol, ttl);
                    this.storage.set(keys.thumbprint, thumbprint, ttl);
                }
            },
            _readFromStorage: function readFromStorage(thumbprint) {
                var stored = {}, isExpired;
                if (this.storage) {
                    stored.data = this.storage.get(keys.data);
                    stored.protocol = this.storage.get(keys.protocol);
                    stored.thumbprint = this.storage.get(keys.thumbprint);
                }
                isExpired = stored.thumbprint !== thumbprint || stored.protocol !== location.protocol;
                return stored.data && !isExpired ? stored.data : null;
            },
            initialize: function initialize() {
                var that = this, deferred;
                deferred = this.prefetch ? this._loadPrefetch(this.prefetch) : $.Deferred().resolve();
                this.local && deferred.done(addLocalToIndex);
                this.transport = this.remote ? new Transport(this.remote) : null;
                this.initialize = function initialize() {
                    return deferred.promise();
                };
                return deferred.promise();
                function addLocalToIndex() {
                    that.add(that.local);
                }
            },
            add: function add(data) {
                this.index.add(data);
            },
            get: function get(query, cb) {
                var that = this, matches, cacheHit = false;
                matches = this.index.get(query);
                matches = this.sorter(matches).slice(0, this.limit);
                if (matches.length < this.limit && this.transport) {
                    cacheHit = this._getFromRemote(query, returnRemoteMatches);
                }
                !cacheHit && cb && cb(matches);
                function returnRemoteMatches(remoteMatches) {
                    var matchesWithBackfill = matches.slice(0);
                    _.each(remoteMatches, function(remoteMatch) {
                        var isDuplicate;
                        isDuplicate = _.some(matchesWithBackfill, function(match) {
                            return that.dupDetector(remoteMatch, match);
                        });
                        !isDuplicate && matchesWithBackfill.push(remoteMatch);
                        return matchesWithBackfill.length < that.limit;
                    });
                    cb && cb(that.sorter(matchesWithBackfill));
                }
            },
            ttAdapter: function ttAdapter() {
                return _.bind(this.get, this);
            }
        });
        return Bloodhound;
        function getSorter(sortFn) {
            return _.isFunction(sortFn) ? sort : noSort;
            function sort(array) {
                return array.sort(sortFn);
            }
            function noSort(array) {
                return array;
            }
        }
        function ignoreDuplicates() {
            return false;
        }
    }();
    var html = {
        wrapper: '<span class="twitter-typeahead"></span>',
        dropdown: '<span class="tt-dropdown-menu"></span>',
        dataset: '<div class="tt-dataset-%CLASS%"></div>',
        suggestions: '<span class="tt-suggestions"></span>',
        suggestion: '<div class="tt-suggestion">%BODY%</div>'
    };
    var css = {
        wrapper: {
            position: "relative",
            display: "inline-block"
        },
        hint: {
            position: "absolute",
            top: "0",
            left: "0",
            borderColor: "transparent",
            boxShadow: "none"
        },
        input: {
            position: "relative",
            verticalAlign: "top",
            backgroundColor: "transparent"
        },
        inputWithNoHint: {
            position: "relative",
            verticalAlign: "top"
        },
        dropdown: {
            position: "absolute",
            top: "100%",
            left: "0",
            zIndex: "100",
            display: "none"
        },
        suggestions: {
            display: "block"
        },
        suggestion: {
            whiteSpace: "nowrap",
            cursor: "pointer"
        },
        suggestionChild: {
            whiteSpace: "normal"
        },
        ltr: {
            left: "0",
            right: "auto"
        },
        rtl: {
            left: "auto",
            right: " 0"
        }
    };
    if (_.isMsie()) {
        _.mixin(css.input, {
            backgroundImage: "url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)"
        });
    }
    if (_.isMsie() && _.isMsie() <= 7) {
        _.mixin(css.input, {
            marginTop: "-1px"
        });
    }
    var EventBus = function() {
        var namespace = "typeahead:";
        function EventBus(o) {
            if (!o || !o.el) {
                $.error("EventBus initialized without el");
            }
            this.$el = $(o.el);
        }
        _.mixin(EventBus.prototype, {
            trigger: function(type) {
                var args = [].slice.call(arguments, 1);
                this.$el.trigger(namespace + type, args);
            }
        });
        return EventBus;
    }();
    var EventEmitter = function() {
        var splitter = /\s+/, nextTick = getNextTick();
        return {
            onSync: onSync,
            onAsync: onAsync,
            off: off,
            trigger: trigger
        };
        function on(method, types, cb, context) {
            var type;
            if (!cb) {
                return this;
            }
            types = types.split(splitter);
            cb = context ? bindContext(cb, context) : cb;
            this._callbacks = this._callbacks || {};
            while (type = types.shift()) {
                this._callbacks[type] = this._callbacks[type] || {
                    sync: [],
                    async: []
                };
                this._callbacks[type][method].push(cb);
            }
            return this;
        }
        function onAsync(types, cb, context) {
            return on.call(this, "async", types, cb, context);
        }
        function onSync(types, cb, context) {
            return on.call(this, "sync", types, cb, context);
        }
        function off(types) {
            var type;
            if (!this._callbacks) {
                return this;
            }
            types = types.split(splitter);
            while (type = types.shift()) {
                delete this._callbacks[type];
            }
            return this;
        }
        function trigger(types) {
            var that = this, type, callbacks, args, syncFlush, asyncFlush;
            if (!this._callbacks) {
                return this;
            }
            types = types.split(splitter);
            args = [].slice.call(arguments, 1);
            while ((type = types.shift()) && (callbacks = this._callbacks[type])) {
                syncFlush = getFlush(callbacks.sync, this, [ type ].concat(args));
                asyncFlush = getFlush(callbacks.async, this, [ type ].concat(args));
                syncFlush() && nextTick(asyncFlush);
            }
            return this;
        }
        function getFlush(callbacks, context, args) {
            return flush;
            function flush() {
                var cancelled;
                for (var i = 0; !cancelled && i < callbacks.length; i += 1) {
                    cancelled = callbacks[i].apply(context, args) === false;
                }
                return !cancelled;
            }
        }
        function getNextTick() {
            var nextTickFn, messageChannel;
            if (window.setImmediate) {
                nextTickFn = function nextTickSetImmediate(fn) {
                    setImmediate(function() {
                        fn();
                    });
                };
            } else {
                nextTickFn = function nextTickSetTimeout(fn) {
                    setTimeout(function() {
                        fn();
                    }, 0);
                };
            }
            return nextTickFn;
        }
        function bindContext(fn, context) {
            return fn.bind ? fn.bind(context) : function() {
                fn.apply(context, [].slice.call(arguments, 0));
            };
        }
    }();
    var highlight = function(doc) {
        var defaults = {
            node: null,
            pattern: null,
            tagName: "strong",
            className: null,
            wordsOnly: false,
            caseSensitive: false
        };
        return function hightlight(o) {
            var regex;
            o = _.mixin({}, defaults, o);
            if (!o.node || !o.pattern) {
                return;
            }
            o.pattern = _.isArray(o.pattern) ? o.pattern : [ o.pattern ];
            regex = getRegex(o.pattern, o.caseSensitive, o.wordsOnly);
            traverse(o.node, hightlightTextNode);
            function hightlightTextNode(textNode) {
                var match, patternNode;
                if (match = regex.exec(textNode.data)) {
                    wrapperNode = doc.createElement(o.tagName);
                    o.className && (wrapperNode.className = o.className);
                    patternNode = textNode.splitText(match.index);
                    patternNode.splitText(match[0].length);
                    wrapperNode.appendChild(patternNode.cloneNode(true));
                    textNode.parentNode.replaceChild(wrapperNode, patternNode);
                }
                return !!match;
            }
            function traverse(el, hightlightTextNode) {
                var childNode, TEXT_NODE_TYPE = 3;
                for (var i = 0; i < el.childNodes.length; i++) {
                    childNode = el.childNodes[i];
                    if (childNode.nodeType === TEXT_NODE_TYPE) {
                        i += hightlightTextNode(childNode) ? 1 : 0;
                    } else {
                        traverse(childNode, hightlightTextNode);
                    }
                }
            }
        };
        function getRegex(patterns, caseSensitive, wordsOnly) {
            var escapedPatterns = [], regexStr;
            for (var i = 0; i < patterns.length; i++) {
                escapedPatterns.push(_.escapeRegExChars(patterns[i]));
            }
            regexStr = wordsOnly ? "\\b(" + escapedPatterns.join("|") + ")\\b" : "(" + escapedPatterns.join("|") + ")";
            return caseSensitive ? new RegExp(regexStr) : new RegExp(regexStr, "i");
        }
    }(window.document);
    var Input = function() {
        var specialKeyCodeMap;
        specialKeyCodeMap = {
            9: "tab",
            27: "esc",
            37: "left",
            39: "right",
            13: "enter",
            38: "up",
            40: "down"
        };
        function Input(o) {
            var that = this, onBlur, onFocus, onKeydown, onInput;
            o = o || {};
            if (!o.input) {
                $.error("input is missing");
            }
            onBlur = _.bind(this._onBlur, this);
            onFocus = _.bind(this._onFocus, this);
            onKeydown = _.bind(this._onKeydown, this);
            onInput = _.bind(this._onInput, this);
            this.$hint = $(o.hint);
            this.$input = $(o.input).on("blur.tt", onBlur).on("focus.tt", onFocus).on("keydown.tt", onKeydown);
            if (this.$hint.length === 0) {
                this.setHintValue = this.getHintValue = this.clearHint = _.noop;
            }
            if (!_.isMsie()) {
                this.$input.on("input.tt", onInput);
            } else {
                this.$input.on("keydown.tt keypress.tt cut.tt paste.tt", function($e) {
                    if (specialKeyCodeMap[$e.which || $e.keyCode]) {
                        return;
                    }
                    _.defer(_.bind(that._onInput, that, $e));
                });
            }
            this.query = this.$input.val();
            this.$overflowHelper = buildOverflowHelper(this.$input);
        }
        Input.normalizeQuery = function(str) {
            return (str || "").replace(/^\s*/g, "").replace(/\s{2,}/g, " ");
        };
        _.mixin(Input.prototype, EventEmitter, {
            _onBlur: function onBlur($e) {
                this.resetInputValue();
                this.trigger("blurred");
            },
            _onFocus: function onFocus($e) {
                this.trigger("focused");
            },
            _onKeydown: function onKeydown($e) {
                var keyName = specialKeyCodeMap[$e.which || $e.keyCode];
                this._managePreventDefault(keyName, $e);
                if (keyName && this._shouldTrigger(keyName, $e)) {
                    this.trigger(keyName + "Keyed", $e);
                }
            },
            _onInput: function onInput($e) {
                this._checkInputValue();
            },
            _managePreventDefault: function managePreventDefault(keyName, $e) {
                var preventDefault, hintValue, inputValue;
                switch (keyName) {
                  case "tab":
                    hintValue = this.getHintValue();
                    inputValue = this.getInputValue();
                    preventDefault = hintValue && hintValue !== inputValue && !withModifier($e);
                    break;

                  case "up":
                  case "down":
                    preventDefault = !withModifier($e);
                    break;

                  default:
                    preventDefault = false;
                }
                preventDefault && $e.preventDefault();
            },
            _shouldTrigger: function shouldTrigger(keyName, $e) {
                var trigger;
                switch (keyName) {
                  case "tab":
                    trigger = !withModifier($e);
                    break;

                  default:
                    trigger = true;
                }
                return trigger;
            },
            _checkInputValue: function checkInputValue() {
                var inputValue, areEquivalent, hasDifferentWhitespace;
                inputValue = this.getInputValue();
                areEquivalent = areQueriesEquivalent(inputValue, this.query);
                hasDifferentWhitespace = areEquivalent ? this.query.length !== inputValue.length : false;
                if (!areEquivalent) {
                    this.trigger("queryChanged", this.query = inputValue);
                } else if (hasDifferentWhitespace) {
                    this.trigger("whitespaceChanged", this.query);
                }
            },
            focus: function focus() {
                this.$input.focus();
            },
            blur: function blur() {
                this.$input.blur();
            },
            getQuery: function getQuery() {
                return this.query;
            },
            setQuery: function setQuery(query) {
                this.query = query;
            },
            getInputValue: function getInputValue() {
                return this.$input.val();
            },
            setInputValue: function setInputValue(value, silent) {
                this.$input.val(value);
                !silent && this._checkInputValue();
            },
            getHintValue: function getHintValue() {
                return this.$hint.val();
            },
            setHintValue: function setHintValue(value) {
                this.$hint.val(value);
            },
            resetInputValue: function resetInputValue() {
                this.$input.val(this.query);
            },
            clearHint: function clearHint() {
                this.$hint.val("");
            },
            getLanguageDirection: function getLanguageDirection() {
                return (this.$input.css("direction") || "ltr").toLowerCase();
            },
            hasOverflow: function hasOverflow() {
                var constraint = this.$input.width() - 2;
                this.$overflowHelper.text(this.getInputValue());
                return this.$overflowHelper.width() >= constraint;
            },
            isCursorAtEnd: function() {
                var valueLength, selectionStart, range;
                valueLength = this.$input.val().length;
                selectionStart = this.$input[0].selectionStart;
                if (_.isNumber(selectionStart)) {
                    return selectionStart === valueLength;
                } else if (document.selection) {
                    range = document.selection.createRange();
                    range.moveStart("character", -valueLength);
                    return valueLength === range.text.length;
                }
                return true;
            },
            destroy: function destroy() {
                this.$hint.off(".tt");
                this.$input.off(".tt");
                this.$hint = this.$input = this.$overflowHelper = null;
            }
        });
        return Input;
        function buildOverflowHelper($input) {
            return $('<pre aria-hidden="true"></pre>').css({
                position: "absolute",
                visibility: "hidden",
                whiteSpace: "nowrap",
                fontFamily: $input.css("font-family"),
                fontSize: $input.css("font-size"),
                fontStyle: $input.css("font-style"),
                fontVariant: $input.css("font-variant"),
                fontWeight: $input.css("font-weight"),
                wordSpacing: $input.css("word-spacing"),
                letterSpacing: $input.css("letter-spacing"),
                textIndent: $input.css("text-indent"),
                textRendering: $input.css("text-rendering"),
                textTransform: $input.css("text-transform")
            }).insertAfter($input);
        }
        function areQueriesEquivalent(a, b) {
            return Input.normalizeQuery(a) === Input.normalizeQuery(b);
        }
        function withModifier($e) {
            return $e.altKey || $e.ctrlKey || $e.metaKey || $e.shiftKey;
        }
    }();
    var Dataset = function() {
        var datasetKey = "ttDataset", valueKey = "ttValue", datumKey = "ttDatum";
        function Dataset(o) {
            o = o || {};
            o.templates = o.templates || {};
            if (!o.source) {
                $.error("missing source");
            }
            if (o.name && !isValidName(o.name)) {
                $.error("invalid dataset name: " + o.name);
            }
            this.query = null;
            this.highlight = !!o.highlight;
            this.name = o.name || _.getUniqueId();
            this.source = o.source;
            this.displayFn = getDisplayFn(o.display || o.displayKey);
            this.templates = getTemplates(o.templates, this.displayFn);
            this.$el = $(html.dataset.replace("%CLASS%", this.name));
        }
        Dataset.extractDatasetName = function extractDatasetName(el) {
            return $(el).data(datasetKey);
        };
        Dataset.extractValue = function extractDatum(el) {
            return $(el).data(valueKey);
        };
        Dataset.extractDatum = function extractDatum(el) {
            return $(el).data(datumKey);
        };
        _.mixin(Dataset.prototype, EventEmitter, {
            _render: function render(query, suggestions) {
                if (!this.$el) {
                    return;
                }
                var that = this, hasSuggestions;
                this.$el.empty();
                hasSuggestions = suggestions && suggestions.length;
                if (!hasSuggestions && this.templates.empty) {
                    this.$el.html(getEmptyHtml()).prepend(that.templates.header ? getHeaderHtml() : null).append(that.templates.footer ? getFooterHtml() : null);
                } else if (hasSuggestions) {
                    this.$el.html(getSuggestionsHtml()).prepend(that.templates.header ? getHeaderHtml() : null).append(that.templates.footer ? getFooterHtml() : null);
                }
                this.trigger("rendered");
                function getEmptyHtml() {
                    return that.templates.empty({
                        query: query,
                        isEmpty: true
                    });
                }
                function getSuggestionsHtml() {
                    var $suggestions, nodes;
                    $suggestions = $(html.suggestions).css(css.suggestions);
                    nodes = _.map(suggestions, getSuggestionNode);
                    $suggestions.append.apply($suggestions, nodes);
                    that.highlight && highlight({
                        node: $suggestions[0],
                        pattern: query
                    });
                    return $suggestions;
                    function getSuggestionNode(suggestion) {
                        var $el, innerHtml, outerHtml;
                        innerHtml = that.templates.suggestion(suggestion);
                        outerHtml = html.suggestion.replace("%BODY%", innerHtml);
                        $el = $(outerHtml).data(datasetKey, that.name).data(valueKey, that.displayFn(suggestion)).data(datumKey, suggestion);
                        $el.children().each(function() {
                            $(this).css(css.suggestionChild);
                        });
                        return $el;
                    }
                }
                function getHeaderHtml() {
                    return that.templates.header({
                        query: query,
                        isEmpty: !hasSuggestions
                    });
                }
                function getFooterHtml() {
                    return that.templates.footer({
                        query: query,
                        isEmpty: !hasSuggestions
                    });
                }
            },
            getRoot: function getRoot() {
                return this.$el;
            },
            update: function update(query) {
                var that = this;
                this.query = query;
                this.source(query, renderIfQueryIsSame);
                function renderIfQueryIsSame(suggestions) {
                    query === that.query && that._render(query, suggestions);
                }
            },
            clear: function clear() {
                this._render(this.query || "");
            },
            isEmpty: function isEmpty() {
                return this.$el.is(":empty");
            },
            destroy: function destroy() {
                this.$el = null;
            }
        });
        return Dataset;
        function getDisplayFn(display) {
            display = display || "value";
            return _.isFunction(display) ? display : displayFn;
            function displayFn(obj) {
                return obj[display];
            }
        }
        function getTemplates(templates, displayFn) {
            return {
                empty: templates.empty && _.templatify(templates.empty),
                header: templates.header && _.templatify(templates.header),
                footer: templates.footer && _.templatify(templates.footer),
                suggestion: templates.suggestion || suggestionTemplate
            };
            function suggestionTemplate(context) {
                return "<p>" + displayFn(context) + "</p>";
            }
        }
        function isValidName(str) {
            return /^[_a-zA-Z0-9-]+$/.test(str);
        }
    }();
    var Dropdown = function() {
        function Dropdown(o) {
            var that = this, onSuggestionClick, onSuggestionMouseEnter, onSuggestionMouseLeave;
            o = o || {};
            if (!o.menu) {
                $.error("menu is required");
            }
            this.isOpen = false;
            this.isEmpty = true;
            this.datasets = _.map(o.datasets, initializeDataset);
            onSuggestionClick = _.bind(this._onSuggestionClick, this);
            onSuggestionMouseEnter = _.bind(this._onSuggestionMouseEnter, this);
            onSuggestionMouseLeave = _.bind(this._onSuggestionMouseLeave, this);
            this.$menu = $(o.menu).on("click.tt", ".tt-suggestion", onSuggestionClick).on("mouseenter.tt", ".tt-suggestion", onSuggestionMouseEnter).on("mouseleave.tt", ".tt-suggestion", onSuggestionMouseLeave);
            _.each(this.datasets, function(dataset) {
                that.$menu.append(dataset.getRoot());
                dataset.onSync("rendered", that._onRendered, that);
            });
        }
        _.mixin(Dropdown.prototype, EventEmitter, {
            _onSuggestionClick: function onSuggestionClick($e) {
                this.trigger("suggestionClicked", $($e.currentTarget));
            },
            _onSuggestionMouseEnter: function onSuggestionMouseEnter($e) {
                this._removeCursor();
                this._setCursor($($e.currentTarget), true);
            },
            _onSuggestionMouseLeave: function onSuggestionMouseLeave($e) {
                this._removeCursor();
            },
            _onRendered: function onRendered() {
                this.isEmpty = _.every(this.datasets, isDatasetEmpty);
                this.isEmpty ? this._hide() : this.isOpen && this._show();
                this.trigger("datasetRendered");
                function isDatasetEmpty(dataset) {
                    return dataset.isEmpty();
                }
            },
            _hide: function() {
                this.$menu.hide();
            },
            _show: function() {
                this.$menu.css("display", "block");
            },
            _getSuggestions: function getSuggestions() {
                return this.$menu.find(".tt-suggestion");
            },
            _getCursor: function getCursor() {
                return this.$menu.find(".tt-cursor").first();
            },
            _setCursor: function setCursor($el, silent) {
                $el.first().addClass("tt-cursor");
                !silent && this.trigger("cursorMoved");
            },
            _removeCursor: function removeCursor() {
                this._getCursor().removeClass("tt-cursor");
            },
            _moveCursor: function moveCursor(increment) {
                var $suggestions, $oldCursor, newCursorIndex, $newCursor;
                if (!this.isOpen) {
                    return;
                }
                $oldCursor = this._getCursor();
                $suggestions = this._getSuggestions();
                this._removeCursor();
                newCursorIndex = $suggestions.index($oldCursor) + increment;
                newCursorIndex = (newCursorIndex + 1) % ($suggestions.length + 1) - 1;
                if (newCursorIndex === -1) {
                    this.trigger("cursorRemoved");
                    return;
                } else if (newCursorIndex < -1) {
                    newCursorIndex = $suggestions.length - 1;
                }
                this._setCursor($newCursor = $suggestions.eq(newCursorIndex));
                this._ensureVisible($newCursor);
            },
            _ensureVisible: function ensureVisible($el) {
                var elTop, elBottom, menuScrollTop, menuHeight;
                elTop = $el.position().top;
                elBottom = elTop + $el.outerHeight(true);
                menuScrollTop = this.$menu.scrollTop();
                menuHeight = this.$menu.height() + parseInt(this.$menu.css("paddingTop"), 10) + parseInt(this.$menu.css("paddingBottom"), 10);
                if (elTop < 0) {
                    this.$menu.scrollTop(menuScrollTop + elTop);
                } else if (menuHeight < elBottom) {
                    this.$menu.scrollTop(menuScrollTop + (elBottom - menuHeight));
                }
            },
            close: function close() {
                if (this.isOpen) {
                    this.isOpen = false;
                    this._removeCursor();
                    this._hide();
                    this.trigger("closed");
                }
            },
            open: function open() {
                if (!this.isOpen) {
                    this.isOpen = true;
                    !this.isEmpty && this._show();
                    this.trigger("opened");
                }
            },
            setLanguageDirection: function setLanguageDirection(dir) {
                this.$menu.css(dir === "ltr" ? css.ltr : css.rtl);
            },
            moveCursorUp: function moveCursorUp() {
                this._moveCursor(-1);
            },
            moveCursorDown: function moveCursorDown() {
                this._moveCursor(+1);
            },
            getDatumForSuggestion: function getDatumForSuggestion($el) {
                var datum = null;
                if ($el.length) {
                    datum = {
                        raw: Dataset.extractDatum($el),
                        value: Dataset.extractValue($el),
                        datasetName: Dataset.extractDatasetName($el)
                    };
                }
                return datum;
            },
            getDatumForCursor: function getDatumForCursor() {
                return this.getDatumForSuggestion(this._getCursor().first());
            },
            getDatumForTopSuggestion: function getDatumForTopSuggestion() {
                return this.getDatumForSuggestion(this._getSuggestions().first());
            },
            update: function update(query) {
                _.each(this.datasets, updateDataset);
                function updateDataset(dataset) {
                    dataset.update(query);
                }
            },
            empty: function empty() {
                _.each(this.datasets, clearDataset);
                this.isEmpty = true;
                function clearDataset(dataset) {
                    dataset.clear();
                }
            },
            isVisible: function isVisible() {
                return this.isOpen && !this.isEmpty;
            },
            destroy: function destroy() {
                this.$menu.off(".tt");
                this.$menu = null;
                _.each(this.datasets, destroyDataset);
                function destroyDataset(dataset) {
                    dataset.destroy();
                }
            }
        });
        return Dropdown;
        function initializeDataset(oDataset) {
            return new Dataset(oDataset);
        }
    }();
    var Typeahead = function() {
        var attrsKey = "ttAttrs";
        function Typeahead(o) {
            var $menu, $input, $hint, datasets;
            o = o || {};
            if (!o.input) {
                $.error("missing input");
            }
            this.autoselect = !!o.autoselect;
            this.minLength = _.isNumber(o.minLength) ? o.minLength : 1;
            this.$node = buildDomStructure(o.input, o.withHint);
            $menu = this.$node.find(".tt-dropdown-menu");
            $input = this.$node.find(".tt-input");
            $hint = this.$node.find(".tt-hint");
            this.eventBus = o.eventBus || new EventBus({
                el: $input
            });
            this.dropdown = new Dropdown({
                menu: $menu,
                datasets: o.datasets
            }).onSync("suggestionClicked", this._onSuggestionClicked, this).onSync("cursorMoved", this._onCursorMoved, this).onSync("cursorRemoved", this._onCursorRemoved, this).onSync("opened", this._onOpened, this).onSync("closed", this._onClosed, this).onAsync("datasetRendered", this._onDatasetRendered, this);
            this.input = new Input({
                input: $input,
                hint: $hint
            }).onSync("focused", this._onFocused, this).onSync("blurred", this._onBlurred, this).onSync("enterKeyed", this._onEnterKeyed, this).onSync("tabKeyed", this._onTabKeyed, this).onSync("escKeyed", this._onEscKeyed, this).onSync("upKeyed", this._onUpKeyed, this).onSync("downKeyed", this._onDownKeyed, this).onSync("leftKeyed", this._onLeftKeyed, this).onSync("rightKeyed", this._onRightKeyed, this).onSync("queryChanged", this._onQueryChanged, this).onSync("whitespaceChanged", this._onWhitespaceChanged, this);
            $menu.on("mousedown.tt", function($e) {
                if (_.isMsie() && _.isMsie() < 9) {
                    $input[0].onbeforedeactivate = function() {
                        window.event.returnValue = false;
                        $input[0].onbeforedeactivate = null;
                    };
                }
                $e.preventDefault();
            });
        }
        _.mixin(Typeahead.prototype, {
            _onSuggestionClicked: function onSuggestionClicked(type, $el) {
                var datum;
                if (datum = this.dropdown.getDatumForSuggestion($el)) {
                    this._select(datum);
                }
            },
            _onCursorMoved: function onCursorMoved() {
                var datum = this.dropdown.getDatumForCursor();
                this.input.clearHint();
                this.input.setInputValue(datum.value, true);
                this.eventBus.trigger("cursorchanged", datum.raw, datum.datasetName);
            },
            _onCursorRemoved: function onCursorRemoved() {
                this.input.resetInputValue();
                this._updateHint();
            },
            _onDatasetRendered: function onDatasetRendered() {
                this._updateHint();
            },
            _onOpened: function onOpened() {
                this._updateHint();
                this.eventBus.trigger("opened");
            },
            _onClosed: function onClosed() {
                this.input.clearHint();
                this.eventBus.trigger("closed");
            },
            _onFocused: function onFocused() {
                this.dropdown.empty();
                this.dropdown.open();
            },
            _onBlurred: function onBlurred() {
                this.dropdown.close();
            },
            _onEnterKeyed: function onEnterKeyed(type, $e) {
                var cursorDatum, topSuggestionDatum;
                cursorDatum = this.dropdown.getDatumForCursor();
                topSuggestionDatum = this.dropdown.getDatumForTopSuggestion();
                if (cursorDatum) {
                    this._select(cursorDatum);
                    $e.preventDefault();
                } else if (this.autoselect && topSuggestionDatum) {
                    this._select(topSuggestionDatum);
                    $e.preventDefault();
                }
            },
            _onTabKeyed: function onTabKeyed(type, $e) {
                var datum;
                if (datum = this.dropdown.getDatumForCursor()) {
                    this._select(datum);
                    $e.preventDefault();
                } else {
                    this._autocomplete();
                }
            },
            _onEscKeyed: function onEscKeyed() {
                this.dropdown.close();
                this.input.resetInputValue();
            },
            _onUpKeyed: function onUpKeyed() {
                var query = this.input.getQuery();
                if (!this.dropdown.isOpen && query.length >= this.minLength) {
                    this.dropdown.update(query);
                }
                this.dropdown.open();
                this.dropdown.moveCursorUp();
            },
            _onDownKeyed: function onDownKeyed() {
                var query = this.input.getQuery();
                if (!this.dropdown.isOpen && query.length >= this.minLength) {
                    this.dropdown.update(query);
                }
                this.dropdown.open();
                this.dropdown.moveCursorDown();
            },
            _onLeftKeyed: function onLeftKeyed() {
                this.dir === "rtl" && this._autocomplete();
            },
            _onRightKeyed: function onRightKeyed() {
                this.dir === "ltr" && this._autocomplete();
            },
            _onQueryChanged: function onQueryChanged(e, query) {
                this.input.clearHint();
                this.dropdown.empty();
                query.length >= this.minLength && this.dropdown.update(query);
                this.dropdown.open();
                this._setLanguageDirection();
            },
            _onWhitespaceChanged: function onWhitespaceChanged() {
                this._updateHint();
                this.dropdown.open();
            },
            _setLanguageDirection: function setLanguageDirection() {
                var dir;
                if (this.dir !== (dir = this.input.getLanguageDirection())) {
                    this.dir = dir;
                    this.$node.css("direction", dir);
                    this.dropdown.setLanguageDirection(dir);
                }
            },
            _updateHint: function updateHint() {
                var datum, inputValue, query, escapedQuery, frontMatchRegEx, match;
                datum = this.dropdown.getDatumForTopSuggestion();
                if (datum && this.dropdown.isVisible() && !this.input.hasOverflow()) {
                    inputValue = this.input.getInputValue();
                    query = Input.normalizeQuery(inputValue);
                    escapedQuery = _.escapeRegExChars(query);
                    frontMatchRegEx = new RegExp("^(?:" + escapedQuery + ")(.*$)", "i");
                    match = frontMatchRegEx.exec(datum.value);
                    this.input.setHintValue(inputValue + (match ? match[1] : ""));
                }
            },
            _autocomplete: function autocomplete() {
                var hint, query, datum;
                hint = this.input.getHintValue();
                query = this.input.getQuery();
                if (hint && query !== hint && this.input.isCursorAtEnd()) {
                    datum = this.dropdown.getDatumForTopSuggestion();
                    datum && this.input.setInputValue(datum.value);
                    this.eventBus.trigger("autocompleted", datum.raw, datum.datasetName);
                }
            },
            _select: function select(datum) {
                this.input.clearHint();
                this.input.setQuery(datum.value);
                this.input.setInputValue(datum.value, true);
                this._setLanguageDirection();
                this.eventBus.trigger("selected", datum.raw, datum.datasetName);
                this.dropdown.close();
                _.defer(_.bind(this.dropdown.empty, this.dropdown));
            },
            open: function open() {
                this.dropdown.open();
            },
            close: function close() {
                this.dropdown.close();
            },
            getQuery: function getQuery() {
                return this.input.getQuery();
            },
            setQuery: function setQuery(val) {
                this.input.setInputValue(val);
            },
            destroy: function destroy() {
                this.input.destroy();
                this.dropdown.destroy();
                destroyDomStructure(this.$node);
                this.$node = null;
            }
        });
        return Typeahead;
        function buildDomStructure(input, withHint) {
            var $input, $wrapper, $dropdown, $hint;
            $input = $(input);
            $wrapper = $(html.wrapper).css(css.wrapper);
            $dropdown = $(html.dropdown).css(css.dropdown);
            $hint = $input.clone().css(css.hint).css(getBackgroundStyles($input));
            $hint.val("").removeData().addClass("tt-hint").removeAttr("id name placeholder").prop("disabled", true).attr({
                autocomplete: "off",
                spellcheck: "false"
            });
            $input.data(attrsKey, {
                dir: $input.attr("dir"),
                autocomplete: $input.attr("autocomplete"),
                spellcheck: $input.attr("spellcheck"),
                style: $input.attr("style")
            });
            $input.addClass("tt-input").attr({
                autocomplete: "off",
                spellcheck: false
            }).css(withHint ? css.input : css.inputWithNoHint);
            try {
                !$input.attr("dir") && $input.attr("dir", "auto");
            } catch (e) {}
            return $input.wrap($wrapper).parent().prepend(withHint ? $hint : null).append($dropdown);
        }
        function getBackgroundStyles($el) {
            return {
                backgroundAttachment: $el.css("background-attachment"),
                backgroundClip: $el.css("background-clip"),
                backgroundColor: $el.css("background-color"),
                backgroundImage: $el.css("background-image"),
                backgroundOrigin: $el.css("background-origin"),
                backgroundPosition: $el.css("background-position"),
                backgroundRepeat: $el.css("background-repeat"),
                backgroundSize: $el.css("background-size")
            };
        }
        function destroyDomStructure($node) {
            var $input = $node.find(".tt-input");
            _.each($input.data(attrsKey), function(val, key) {
                _.isUndefined(val) ? $input.removeAttr(key) : $input.attr(key, val);
            });
            $input.detach().removeData(attrsKey).removeClass("tt-input").insertAfter($node);
            $node.remove();
        }
    }();
    (function() {
        var old, typeaheadKey, methods;
        old = $.fn.typeahead;
        typeaheadKey = "ttTypeahead";
        methods = {
            initialize: function initialize(o, datasets) {
                datasets = _.isArray(datasets) ? datasets : [].slice.call(arguments, 1);
                o = o || {};
                return this.each(attach);
                function attach() {
                    var $input = $(this), eventBus, typeahead;
                    _.each(datasets, function(d) {
                        d.highlight = !!o.highlight;
                    });
                    typeahead = new Typeahead({
                        input: $input,
                        eventBus: eventBus = new EventBus({
                            el: $input
                        }),
                        withHint: _.isUndefined(o.hint) ? true : !!o.hint,
                        minLength: o.minLength,
                        autoselect: o.autoselect,
                        datasets: datasets
                    });
                    $input.data(typeaheadKey, typeahead);
                }
            },
            open: function open() {
                return this.each(openTypeahead);
                function openTypeahead() {
                    var $input = $(this), typeahead;
                    if (typeahead = $input.data(typeaheadKey)) {
                        typeahead.open();
                    }
                }
            },
            close: function close() {
                return this.each(closeTypeahead);
                function closeTypeahead() {
                    var $input = $(this), typeahead;
                    if (typeahead = $input.data(typeaheadKey)) {
                        typeahead.close();
                    }
                }
            },
            val: function val(newVal) {
                return !arguments.length ? getQuery(this.first()) : this.each(setQuery);
                function setQuery() {
                    var $input = $(this), typeahead;
                    if (typeahead = $input.data(typeaheadKey)) {
                        typeahead.setQuery(newVal);
                    }
                }
                function getQuery($input) {
                    var typeahead, query;
                    if (typeahead = $input.data(typeaheadKey)) {
                        query = typeahead.getQuery();
                    }
                    return query;
                }
            },
            destroy: function destroy() {
                return this.each(unattach);
                function unattach() {
                    var $input = $(this), typeahead;
                    if (typeahead = $input.data(typeaheadKey)) {
                        typeahead.destroy();
                        $input.removeData(typeaheadKey);
                    }
                }
            }
        };
        $.fn.typeahead = function(method) {
            if (methods[method]) {
                return methods[method].apply(this, [].slice.call(arguments, 1));
            } else {
                return methods.initialize.apply(this, arguments);
            }
        };
        $.fn.typeahead.noConflict = function noConflict() {
            $.fn.typeahead = old;
            return this;
        };
    })();
})(window.jQuery);docs-assets/js/scrollspy.js000066400000010400152434262010011774 0ustar00/* ========================================================================
 * Bootstrap: scrollspy.js v3.1.1
 * http://getbootstrap.com/javascript/#scrollspy
 * ========================================================================
 * Copyright 2011-2014 Twitter, Inc.
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
 * ======================================================================== */


+function ($) {
  'use strict';

  // SCROLLSPY CLASS DEFINITION
  // ==========================

  function ScrollSpy(element, options) {
    var href
    var process  = $.proxy(this.process, this)

    this.$element       = $(element).is('body') ? $(window) : $(element)
    this.$body          = $('body')
    this.$scrollElement = this.$element.on('scroll.bs.scroll-spy.data-api', process)
    this.options        = $.extend({}, ScrollSpy.DEFAULTS, options)
    this.selector       = (this.options.target
      || ((href = $(element).attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7
      || '') + ' .nav li > a'
    this.offsets        = $([])
    this.targets        = $([])
    this.activeTarget   = null

    this.refresh()
    this.process()
  }

  ScrollSpy.DEFAULTS = {
    offset: 10
  }

  ScrollSpy.prototype.refresh = function () {
    var offsetMethod = this.$element[0] == window ? 'offset' : 'position'

    this.offsets = $([])
    this.targets = $([])

    var self     = this
    var $targets = this.$body
      .find(this.selector)
      .map(function () {
        var $el   = $(this)
        var href  = $el.data('target') || $el.attr('href')
        var $href = /^#./.test(href) && $(href)

        return ($href
          && $href.length
          && $href.is(':visible')
          && [[ $href[offsetMethod]().top + (!$.isWindow(self.$scrollElement.get(0)) && self.$scrollElement.scrollTop()), href ]]) || null
      })
      .sort(function (a, b) { return a[0] - b[0] })
      .each(function () {
        self.offsets.push(this[0])
        self.targets.push(this[1])
      })
  }

  ScrollSpy.prototype.process = function () {
    var scrollTop    = this.$scrollElement.scrollTop() + this.options.offset
    var scrollHeight = this.$scrollElement[0].scrollHeight || this.$body[0].scrollHeight
    var maxScroll    = scrollHeight - this.$scrollElement.height()
    var offsets      = this.offsets
    var targets      = this.targets
    var activeTarget = this.activeTarget
    var i

    if (scrollTop >= maxScroll) {
      return activeTarget != (i = targets.last()[0]) && this.activate(i)
    }

    if (activeTarget && scrollTop <= offsets[0]) {
      return activeTarget != (i = targets[0]) && this.activate(i)
    }

    for (i = offsets.length; i--;) {
      activeTarget != targets[i]
        && scrollTop >= offsets[i]
        && (!offsets[i + 1] || scrollTop <= offsets[i + 1])
        && this.activate( targets[i] )
    }
  }

  ScrollSpy.prototype.activate = function (target) {
    this.activeTarget = target

    $(this.selector)
      .parentsUntil(this.options.target, '.active')
      .removeClass('active')

    var selector = this.selector +
        '[data-target="' + target + '"],' +
        this.selector + '[href="' + target + '"]'

    var active = $(selector)
      .parents('li')
      .addClass('active')

    if (active.parent('.dropdown-menu').length) {
      active = active
        .closest('li.dropdown')
        .addClass('active')
    }

    active.trigger('activate.bs.scrollspy')
  }


  // SCROLLSPY PLUGIN DEFINITION
  // ===========================

  var old = $.fn.scrollspy

  $.fn.scrollspy = function (option) {
    return this.each(function () {
      var $this   = $(this)
      var data    = $this.data('bs.scrollspy')
      var options = typeof option == 'object' && option

      if (!data) $this.data('bs.scrollspy', (data = new ScrollSpy(this, options)))
      if (typeof option == 'string') data[option]()
    })
  }

  $.fn.scrollspy.Constructor = ScrollSpy


  // SCROLLSPY NO CONFLICT
  // =====================

  $.fn.scrollspy.noConflict = function () {
    $.fn.scrollspy = old
    return this
  }


  // SCROLLSPY DATA-API
  // ==================

  $(window).on('load', function () {
    $('[data-spy="scroll"]').each(function () {
      var $spy = $(this)
      $spy.scrollspy($spy.data())
    })
  })

}(jQuery);
docs-assets/js/typeahead.bundle.min.js000066400000065756152434262010013770 0ustar00/*!
 * typeahead.js 0.10.1
 * https://github.com/twitter/typeahead.js
 * Copyright 2013 Twitter, Inc. and other contributors; Licensed MIT
 */

!function(a){var b={isMsie:function(){return/(msie|trident)/i.test(navigator.userAgent)?navigator.userAgent.match(/(msie |rv:)(\d+(.\d+)?)/i)[2]:!1},isBlankString:function(a){return!a||/^\s*$/.test(a)},escapeRegExChars:function(a){return a.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&")},isString:function(a){return"string"==typeof a},isNumber:function(a){return"number"==typeof a},isArray:a.isArray,isFunction:a.isFunction,isObject:a.isPlainObject,isUndefined:function(a){return"undefined"==typeof a},bind:a.proxy,each:function(b,c){function d(a,b){return c(b,a)}a.each(b,d)},map:a.map,filter:a.grep,every:function(b,c){var d=!0;return b?(a.each(b,function(a,e){return(d=c.call(null,e,a,b))?void 0:!1}),!!d):d},some:function(b,c){var d=!1;return b?(a.each(b,function(a,e){return(d=c.call(null,e,a,b))?!1:void 0}),!!d):d},mixin:a.extend,getUniqueId:function(){var a=0;return function(){return a++}}(),templatify:function(b){function c(){return String(b)}return a.isFunction(b)?b:c},defer:function(a){setTimeout(a,0)},debounce:function(a,b,c){var d,e;return function(){var f,g,h=this,i=arguments;return f=function(){d=null,c||(e=a.apply(h,i))},g=c&&!d,clearTimeout(d),d=setTimeout(f,b),g&&(e=a.apply(h,i)),e}},throttle:function(a,b){var c,d,e,f,g,h;return g=0,h=function(){g=new Date,e=null,f=a.apply(c,d)},function(){var i=new Date,j=b-(i-g);return c=this,d=arguments,0>=j?(clearTimeout(e),e=null,g=i,f=a.apply(c,d)):e||(e=setTimeout(h,j)),f}},noop:function(){}},c="0.10.1",d=function(){function a(a){this.maxSize=a||100,this.size=0,this.hash={},this.list=new c}function c(){this.head=this.tail=null}function d(a,b){this.key=a,this.val=b,this.prev=this.next=null}return b.mixin(a.prototype,{set:function(a,b){var c,e=this.list.tail;this.size>=this.maxSize&&(this.list.remove(e),delete this.hash[e.key]),(c=this.hash[a])?(c.val=b,this.list.moveToFront(c)):(c=new d(a,b),this.list.add(c),this.hash[a]=c,this.size++)},get:function(a){var b=this.hash[a];return b?(this.list.moveToFront(b),b.val):void 0}}),b.mixin(c.prototype,{add:function(a){this.head&&(a.next=this.head,this.head.prev=a),this.head=a,this.tail=this.tail||a},remove:function(a){a.prev?a.prev.next=a.next:this.head=a.next,a.next?a.next.prev=a.prev:this.tail=a.prev},moveToFront:function(a){this.remove(a),this.add(a)}}),a}(this),e=function(){function a(a){this.prefix=["__",a,"__"].join(""),this.ttlKey="__ttl__",this.keyMatcher=new RegExp("^"+this.prefix)}function c(){return(new Date).getTime()}function d(a){return JSON.stringify(b.isUndefined(a)?null:a)}function e(a){return JSON.parse(a)}var f,g;try{f=window.localStorage,f.setItem("~~~","!"),f.removeItem("~~~")}catch(h){f=null}return g=f&&window.JSON?{_prefix:function(a){return this.prefix+a},_ttlKey:function(a){return this._prefix(a)+this.ttlKey},get:function(a){return this.isExpired(a)&&this.remove(a),e(f.getItem(this._prefix(a)))},set:function(a,e,g){return b.isNumber(g)?f.setItem(this._ttlKey(a),d(c()+g)):f.removeItem(this._ttlKey(a)),f.setItem(this._prefix(a),d(e))},remove:function(a){return f.removeItem(this._ttlKey(a)),f.removeItem(this._prefix(a)),this},clear:function(){var a,b,c=[],d=f.length;for(a=0;d>a;a++)(b=f.key(a)).match(this.keyMatcher)&&c.push(b.replace(this.keyMatcher,""));for(a=c.length;a--;)this.remove(c[a]);return this},isExpired:function(a){var d=e(f.getItem(this._ttlKey(a)));return b.isNumber(d)&&c()>d?!0:!1}}:{get:b.noop,set:b.noop,remove:b.noop,clear:b.noop,isExpired:b.noop},b.mixin(a.prototype,g),a}(),f=function(){function c(b){b=b||{},this._send=b.transport?e(b.transport):a.ajax,this._get=b.rateLimiter?b.rateLimiter(this._get):this._get}function e(c){return function(d,e){function f(a){b.defer(function(){h.resolve(a)})}function g(a){b.defer(function(){h.reject(a)})}var h=a.Deferred();return c(d,e,f,g),h}}var f=0,g={},h=6,i=new d(10);return c.setMaxPendingRequests=function(a){h=a},c.resetCache=function(){i=new d(10)},b.mixin(c.prototype,{_get:function(a,b,c){function d(b){c&&c(b),i.set(a,b)}function e(){f--,delete g[a],k.onDeckRequestArgs&&(k._get.apply(k,k.onDeckRequestArgs),k.onDeckRequestArgs=null)}var j,k=this;(j=g[a])?j.done(d):h>f?(f++,g[a]=this._send(a,b).done(d).always(e)):this.onDeckRequestArgs=[].slice.call(arguments,0)},get:function(a,c,d){var e;return b.isFunction(c)&&(d=c,c={}),(e=i.get(a))?b.defer(function(){d&&d(e)}):this._get(a,c,d),!!e}}),c}(),g=function(){function c(b){b=b||{},b.datumTokenizer&&b.queryTokenizer||a.error("datumTokenizer and queryTokenizer are both required"),this.datumTokenizer=b.datumTokenizer,this.queryTokenizer=b.queryTokenizer,this.datums=[],this.trie=e()}function d(a){return a=b.filter(a,function(a){return!!a}),a=b.map(a,function(a){return a.toLowerCase()})}function e(){return{ids:[],children:{}}}function f(a){for(var b={},c=[],d=0;d<a.length;d++)b[a[d]]||(b[a[d]]=!0,c.push(a[d]));return c}function g(a,b){function c(a,b){return a-b}var d=0,e=0,f=[];for(a=a.sort(c),b=b.sort(c);d<a.length&&e<b.length;)a[d]<b[e]?d++:a[d]>b[e]?e++:(f.push(a[d]),d++,e++);return f}return b.mixin(c.prototype,{bootstrap:function(a){this.datums=a.datums,this.trie=a.trie},add:function(a){var c=this;a=b.isArray(a)?a:[a],b.each(a,function(a){var f,g;f=c.datums.push(a)-1,g=d(c.datumTokenizer(a)),b.each(g,function(a){var b,d,g;for(b=c.trie,d=a.split("");g=d.shift();)b=b.children[g]||(b.children[g]=e()),b.ids.push(f)})})},get:function(a){var c,e,h=this;return c=d(this.queryTokenizer(a)),b.each(c,function(a){var b,c,d,f;if(e&&0===e.length)return!1;for(b=h.trie,c=a.split("");b&&(d=c.shift());)b=b.children[d];return b&&0===c.length?(f=b.ids.slice(0),void(e=e?g(e,f):f)):(e=[],!1)}),e?b.map(f(e),function(a){return h.datums[a]}):[]},serialize:function(){return{datums:this.datums,trie:this.trie}}}),c}(),h=function(){function d(a){var c=a.local||null;return b.isFunction(c)&&(c=c.call(null)),c}function e(d){var e,f;return f={url:null,thumbprint:"",ttl:864e5,filter:null,ajax:{}},(e=d.prefetch||null)&&(e=b.isString(e)?{url:e}:e,e=b.mixin(f,e),e.thumbprint=c+e.thumbprint,e.ajax.type=e.ajax.type||"GET",e.ajax.dataType=e.ajax.dataType||"json",!e.url&&a.error("prefetch requires url to be set")),e}function f(c){function d(a){return function(c){return b.debounce(c,a)}}function e(a){return function(c){return b.throttle(c,a)}}var f,g;return g={url:null,wildcard:"%QUERY",replace:null,rateLimitBy:"debounce",rateLimitWait:300,send:null,filter:null,ajax:{}},(f=c.remote||null)&&(f=b.isString(f)?{url:f}:f,f=b.mixin(g,f),f.rateLimiter=/^throttle$/i.test(f.rateLimitBy)?e(f.rateLimitWait):d(f.rateLimitWait),f.ajax.type=f.ajax.type||"GET",f.ajax.dataType=f.ajax.dataType||"json",delete f.rateLimitBy,delete f.rateLimitWait,!f.url&&a.error("remote requires url to be set")),f}return{local:d,prefetch:e,remote:f}}(),i=(window.Bloodhound=function(){function c(b){b&&(b.local||b.prefetch||b.remote)||a.error("one of local, prefetch, or remote is required"),this.limit=b.limit||5,this.sorter=d(b.sorter),this.dupDetector=b.dupDetector||i,this.local=h.local(b),this.prefetch=h.prefetch(b),this.remote=h.remote(b),this.cacheKey=this.prefetch?this.prefetch.cacheKey||this.prefetch.url:null,this.index=new g({datumTokenizer:b.datumTokenizer,queryTokenizer:b.queryTokenizer}),this.storage=this.cacheKey?new e(this.cacheKey):null}function d(a){function c(b){return b.sort(a)}function d(a){return a}return b.isFunction(a)?c:d}function i(){return!1}var j;return j={data:"data",protocol:"protocol",thumbprint:"thumbprint"},c.tokenizers={whitespace:function(a){return a.split(/\s+/)},nonword:function(a){return a.split(/\W+/)}},b.mixin(c.prototype,{_loadPrefetch:function(b){function c(a){var c;c=b.filter?b.filter(a):a,f.add(c),f._saveToStorage(f.index.serialize(),b.thumbprint,b.ttl)}var d,e,f=this;return(d=this._readFromStorage(b.thumbprint))?(this.index.bootstrap(d),e=a.Deferred().resolve()):e=a.ajax(b.url,b.ajax).done(c),e},_getFromRemote:function(a,b){function c(a){var c=f.remote.filter?f.remote.filter(a):a;b(c)}var d,e,f=this;return a=a||"",e=encodeURIComponent(a),d=this.remote.replace?this.remote.replace(this.remote.url,a):this.remote.url.replace(this.remote.wildcard,e),this.transport.get(d,this.remote.ajax,c)},_saveToStorage:function(a,b,c){this.storage&&(this.storage.set(j.data,a,c),this.storage.set(j.protocol,location.protocol,c),this.storage.set(j.thumbprint,b,c))},_readFromStorage:function(a){var b,c={};return this.storage&&(c.data=this.storage.get(j.data),c.protocol=this.storage.get(j.protocol),c.thumbprint=this.storage.get(j.thumbprint)),b=c.thumbprint!==a||c.protocol!==location.protocol,c.data&&!b?c.data:null},initialize:function(){function b(){d.add(d.local)}var c,d=this;return c=this.prefetch?this._loadPrefetch(this.prefetch):a.Deferred().resolve(),this.local&&c.done(b),this.transport=this.remote?new f(this.remote):null,this.initialize=function(){return c.promise()},c.promise()},add:function(a){this.index.add(a)},get:function(a,c){function d(a){var d=e.slice(0);b.each(a,function(a){var c;return c=b.some(d,function(b){return f.dupDetector(a,b)}),!c&&d.push(a),d.length<f.limit}),c&&c(f.sorter(d))}var e,f=this,g=!1;e=this.index.get(a),e=this.sorter(e).slice(0,this.limit),e.length<this.limit&&this.transport&&(g=this._getFromRemote(a,d)),!g&&c&&c(e)},ttAdapter:function(){return b.bind(this.get,this)}}),c}(),{wrapper:'<span class="twitter-typeahead"></span>',dropdown:'<span class="tt-dropdown-menu"></span>',dataset:'<div class="tt-dataset-%CLASS%"></div>',suggestions:'<span class="tt-suggestions"></span>',suggestion:'<div class="tt-suggestion">%BODY%</div>'}),j={wrapper:{position:"relative",display:"inline-block"},hint:{position:"absolute",top:"0",left:"0",borderColor:"transparent",boxShadow:"none"},input:{position:"relative",verticalAlign:"top",backgroundColor:"transparent"},inputWithNoHint:{position:"relative",verticalAlign:"top"},dropdown:{position:"absolute",top:"100%",left:"0",zIndex:"100",display:"none"},suggestions:{display:"block"},suggestion:{whiteSpace:"nowrap",cursor:"pointer"},suggestionChild:{whiteSpace:"normal"},ltr:{left:"0",right:"auto"},rtl:{left:"auto",right:" 0"}};b.isMsie()&&b.mixin(j.input,{backgroundImage:"url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)"}),b.isMsie()&&b.isMsie()<=7&&b.mixin(j.input,{marginTop:"-1px"});var k=function(){function c(b){b&&b.el||a.error("EventBus initialized without el"),this.$el=a(b.el)}var d="typeahead:";return b.mixin(c.prototype,{trigger:function(a){var b=[].slice.call(arguments,1);this.$el.trigger(d+a,b)}}),c}(),l=function(){function a(a,b,c,d){var e;if(!c)return this;for(b=b.split(i),c=d?h(c,d):c,this._callbacks=this._callbacks||{};e=b.shift();)this._callbacks[e]=this._callbacks[e]||{sync:[],async:[]},this._callbacks[e][a].push(c);return this}function b(b,c,d){return a.call(this,"async",b,c,d)}function c(b,c,d){return a.call(this,"sync",b,c,d)}function d(a){var b;if(!this._callbacks)return this;for(a=a.split(i);b=a.shift();)delete this._callbacks[b];return this}function e(a){var b,c,d,e,g;if(!this._callbacks)return this;for(a=a.split(i),d=[].slice.call(arguments,1);(b=a.shift())&&(c=this._callbacks[b]);)e=f(c.sync,this,[b].concat(d)),g=f(c.async,this,[b].concat(d)),e()&&j(g);return this}function f(a,b,c){function d(){for(var d,e=0;!d&&e<a.length;e+=1)d=a[e].apply(b,c)===!1;return!d}return d}function g(){var a;return a=window.setImmediate?function(a){setImmediate(function(){a()})}:function(a){setTimeout(function(){a()},0)}}function h(a,b){return a.bind?a.bind(b):function(){a.apply(b,[].slice.call(arguments,0))}}var i=/\s+/,j=g();return{onSync:c,onAsync:b,off:d,trigger:e}}(),m=function(a){function c(a,c,d){for(var e,f=[],g=0;g<a.length;g++)f.push(b.escapeRegExChars(a[g]));return e=d?"\\b("+f.join("|")+")\\b":"("+f.join("|")+")",c?new RegExp(e):new RegExp(e,"i")}var d={node:null,pattern:null,tagName:"strong",className:null,wordsOnly:!1,caseSensitive:!1};return function(e){function f(b){var c,d;return(c=h.exec(b.data))&&(wrapperNode=a.createElement(e.tagName),e.className&&(wrapperNode.className=e.className),d=b.splitText(c.index),d.splitText(c[0].length),wrapperNode.appendChild(d.cloneNode(!0)),b.parentNode.replaceChild(wrapperNode,d)),!!c}function g(a,b){for(var c,d=3,e=0;e<a.childNodes.length;e++)c=a.childNodes[e],c.nodeType===d?e+=b(c)?1:0:g(c,b)}var h;e=b.mixin({},d,e),e.node&&e.pattern&&(e.pattern=b.isArray(e.pattern)?e.pattern:[e.pattern],h=c(e.pattern,e.caseSensitive,e.wordsOnly),g(e.node,f))}}(window.document),n=function(){function c(c){var e,f,h,i,j=this;c=c||{},c.input||a.error("input is missing"),e=b.bind(this._onBlur,this),f=b.bind(this._onFocus,this),h=b.bind(this._onKeydown,this),i=b.bind(this._onInput,this),this.$hint=a(c.hint),this.$input=a(c.input).on("blur.tt",e).on("focus.tt",f).on("keydown.tt",h),0===this.$hint.length&&(this.setHintValue=this.getHintValue=this.clearHint=b.noop),b.isMsie()?this.$input.on("keydown.tt keypress.tt cut.tt paste.tt",function(a){g[a.which||a.keyCode]||b.defer(b.bind(j._onInput,j,a))}):this.$input.on("input.tt",i),this.query=this.$input.val(),this.$overflowHelper=d(this.$input)}function d(b){return a('<pre aria-hidden="true"></pre>').css({position:"absolute",visibility:"hidden",whiteSpace:"nowrap",fontFamily:b.css("font-family"),fontSize:b.css("font-size"),fontStyle:b.css("font-style"),fontVariant:b.css("font-variant"),fontWeight:b.css("font-weight"),wordSpacing:b.css("word-spacing"),letterSpacing:b.css("letter-spacing"),textIndent:b.css("text-indent"),textRendering:b.css("text-rendering"),textTransform:b.css("text-transform")}).insertAfter(b)}function e(a,b){return c.normalizeQuery(a)===c.normalizeQuery(b)}function f(a){return a.altKey||a.ctrlKey||a.metaKey||a.shiftKey}var g;return g={9:"tab",27:"esc",37:"left",39:"right",13:"enter",38:"up",40:"down"},c.normalizeQuery=function(a){return(a||"").replace(/^\s*/g,"").replace(/\s{2,}/g," ")},b.mixin(c.prototype,l,{_onBlur:function(){this.resetInputValue(),this.trigger("blurred")},_onFocus:function(){this.trigger("focused")},_onKeydown:function(a){var b=g[a.which||a.keyCode];this._managePreventDefault(b,a),b&&this._shouldTrigger(b,a)&&this.trigger(b+"Keyed",a)},_onInput:function(){this._checkInputValue()},_managePreventDefault:function(a,b){var c,d,e;switch(a){case"tab":d=this.getHintValue(),e=this.getInputValue(),c=d&&d!==e&&!f(b);break;case"up":case"down":c=!f(b);break;default:c=!1}c&&b.preventDefault()},_shouldTrigger:function(a,b){var c;switch(a){case"tab":c=!f(b);break;default:c=!0}return c},_checkInputValue:function(){var a,b,c;a=this.getInputValue(),b=e(a,this.query),c=b?this.query.length!==a.length:!1,b?c&&this.trigger("whitespaceChanged",this.query):this.trigger("queryChanged",this.query=a)},focus:function(){this.$input.focus()},blur:function(){this.$input.blur()},getQuery:function(){return this.query},setQuery:function(a){this.query=a},getInputValue:function(){return this.$input.val()},setInputValue:function(a,b){this.$input.val(a),!b&&this._checkInputValue()},getHintValue:function(){return this.$hint.val()},setHintValue:function(a){this.$hint.val(a)},resetInputValue:function(){this.$input.val(this.query)},clearHint:function(){this.$hint.val("")},getLanguageDirection:function(){return(this.$input.css("direction")||"ltr").toLowerCase()},hasOverflow:function(){var a=this.$input.width()-2;return this.$overflowHelper.text(this.getInputValue()),this.$overflowHelper.width()>=a},isCursorAtEnd:function(){var a,c,d;return a=this.$input.val().length,c=this.$input[0].selectionStart,b.isNumber(c)?c===a:document.selection?(d=document.selection.createRange(),d.moveStart("character",-a),a===d.text.length):!0},destroy:function(){this.$hint.off(".tt"),this.$input.off(".tt"),this.$hint=this.$input=this.$overflowHelper=null}}),c}(),o=function(){function c(c){c=c||{},c.templates=c.templates||{},c.source||a.error("missing source"),c.name&&!f(c.name)&&a.error("invalid dataset name: "+c.name),this.query=null,this.highlight=!!c.highlight,this.name=c.name||b.getUniqueId(),this.source=c.source,this.displayFn=d(c.display||c.displayKey),this.templates=e(c.templates,this.displayFn),this.$el=a(i.dataset.replace("%CLASS%",this.name))}function d(a){function c(b){return b[a]}return a=a||"value",b.isFunction(a)?a:c}function e(a,c){function d(a){return"<p>"+c(a)+"</p>"}return{empty:a.empty&&b.templatify(a.empty),header:a.header&&b.templatify(a.header),footer:a.footer&&b.templatify(a.footer),suggestion:a.suggestion||d}}function f(a){return/^[_a-zA-Z0-9-]+$/.test(a)}var g="ttDataset",h="ttValue",k="ttDatum";return c.extractDatasetName=function(b){return a(b).data(g)},c.extractValue=function(b){return a(b).data(h)},c.extractDatum=function(b){return a(b).data(k)},b.mixin(c.prototype,l,{_render:function(c,d){function e(){return p.templates.empty({query:c,isEmpty:!0})}function f(){function e(b){var c,d,e;return d=p.templates.suggestion(b),e=i.suggestion.replace("%BODY%",d),c=a(e).data(g,p.name).data(h,p.displayFn(b)).data(k,b),c.children().each(function(){a(this).css(j.suggestionChild)}),c}var f,l;return f=a(i.suggestions).css(j.suggestions),l=b.map(d,e),f.append.apply(f,l),p.highlight&&m({node:f[0],pattern:c}),f}function l(){return p.templates.header({query:c,isEmpty:!o})}function n(){return p.templates.footer({query:c,isEmpty:!o})}if(this.$el){var o,p=this;this.$el.empty(),o=d&&d.length,!o&&this.templates.empty?this.$el.html(e()).prepend(p.templates.header?l():null).append(p.templates.footer?n():null):o&&this.$el.html(f()).prepend(p.templates.header?l():null).append(p.templates.footer?n():null),this.trigger("rendered")}},getRoot:function(){return this.$el},update:function(a){function b(b){a===c.query&&c._render(a,b)}var c=this;this.query=a,this.source(a,b)},clear:function(){this._render(this.query||"")},isEmpty:function(){return this.$el.is(":empty")},destroy:function(){this.$el=null}}),c}(),p=function(){function c(c){var e,f,g,h=this;c=c||{},c.menu||a.error("menu is required"),this.isOpen=!1,this.isEmpty=!0,this.datasets=b.map(c.datasets,d),e=b.bind(this._onSuggestionClick,this),f=b.bind(this._onSuggestionMouseEnter,this),g=b.bind(this._onSuggestionMouseLeave,this),this.$menu=a(c.menu).on("click.tt",".tt-suggestion",e).on("mouseenter.tt",".tt-suggestion",f).on("mouseleave.tt",".tt-suggestion",g),b.each(this.datasets,function(a){h.$menu.append(a.getRoot()),a.onSync("rendered",h._onRendered,h)})}function d(a){return new o(a)}return b.mixin(c.prototype,l,{_onSuggestionClick:function(b){this.trigger("suggestionClicked",a(b.currentTarget))},_onSuggestionMouseEnter:function(b){this._removeCursor(),this._setCursor(a(b.currentTarget),!0)},_onSuggestionMouseLeave:function(){this._removeCursor()},_onRendered:function(){function a(a){return a.isEmpty()}this.isEmpty=b.every(this.datasets,a),this.isEmpty?this._hide():this.isOpen&&this._show(),this.trigger("datasetRendered")},_hide:function(){this.$menu.hide()},_show:function(){this.$menu.css("display","block")},_getSuggestions:function(){return this.$menu.find(".tt-suggestion")},_getCursor:function(){return this.$menu.find(".tt-cursor").first()},_setCursor:function(a,b){a.first().addClass("tt-cursor"),!b&&this.trigger("cursorMoved")},_removeCursor:function(){this._getCursor().removeClass("tt-cursor")},_moveCursor:function(a){var b,c,d,e;if(this.isOpen){if(c=this._getCursor(),b=this._getSuggestions(),this._removeCursor(),d=b.index(c)+a,d=(d+1)%(b.length+1)-1,-1===d)return void this.trigger("cursorRemoved");-1>d&&(d=b.length-1),this._setCursor(e=b.eq(d)),this._ensureVisible(e)}},_ensureVisible:function(a){var b,c,d,e;b=a.position().top,c=b+a.outerHeight(!0),d=this.$menu.scrollTop(),e=this.$menu.height()+parseInt(this.$menu.css("paddingTop"),10)+parseInt(this.$menu.css("paddingBottom"),10),0>b?this.$menu.scrollTop(d+b):c>e&&this.$menu.scrollTop(d+(c-e))},close:function(){this.isOpen&&(this.isOpen=!1,this._removeCursor(),this._hide(),this.trigger("closed"))},open:function(){this.isOpen||(this.isOpen=!0,!this.isEmpty&&this._show(),this.trigger("opened"))},setLanguageDirection:function(a){this.$menu.css("ltr"===a?j.ltr:j.rtl)},moveCursorUp:function(){this._moveCursor(-1)},moveCursorDown:function(){this._moveCursor(1)},getDatumForSuggestion:function(a){var b=null;return a.length&&(b={raw:o.extractDatum(a),value:o.extractValue(a),datasetName:o.extractDatasetName(a)}),b},getDatumForCursor:function(){return this.getDatumForSuggestion(this._getCursor().first())},getDatumForTopSuggestion:function(){return this.getDatumForSuggestion(this._getSuggestions().first())},update:function(a){function c(b){b.update(a)}b.each(this.datasets,c)},empty:function(){function a(a){a.clear()}b.each(this.datasets,a),this.isEmpty=!0},isVisible:function(){return this.isOpen&&!this.isEmpty},destroy:function(){function a(a){a.destroy()}this.$menu.off(".tt"),this.$menu=null,b.each(this.datasets,a)}}),c}(),q=function(){function c(c){var e,f,g;c=c||{},c.input||a.error("missing input"),this.autoselect=!!c.autoselect,this.minLength=b.isNumber(c.minLength)?c.minLength:1,this.$node=d(c.input,c.withHint),e=this.$node.find(".tt-dropdown-menu"),f=this.$node.find(".tt-input"),g=this.$node.find(".tt-hint"),this.eventBus=c.eventBus||new k({el:f}),this.dropdown=new p({menu:e,datasets:c.datasets}).onSync("suggestionClicked",this._onSuggestionClicked,this).onSync("cursorMoved",this._onCursorMoved,this).onSync("cursorRemoved",this._onCursorRemoved,this).onSync("opened",this._onOpened,this).onSync("closed",this._onClosed,this).onAsync("datasetRendered",this._onDatasetRendered,this),this.input=new n({input:f,hint:g}).onSync("focused",this._onFocused,this).onSync("blurred",this._onBlurred,this).onSync("enterKeyed",this._onEnterKeyed,this).onSync("tabKeyed",this._onTabKeyed,this).onSync("escKeyed",this._onEscKeyed,this).onSync("upKeyed",this._onUpKeyed,this).onSync("downKeyed",this._onDownKeyed,this).onSync("leftKeyed",this._onLeftKeyed,this).onSync("rightKeyed",this._onRightKeyed,this).onSync("queryChanged",this._onQueryChanged,this).onSync("whitespaceChanged",this._onWhitespaceChanged,this),e.on("mousedown.tt",function(a){b.isMsie()&&b.isMsie()<9&&(f[0].onbeforedeactivate=function(){window.event.returnValue=!1,f[0].onbeforedeactivate=null}),a.preventDefault()})}function d(b,c){var d,f,h,k;d=a(b),f=a(i.wrapper).css(j.wrapper),h=a(i.dropdown).css(j.dropdown),k=d.clone().css(j.hint).css(e(d)),k.val("").removeData().addClass("tt-hint").removeAttr("id name placeholder").prop("disabled",!0).attr({autocomplete:"off",spellcheck:"false"}),d.data(g,{dir:d.attr("dir"),autocomplete:d.attr("autocomplete"),spellcheck:d.attr("spellcheck"),style:d.attr("style")}),d.addClass("tt-input").attr({autocomplete:"off",spellcheck:!1}).css(c?j.input:j.inputWithNoHint);try{!d.attr("dir")&&d.attr("dir","auto")}catch(l){}return d.wrap(f).parent().prepend(c?k:null).append(h)}function e(a){return{backgroundAttachment:a.css("background-attachment"),backgroundClip:a.css("background-clip"),backgroundColor:a.css("background-color"),backgroundImage:a.css("background-image"),backgroundOrigin:a.css("background-origin"),backgroundPosition:a.css("background-position"),backgroundRepeat:a.css("background-repeat"),backgroundSize:a.css("background-size")}}function f(a){var c=a.find(".tt-input");b.each(c.data(g),function(a,d){b.isUndefined(a)?c.removeAttr(d):c.attr(d,a)}),c.detach().removeData(g).removeClass("tt-input").insertAfter(a),a.remove()}var g="ttAttrs";return b.mixin(c.prototype,{_onSuggestionClicked:function(a,b){var c;(c=this.dropdown.getDatumForSuggestion(b))&&this._select(c)},_onCursorMoved:function(){var a=this.dropdown.getDatumForCursor();this.input.clearHint(),this.input.setInputValue(a.value,!0),this.eventBus.trigger("cursorchanged",a.raw,a.datasetName)},_onCursorRemoved:function(){this.input.resetInputValue(),this._updateHint()},_onDatasetRendered:function(){this._updateHint()},_onOpened:function(){this._updateHint(),this.eventBus.trigger("opened")},_onClosed:function(){this.input.clearHint(),this.eventBus.trigger("closed")},_onFocused:function(){this.dropdown.empty(),this.dropdown.open()},_onBlurred:function(){this.dropdown.close()},_onEnterKeyed:function(a,b){var c,d;c=this.dropdown.getDatumForCursor(),d=this.dropdown.getDatumForTopSuggestion(),c?(this._select(c),b.preventDefault()):this.autoselect&&d&&(this._select(d),b.preventDefault())},_onTabKeyed:function(a,b){var c;(c=this.dropdown.getDatumForCursor())?(this._select(c),b.preventDefault()):this._autocomplete()},_onEscKeyed:function(){this.dropdown.close(),this.input.resetInputValue()},_onUpKeyed:function(){var a=this.input.getQuery();!this.dropdown.isOpen&&a.length>=this.minLength&&this.dropdown.update(a),this.dropdown.open(),this.dropdown.moveCursorUp()},_onDownKeyed:function(){var a=this.input.getQuery();!this.dropdown.isOpen&&a.length>=this.minLength&&this.dropdown.update(a),this.dropdown.open(),this.dropdown.moveCursorDown()},_onLeftKeyed:function(){"rtl"===this.dir&&this._autocomplete()},_onRightKeyed:function(){"ltr"===this.dir&&this._autocomplete()},_onQueryChanged:function(a,b){this.input.clearHint(),this.dropdown.empty(),b.length>=this.minLength&&this.dropdown.update(b),this.dropdown.open(),this._setLanguageDirection()},_onWhitespaceChanged:function(){this._updateHint(),this.dropdown.open()},_setLanguageDirection:function(){var a;this.dir!==(a=this.input.getLanguageDirection())&&(this.dir=a,this.$node.css("direction",a),this.dropdown.setLanguageDirection(a))},_updateHint:function(){var a,c,d,e,f,g;a=this.dropdown.getDatumForTopSuggestion(),a&&this.dropdown.isVisible()&&!this.input.hasOverflow()&&(c=this.input.getInputValue(),d=n.normalizeQuery(c),e=b.escapeRegExChars(d),f=new RegExp("^(?:"+e+")(.*$)","i"),g=f.exec(a.value),this.input.setHintValue(c+(g?g[1]:"")))},_autocomplete:function(){var a,b,c;a=this.input.getHintValue(),b=this.input.getQuery(),a&&b!==a&&this.input.isCursorAtEnd()&&(c=this.dropdown.getDatumForTopSuggestion(),c&&this.input.setInputValue(c.value),this.eventBus.trigger("autocompleted",c.raw,c.datasetName))},_select:function(a){this.input.clearHint(),this.input.setQuery(a.value),this.input.setInputValue(a.value,!0),this._setLanguageDirection(),this.eventBus.trigger("selected",a.raw,a.datasetName),this.dropdown.close(),b.defer(b.bind(this.dropdown.empty,this.dropdown))},open:function(){this.dropdown.open()},close:function(){this.dropdown.close()},getQuery:function(){return this.input.getQuery()},setQuery:function(a){this.input.setInputValue(a)},destroy:function(){this.input.destroy(),this.dropdown.destroy(),f(this.$node),this.$node=null}}),c}();!function(){var c,d,e;c=a.fn.typeahead,d="ttTypeahead",e={initialize:function(c,e){function f(){var f,g,h=a(this);b.each(e,function(a){a.highlight=!!c.highlight}),g=new q({input:h,eventBus:f=new k({el:h}),withHint:b.isUndefined(c.hint)?!0:!!c.hint,minLength:c.minLength,autoselect:c.autoselect,datasets:e}),h.data(d,g)}return e=b.isArray(e)?e:[].slice.call(arguments,1),c=c||{},this.each(f)},open:function(){function b(){var b,c=a(this);(b=c.data(d))&&b.open()}return this.each(b)},close:function(){function b(){var b,c=a(this);(b=c.data(d))&&b.close()}return this.each(b)},val:function(b){function c(){var c,e=a(this);(c=e.data(d))&&c.setQuery(b)}function e(a){var b,c;return(b=a.data(d))&&(c=b.getQuery()),c}return arguments.length?this.each(c):e(this.first())},destroy:function(){function b(){var b,c=a(this);(b=c.data(d))&&(b.destroy(),c.removeData(d))}return this.each(b)}},a.fn.typeahead=function(a){return e[a]?e[a].apply(this,[].slice.call(arguments,1)):e.initialize.apply(this,arguments)},a.fn.typeahead.noConflict=function(){return a.fn.typeahead=c,this}}()}(window.jQuery);docs-assets/js/docs.min.js000066400000003674152434262010011473 0ustar00/*!
 * bootstrap-tokenfield 0.12.1
 * https://github.com/sliptree/bootstrap-tokenfield
 * Copyright 2013-2014 Sliptree and other contributors; Licensed MIT
 */

jQuery(function(){$("#download-master").click(function(){_trackEvent("Downloads","master")})}),jQuery(document).ready(function(a){a("body").scrollspy({target:".bs-sidebar",offset:0}),a(window).on("load",function(){a("body").scrollspy("refresh")}),setTimeout(function(){var b=a(".bs-sidebar");b.affix({offset:{top:function(){var a=b.offset().top,c=parseInt(b.children(0).css("margin-top"),10);return this.top=a-c},bottom:function(){return this.bottom=a(".bs-footer").outerHeight(!0)}}})},100),a(".token-example-field").tokenfield(),a("#tokenfield-1").tokenfield({autocomplete:{source:["red","blue","green","yellow","violet","brown","purple","black","white"],delay:100},showAutocompleteOnFocus:!0,delimiter:[","," ","-","_"]});var b=new Bloodhound({local:[{value:"red"},{value:"blue"},{value:"green"},{value:"yellow"},{value:"violet"},{value:"brown"},{value:"purple"},{value:"black"},{value:"white"}],datumTokenizer:function(a){return Bloodhound.tokenizers.whitespace(a.value)},queryTokenizer:Bloodhound.tokenizers.whitespace});b.initialize(),a("#tokenfield-typeahead").tokenfield({typeahead:[null,{source:b.ttAdapter()}]}),a("#tokenfield-2").on("tokenfield:createtoken",function(a){var b=a.attrs.value.split("|");a.attrs.value=b[1]||b[0],a.attrs.label=b[1]?b[0]+" ("+b[1]+")":b[0]}).on("tokenfield:createdtoken",function(b){var c=/\S+@\S+\.\S+/,d=c.test(b.attrs.value);d||a(b.relatedTarget).addClass("invalid")}).on("tokenfield:edittoken",function(a){if(a.attrs.label!==a.attrs.value){var b=a.attrs.label.split(" (");a.attrs.value=b[0]+"|"+a.attrs.value}}).on("tokenfield:removedtoken",function(b){if(b.attrs.length>1){var c=a.map(b.attrs,function(a){return a.value});alert(b.attrs.length+" tokens removed! Token values were: "+c.join(", "))}else alert("Token removed! Token value was: "+b.attrs.value)}).tokenfield()});docs-assets/js/docs.js000066400000005171152434262010010703 0ustar00jQuery(function(){
  // Track downloads
  $('#download-master').click(function(){
    _trackEvent('Downloads', 'master');
  });
});

jQuery(document).ready(function($) {

  /* Docs scrollspy */
  $('body').scrollspy({
    target: '.bs-sidebar',
    offset: 0
  })

  $(window).on('load', function () {
    $('body').scrollspy('refresh')
  })

  // back to top
  setTimeout(function () {
    var $sideBar = $('.bs-sidebar')

    $sideBar.affix({
      offset: {
        top: function () {
          var offsetTop      = $sideBar.offset().top
          var sideBarMargin  = parseInt($sideBar.children(0).css('margin-top'), 10)

          return (this.top = offsetTop - sideBarMargin)
        }
      , bottom: function () {
          return (this.bottom = $('.bs-footer').outerHeight(true))
        }
      }
    })
  }, 100)

  /* Run examples */
  $('.token-example-field').tokenfield();

  $('#tokenfield-1').tokenfield({
    autocomplete: {
      source: ['red','blue','green','yellow','violet','brown','purple','black','white'],
      delay: 100
    },
    showAutocompleteOnFocus: true,
    delimiter: [',',' ', '-', '_']
  });

  var engine = new Bloodhound({
    local: [{value: 'red'}, {value: 'blue'}, {value: 'green'} , {value: 'yellow'}, {value: 'violet'}, {value: 'brown'}, {value: 'purple'}, {value: 'black'}, {value: 'white'}],
    datumTokenizer: function(d) {
      return Bloodhound.tokenizers.whitespace(d.value);
    },
    queryTokenizer: Bloodhound.tokenizers.whitespace
  });
  engine.initialize();

  $('#tokenfield-typeahead').tokenfield({
    typeahead: [null, { source: engine.ttAdapter() }]
  });

  $('#tokenfield-2')
    .on('tokenfield:createtoken', function (e) {
      var data = e.attrs.value.split('|')
      e.attrs.value = data[1] || data[0]
      e.attrs.label = data[1] ? data[0] + ' (' + data[1] + ')' : data[0]
    })
    .on('tokenfield:createdtoken', function (e) {
      // Über-simplistic e-mail validation
      var re = /\S+@\S+\.\S+/
      var valid = re.test(e.attrs.value)
      if (!valid) {
        $(e.relatedTarget).addClass('invalid')
      }
    })
    .on('tokenfield:edittoken', function (e) {
      if (e.attrs.label !== e.attrs.value) {
        var label = e.attrs.label.split(' (')
        e.attrs.value = label[0] + '|' + e.attrs.value
      }
    })
    .on('tokenfield:removedtoken', function (e) {
      if (e.attrs.length > 1) {
        var values = $.map(e.attrs, function (attrs) { return attrs.value });
        alert(e.attrs.length + ' tokens removed! Token values were: ' + values.join(', '))
      } else {
        alert('Token removed! Token value was: ' + e.attrs.value)
      }
    })
    .tokenfield()

});.travis.yml000066400000000125152434262010006654 0ustar00language: node_js
node_js: ["0.10"]

notifications:
  email: ["illimar@sliptree.com"]less/bootstrap-tokenfield.less000066400000011616152434262010012547 0ustar00/*!
 * bootstrap-tokenfield
 * https://github.com/sliptree/bootstrap-tokenfield
 * Copyright 2013-2014 Sliptree and other contributors; Licensed MIT
 */

@import "../bower_components/bootstrap/less/mixins.less";
@import "../bower_components/bootstrap/less/variables.less";

// Variables

@token-background: #ededed;
@token-border: #d9d9d9;
@token-hover-border: #b9b9b9;
@token-active-border: rgba(82, 168, 236, 0.8);
@token-active-border-fallback: rgb(82, 168, 236); // IE8
@token-active-invalid-border: @token-background;


// Mixins

.tokenfield-focus(@color: @input-border-focus) {
  @color-rgba: rgba(red(@color), green(@color), blue(@color), .6);
  border-color: @color;
  outline: 0;
  .box-shadow(~"inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 8px @{color-rgba}");
}

.tokenfield-validation(@border-color) {
  border-color: darken(@border-color, 10%);
  @shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px lighten(@border-color, 20%);
  .box-shadow(@shadow);
}

.border-radius(@border-radius) {
  -webkit-border-radius: @border-radius;
     -moz-border-radius: @border-radius;
          border-radius: @border-radius;
}

// Blink animation for duplicate tokens

@-webkit-keyframes blink {
  0% {
    border-color: #ededed;
  }
  100% {
    border-color: #b94a48;
  }
}
@-moz-keyframes blink {
  0% {
    border-color: #ededed;
  }
  100% {
    border-color: #b94a48;
  }
}
@keyframes blink {
  0% {
    border-color: #ededed;
  }
  100% {
    border-color: #b94a48;
  }
}

// Tokenfield

.tokenfield {
  height: auto;
  min-height: @input-height-base;
  padding-bottom: 0px;
  &.focus {
    .tokenfield-focus();
  }

  // Tokens
  .token {
    .box-sizing(border-box);
    .border-radius(3px);
    display: inline-block;
    border: 1px solid @token-border;
    background-color: @token-background;
    white-space: nowrap;
    margin: -1px 5px 5px 0;
    height: 22px;
    vertical-align: top;
    cursor: default;
    &:hover {
      border-color: @token-hover-border;
    }
    &.active {
      border-color: rgb(82, 168, 236);
      border-color: rgba(82, 168, 236, 0.8);
    }
    &.duplicate {
      border-color: @state-danger-border;
      .animation-name(blink);
      .animation-duration(0.1s);
      .animation-direction(normal);
      .animation-timing-function(ease);
      .animation-iteration-count(infinite);
    }
    &.invalid {
      background: none;
      border: 1px solid transparent;
      .border-radius(0);
      border-bottom: 1px dotted @brand-danger;
      &.active {
        background: @token-background;
        border: 1px solid @token-active-invalid-border;
        .border-radius(3px);
      }
    }   
    .token-label {
      display: inline-block;
      overflow: hidden;
      text-overflow: ellipsis;
      padding-left: 4px;
      vertical-align: top;
    }
    .close {
      font-family: Arial;
      display: inline-block;
      line-height: 100%;
      font-size: 1.1em;
      line-height: 1.49em;
      margin-left: 5px;
      float: none;
      height: 100%;
      vertical-align: top;
      padding-right: 4px;
    }    
  }

  // Inputs
  .token-input {
    background: none;
    width: 60px;
    min-width: 60px;
    border: 0;
    height: 20px;
    padding: 0;
    margin-bottom: 6px;
    .box-shadow(none);
  }
  .token-input:focus {
    border-color: transparent;
    outline: 0;
    /* IE6-9 */
    .box-shadow(none);
  }  

  // Disabled state
  &.disabled {
    cursor: not-allowed;
    background-color: @gray-lighter;
    .token-input {
      cursor: not-allowed;
    }
    .token:hover {
      cursor: not-allowed;
      border-color: @token-border;
      .close {
        cursor: not-allowed;
        .opacity(0.2);
      }
    }
  }  
}

// Validation states

.has-warning .tokenfield.focus {
  .tokenfield-validation(@state-warning-text);
}
.has-error .tokenfield.focus {
  .tokenfield-validation(@state-danger-text);
}
.has-success .tokenfield.focus {
  .tokenfield-validation(@state-success-text);
}

// Various sizes

.tokenfield.input-sm,
.input-group-sm .tokenfield {
  min-height: 30px;
  padding-bottom: 0px;
}
.input-group-sm .token,
.tokenfield.input-sm .token {
  height: 20px;
  margin-bottom: 4px;
}
.input-group-sm .token-input,
.tokenfield.input-sm .token-input {
  height: 18px;
  margin-bottom: 5px;
}

.tokenfield.input-lg,
.input-group-lg .tokenfield {
  height: auto;
  min-height: 45px;
  padding-bottom: 4px;
}
.input-group-lg .token,
.tokenfield.input-lg .token {
  height: 25px;
}
.input-group-lg .token-label,
.tokenfield.input-lg .token-label {
  line-height: 23px;
}
.input-group-lg .token .close,
.tokenfield.input-lg .token .close {
  line-height: 1.3em;
}
.input-group-lg .token-input,
.tokenfield.input-lg .token-input {
  height: 23px;
  line-height: 23px;
  margin-bottom: 6px;
  vertical-align: top;
}

// RTL

.tokenfield.rtl {
  direction: rtl;
  text-align: right;
}
.tokenfield.rtl .token {
  margin: -1px 0 5px 5px;
}
.tokenfield.rtl .token .token-label {
  padding-left: 0px;
  padding-right: 4px;
}
less/tokenfield-typeahead.less000066400000007430152434262010012475 0ustar00/*!
 * bootstrap-tokenfield
 * https://github.com/sliptree/bootstrap-tokenfield
 * Copyright 2013-2014 Sliptree and other contributors; Licensed MIT
 */

@import "../bower_components/bootstrap/less/mixins.less";
@import "../bower_components/bootstrap/less/variables.less";

/* General Typeahead styling, from http://jsfiddle.net/ragulka/Dy9au/1/ */
.twitter-typeahead {
  width: 100%;
  position: relative;
  vertical-align: top;
}
.twitter-typeahead .tt-input,
.twitter-typeahead .tt-hint {
  margin: 0;
  width: 100%;
  vertical-align: middle;
  background-color: @input-bg;
}
.twitter-typeahead .tt-hint {
  color: @input-color-placeholder;
  z-index: 1;
  border: 1px solid transparent;
}
.twitter-typeahead .tt-input {
  color: @input-color;
  z-index: 2;
}
.twitter-typeahead .tt-input,
.twitter-typeahead .tt-hint {
  height: @input-height-base;
  padding: @padding-base-vertical @padding-base-horizontal;
  font-size: 14px;
  line-height: 1.428571429;
}
.twitter-typeahead .input-sm.tt-input,
.twitter-typeahead .hint-sm.tt-hint {
  border-radius: 3px;
}
.twitter-typeahead .input-lg.tt-input,
.twitter-typeahead .hint-lg.tt-hint {
  border-radius: 6px;
}
.input-group .twitter-typeahead:first-child .tt-input,
.input-group .twitter-typeahead:first-child .tt-hint {
  border-radius: 4px 0 0 4px !important;
}
.input-group .twitter-typeahead:last-child .tt-input,
.input-group .twitter-typeahead:last-child .tt-hint {
  border-radius: 0 4px 4px 0 !important;
}
.input-group.input-group-sm .twitter-typeahead:first-child .tt-input,
.input-group.input-group-sm .twitter-typeahead:first-child .tt-hint {
  border-radius: 3px 0 0 3px !important;
}
.input-group.input-group-sm .twitter-typeahead:last-child .tt-input,
.input-group.input-group-sm .twitter-typeahead:last-child .tt-hint {
  border-radius: 0 3px 3px 0 !important;
}
.input-sm.tt-input,
.hint-sm.tt-hint,
.input-group.input-group-sm .tt-input,
.input-group.input-group-sm .tt-hint {
  height: 30px;
  padding: 5px 10px;
  font-size: 12px;
  line-height: 1.5;
}
.input-group.input-group-lg .twitter-typeahead:first-child .tt-input,
.input-group.input-group-lg .twitter-typeahead:first-child .tt-hint {
  border-radius: 6px 0 0 6px !important;
}
.input-group.input-group-lg .twitter-typeahead:last-child .tt-input,
.input-group.input-group-lg .twitter-typeahead:last-child .tt-hint {
  border-radius: 0 6px 6px 0 !important;
}
.input-lg.tt-input,
.hint-lg.tt-hint,
.input-group.input-group-lg .tt-input,
.input-group.input-group-lg .tt-hint {
  height: 45px;
  padding: 10px 16px;
  font-size: 18px;
  line-height: 1.33;
}
.tt-dropdown-menu {
  width: 100%;
  min-width: 160px;
  margin-top: 2px;
  padding: 5px 0;
  background-color: @dropdown-bg;
  border: 1px solid #ccc;
  border: 1px solid @dropdown-border;
  *border-right-width: 2px;
  *border-bottom-width: 2px;
  border-radius: 6px;
  .box-shadow(0 5px 10px rgba(0, 0, 0, .2));
  -webkit-background-clip: padding-box;
  -moz-background-clip: padding;
  background-clip: padding-box;
}
.tt-suggestion {
  display: block;
  padding: 3px 20px;
}
.tt-suggestion.tt-cursor {
  color: @dropdown-link-hover-color;
  #gradient > .vertical(@dropdown-link-hover-bg, darken(@dropdown-link-hover-bg, 5%));
}
.tt-suggestion.tt-cursor a {
  color: @dropdown-bg;
}
.tt-suggestion p {
  margin: 0;
}

/* Tokenfield-specific Typeahead styling */
.tokenfield .twitter-typeahead {
  width: auto;
}
.tokenfield .twitter-typeahead .tt-hint {
  padding: 0;
  height: 20px;
}
.tokenfield.input-sm .twitter-typeahead .tt-input,
.tokenfield.input-sm .twitter-typeahead .tt-hint {
  height: 18px;
  font-size: 12px;
  line-height: 1.5;
}
.tokenfield.input-lg .twitter-typeahead .tt-input,
.tokenfield.input-lg .twitter-typeahead .tt-hint {
  height: 23px;
  font-size: 18px;
  line-height: 1.33;
}
.tokenfield .twitter-typeahead .tt-suggestions {
  font-size: 14px;
}
test/helpers/jsdom-patch.js000066400000005033152434262010011736 0ustar00/**
 * Patch from zombie.js for jsdom https://github.com/assaf/zombie/blob/master/src/zombie/dom_focus.coffee
 *
 * Adds focus() and blur() methods and events to dom elements
 */

var FOCUS_ELEMENTS, HTML, elementType, setAttribute, setFocus, _i, _j, _len, _len1, _ref, _ref1;

HTML = require("jsdom").dom.level3.html;

FOCUS_ELEMENTS = ["INPUT", "SELECT", "TEXTAREA", "BUTTON", "ANCHOR"];

HTML.HTMLDocument.prototype.__defineGetter__("activeElement", function() {
  return this._inFocus || this.body;
});

setFocus = function(document, element) {
  var inFocus, onblur, onfocus;
  inFocus = document._inFocus;
  if (element !== inFocus) {
    if (inFocus) {
      onblur = document.createEvent("HTMLEvents");
      onblur.initEvent("blur", false, false);
      inFocus.dispatchEvent(onblur);
    }
    if (element) {
      onfocus = document.createEvent("HTMLEvents");
      onfocus.initEvent("focus", false, false);
      element.dispatchEvent(onfocus);
      document._inFocus = element;
    }
  }
};

HTML.HTMLElement.prototype.focus = function() {};

HTML.HTMLElement.prototype.blur = function() {};

_ref = [HTML.HTMLInputElement, HTML.HTMLSelectElement, HTML.HTMLTextAreaElement, HTML.HTMLButtonElement, HTML.HTMLAnchorElement];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
  elementType = _ref[_i];
  elementType.prototype.focus = function() {
    return setFocus(this.ownerDocument, this);
  };
  elementType.prototype.blur = function() {
    return setFocus(this.ownerDocument, null);
  };
  setAttribute = elementType.prototype.setAttribute;
  elementType.prototype.setAttribute = function(name, value) {
    var document;
    setAttribute.call(this, name, value);
    if (name === "autofocus") {
      document = this.ownerDocument;
      if (~FOCUS_ELEMENTS.indexOf(this.tagName) && !document._inFocus) {
        return this.focus();
      }
    }
  };
}

_ref1 = [HTML.HTMLInputElement, HTML.HTMLTextAreaElement, HTML.HTMLSelectElement];
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
  elementType = _ref1[_j];
  elementType.prototype._eventDefaults.focus = function(event) {
    var element;
    element = event.target;
    return element._focusValue = element.value || '';
  };
  elementType.prototype._eventDefaults.blur = function(event) {
    var change, element, focusValue;
    element = event.target;
    focusValue = element._focusValue;
    if (focusValue !== element.value) {
      change = element.ownerDocument.createEvent("HTMLEvents");
      change.initEvent("change", false, false);
      return element.dispatchEvent(change);
    }
  };
}
test/test.tokenfield.2.integration.js000066400000112025152434262010013647 0ustar00describe('2. Integration tests:', function() {

  before(function() {
    require('../node_modules/jquery-simulate-ext/libs/bililiteRange');
    require('../node_modules/jquery-simulate-ext/libs/jquery.simulate');
    
    // https://github.com/j-ulrich/jquery-simulate-ext/issues/9
    // For us, it just saves a littlebit time
    global.$.simulate.ext_disableQuirkDetection = true;
    
    require('../node_modules/jquery-simulate-ext/src/jquery.simulate.ext');
    require('../node_modules/jquery-simulate-ext/src/jquery.simulate.key-combo');
    require('../node_modules/jquery-simulate-ext/src/jquery.simulate.key-sequence');
  });

  describe('Using an alternative delimiter', function() {
    before(function() {
      TFT.template = '<input type="text" class="tokenize" value="red;green;blue;yellow" />'
      TFT.options = {
        delimiter: ';'
      }
    });

    after(function() {
      delete TFT.template;
      delete TFT.options;
    });

    it('must create tokens by splitting the original value with delimiters', function() {
      this.$field.data('bs.tokenfield').$wrapper.find('.token').length.must.equal(4);
    });

    it('must create a token when the delimiting key is pressed and use the first delimiter for setting original input value', function() {
      this.$input.focus().simulate("key-sequence", { sequence: "purple;olive;" })
      this.$field.data('bs.tokenfield').$wrapper.find('.token').length.must.equal(6);
      this.$field.val().must.equal('red; green; blue; yellow; purple; olive');
    });    
  })

  describe('with multiple alternative delimiters', function() {
    describe("Delimiters: [' ', '.']", function() {
      before(function() {
        TFT.template = '<input type="text" class="tokenize" value="red green blue.yellow" />'
        TFT.options = {
          delimiter: [' ', '.']
        }
      });

      after(function() {
        delete TFT.template;
        delete TFT.options;
      });

      it('must create tokens by splitting the original value with delimiters', function() {
        this.$field.data('bs.tokenfield').$wrapper.find('.token').length.must.equal(4);
      });

      it('must create a token when the delimiting key is pressed and use the first delimiter for setting original input value', function() {
        this.$input.focus().simulate("key-sequence", { sequence: "purple olive." });
        this.$field.data('bs.tokenfield').$wrapper.find('.token').length.must.equal(6);
        this.$field.val().must.equal('red green blue yellow purple olive');
      });
    });

    describe("Delimiters: [',', ' ', '-', '_'] (Regression test for #79)", function() {
      before(function() {
        TFT.template = '<input type="text" class="tokenize" value="red,green blue-yellow_123" />'
        TFT.options = {
          delimiter: [',', ' ', '-', '_']
        }
      });

      after(function() {
        delete TFT.template;
        delete TFT.options;
      });

      it('must create tokens by splitting the original value with delimiters', function() {
        this.$field.data('bs.tokenfield').$wrapper.find('.token').length.must.equal(5);
      });
    });

    describe("Using regexp special characters as delimiters", function() {
      before(function() {
        TFT.template = '<input type="text" class="tokenize" value="red\\green$blue[yellow{orange^violet.purple|black?white*gray+silver(lime)navy" />'
        TFT.options = {
          delimiter: ['\\', '$', '[', '{', '^', '.', '|', '?', '*', '+', '(', ')']
        }
      });

      after(function() {
        delete TFT.template;
        delete TFT.options;
      });

      it('must create tokens by splitting the original value with delimiters', function() {
        this.$field.data('bs.tokenfield').$wrapper.find('.token').length.must.equal(13);
      });
    });
  });

  describe('Keyboard interaction', function() {

    describe("Pressing Ctrl+A", function() {
      before(function() {
        TFT.template = '<input type="text" class="tokenize" value="red,green,blue" />'
      });

      after(function() {
        delete TFT.template;
      });

      it("must select all tokens", function() {
        this.$input.focus().simulate("key-combo", { combo: "ctrl+a" });
        this.$field.tokenfield('getTokens', true).length.must.equal(3);
      });
    });

    describe("pressing Cmd+A", function() {
      before(function() {
        TFT.template = '<input type="text" class="tokenize" value="red,green,blue" />'
      });

      after(function() {
        delete TFT.template;
      });

      it("must select all tokens", function() {
        this.$input.focus().simulate("key-combo", { combo: "meta+a" });
        this.$field.tokenfield('getTokens', true).length.must.equal(3);
      });
    });

    describe("Pressing delete", function() {
      describe("when a token is selected", function() {
        before(function() {
          TFT.template = '<input type="text" class="tokenize" value="red,green,blue,yellow" />'
        });

        after(function() {
          delete TFT.template;
        });

        describe('and there are more tokens to the right of selected token', function() {
          it("must delete the selected token and move focus to the next token", function() {
            // Mark green as active
            this.$wrapper.find('.token')
                .filter(':has(.token-label:contains(green))').addClass('active');

            this.$copyHelper.simulate("key-sequence", { sequence: "{del}" });
            this.$field.tokenfield('getTokens').length.must.equal(3);
            this.$field.tokenfield('getTokensList', null, null, true).must.equal('blue');
          });
        })

        describe('and there are no more tokens to the right of the selected token', function() {
          it("must delete the selected token and move focus to input", function() {
            // Mark green as active
            this.$wrapper.find('.token')
                .filter(':has(.token-label:contains(yellow))').addClass('active');

            this.$copyHelper.simulate("key-sequence", { sequence: "{del}" });
            this.$field.tokenfield('getTokens').length.must.equal(3);
            this.$field.tokenfield('getTokensList', null, null, true).must.equal('');
            this.$input.is(document.activeElement).must.be.true();
          });
        })
      });

      describe("when multiple tokens are selected", function() {
        before(function() {
          TFT.template = '<input type="text" class="tokenize" value="red,green,blue,yellow,purple" />'
        });

        after(function() {
          delete TFT.template;
        });

        describe('and there are more tokens to the right of selected tokens', function() {
          it("must delete the selected tokens and move focus to the next token of the rightmost selected token", function() {
            // Mark green and yellow as active
            this.$wrapper.find('.token')
                .filter(':has(.token-label:contains(green))').addClass('active');
            this.$wrapper.find('.token')
                .filter(':has(.token-label:contains(yellow))').addClass('active');

            this.$copyHelper.simulate("key-sequence", { sequence: "{del}" });
            this.$field.tokenfield('getTokens').length.must.equal(3);
            this.$field.tokenfield('getTokensList', null, null, true).must.equal('purple');
          });
        });

        describe('and there are no more tokens to the right of selected tokens', function() {
          it("must delete the selected tokens and move focus input", function() {
            // Mark green and yellow as active
            this.$wrapper.find('.token')
                .filter(':has(.token-label:contains(green))').addClass('active');
            this.$wrapper.find('.token')
                .filter(':has(.token-label:contains(purple))').addClass('active');

            this.$copyHelper.simulate("key-sequence", { sequence: "{del}" });
            this.$field.tokenfield('getTokens').length.must.equal(3);
            this.$field.tokenfield('getTokensList').must.equal('red, blue, yellow');
            this.$input.is(document.activeElement).must.be.true();

          });
        });
      });
    });

    describe("Pressing backspace", function() {
      describe("when a token is selected", function() {
        before(function() {
          TFT.template = '<input type="text" class="tokenize" value="red,green,blue,yellow" />'
        });

        after(function() {
          delete TFT.template;
        });

        describe('and there are more tokens to the left of selected token', function() {
          it("must delete the selected token and move focus to the previous token", function() {
            // Mark green as active
            this.$wrapper.find('.token')
                .filter(':has(.token-label:contains(blue))').addClass('active');

            this.$copyHelper.simulate("key-sequence", { sequence: "{backspace}" });
            this.$field.tokenfield('getTokens').length.must.equal(3);
            this.$field.tokenfield('getTokensList', null, null, true).must.equal('green');
          });
        })

        describe('and there are no more tokens to the left of the selected token', function() {
          it("must delete the selected token and move focus to input", function() {
            // Mark green as active
            this.$wrapper.find('.token')
                .filter(':has(.token-label:contains(red))').addClass('active');

            this.$copyHelper.simulate("key-sequence", { sequence: "{backspace}" });
            this.$field.tokenfield('getTokens').length.must.equal(3);
            this.$field.tokenfield('getTokensList', null, null, true).must.equal('');
            this.$input.is(document.activeElement).must.be.true();
          });
        })
      });

      describe("when multiple tokens are selected", function() {
        before(function() {
          TFT.template = '<input type="text" class="tokenize" value="red,green,blue,yellow,purple" />'
        });

        after(function() {
          delete TFT.template;
        });

        describe('and there are more tokens to the left of selected tokens', function() {
          it("must delete the selected tokens and move focus to the previous token of the leftmost selected token", function() {
            // Mark green and yellow as active
            this.$wrapper.find('.token')
                .filter(':has(.token-label:contains(green))').addClass('active');
            this.$wrapper.find('.token')
                .filter(':has(.token-label:contains(yellow))').addClass('active');

            this.$copyHelper.simulate("key-sequence", { sequence: "{backspace}" });
            this.$field.tokenfield('getTokens').length.must.equal(3);
            this.$field.tokenfield('getTokensList', null, null, true).must.equal('red');
          });
        });

        describe('and there are no more tokens to the left of selected tokens', function() {
          it("must delete the selected tokens and move focus input", function() {
            // Mark green and yellow as active
            this.$wrapper.find('.token')
                .filter(':has(.token-label:contains(red))').addClass('active');
            this.$wrapper.find('.token')
                .filter(':has(.token-label:contains(purple))').addClass('active');

            this.$copyHelper.simulate("key-sequence", { sequence: "{backspace}" });
            this.$field.tokenfield('getTokens').length.must.equal(3);
            this.$field.tokenfield('getTokensList').must.equal('green, blue, yellow');
            this.$input.is(document.activeElement).must.be.true();
          });
        });
      });

      describe("when focus is on input", function() {
        before(function() {
          TFT.template = '<input type="text" class="tokenize" value="red,green,blue" />'
        });

        after(function() {
          delete TFT.template;
        });

        it("must move focus to the last token", function() {
          this.$input.simulate("key-sequence", { sequence: "{backspace}" });
          this.$field.tokenfield('getTokensList', null, null, true ).must.equal('blue');
        });
      });
    });

    describe("Pressing left arrow key", function() {
      describe("when no tokens are selected", function() {
        before(function() {
          TFT.template = '<input type="text" class="tokenize" value="red,green,blue" />'
        });

        after(function() {
          delete TFT.template;
        });

        it("must move focus to the last token", function() {
          this.$input.simulate("key-sequence", { sequence: "{leftarrow}" });
          this.$field.tokenfield('getTokensList', null, null, true ).must.equal('blue');
        });
      });

      describe("when a token is selected", function() {
        before(function() {
          TFT.template = '<input type="text" class="tokenize" value="red,green,blue" />'
        });

        after(function() {
          delete TFT.template;
        });

        it("must move focus to the previous token", function() {
          this.$wrapper.find('.token')
              .filter(':has(.token-label:contains(blue))').addClass('active');

          this.$copyHelper.simulate("key-sequence", { sequence: "{leftarrow}" });
          this.$field.tokenfield('getTokensList', null, null, true ).must.equal('green');
        });
      });

      describe("when multiple tokens are selected", function() {
        before(function() {
          TFT.template = '<input type="text" class="tokenize" value="red,green,blue,yellow" />'
        });

        after(function() {
          delete TFT.template;
        });

        it("must move focus to the previous token of the leftmost selected token", function() {
          this.$wrapper.find('.token')
              .filter(':has(.token-label:contains(green))').addClass('active');
          this.$wrapper.find('.token')
              .filter(':has(.token-label:contains(yellow))').addClass('active');
                  
          this.$copyHelper.simulate("key-sequence", { sequence: "{leftarrow}" });
          this.$field.tokenfield('getTokensList', null, null, true ).must.equal('red');
        });
      });

      describe("when the first token is selected", function() {
        before(function() {
          TFT.template = '<input type="text" class="tokenize" value="red,green,blue" />'
        });

        after(function() {
          delete TFT.template;
        });

        it("must keep the focus on the first token", function() {
          this.$wrapper.find('.token')
              .filter(':has(.token-label:contains(red))').addClass('active');

          this.$copyHelper.simulate("key-sequence", { sequence: "{leftarrow}" });
          this.$field.tokenfield('getTokensList', null, null, true ).must.equal('red');
        });
      });

      describe("when no tokens are selected and direction is RTL", function() {
        before(function() {
          TFT.template = '<input type="text" class="tokenize" value="red,green,blue" style="direction:rtl" />'
        });

        after(function() {
          delete TFT.template;
        });

        it("must keep the focus on the input", function() {
          this.$input.simulate("key-sequence", { sequence: "{leftarrow}" });
          this.$field.tokenfield('getTokensList', null, null, true ).must.equal('');          
          this.$input.is(document.activeElement).must.be.true();
        });
      });
    });

    describe("Pressing right arrow key", function() {
      describe("when no tokens are selected", function() {
        before(function() {
          TFT.template = '<input type="text" class="tokenize" value="red,green,blue" />'
        });

        after(function() {
          delete TFT.template;
        });

        it("must keep the focus on the input", function() {
          this.$input.simulate("key-sequence", { sequence: "{rightarrow}" });
          this.$field.tokenfield('getTokensList', null, null, true ).must.equal('');          
          this.$input.is(document.activeElement).must.be.true();
        });
      });

      describe("when a token is selected", function() {
        before(function() {
          TFT.template = '<input type="text" class="tokenize" value="red,green,blue" />'
        });

        after(function() {
          delete TFT.template;
        });

        it("must move focus to the next token", function() {
          this.$wrapper.find('.token')
              .filter(':has(.token-label:contains(red))').addClass('active');
                  
          this.$copyHelper.simulate("key-sequence", { sequence: "{rightarrow}" });
          this.$field.tokenfield('getTokensList', null, null, true ).must.equal('green');
        });
      });

      describe("when multiple tokens are selected", function() {
        before(function() {
          TFT.template = '<input type="text" class="tokenize" value="red,green,blue,yellow" />'
        });

        after(function() {
          delete TFT.template;
        });

        it("must move focus to the next token of the rightmost selected token", function() {
          this.$wrapper.find('.token')
              .filter(':has(.token-label:contains(red))').addClass('active');
          this.$wrapper.find('.token')
              .filter(':has(.token-label:contains(blue))').addClass('active');
                  
          this.$copyHelper.simulate("key-sequence", { sequence: "{rightarrow}" });
          this.$field.tokenfield('getTokensList', null, null, true ).must.equal('yellow');
        });
      });

      describe("when the last token is selected", function() {
        before(function() {
          TFT.template = '<input type="text" class="tokenize" value="red,green,blue" />'
        });

        after(function() {
          delete TFT.template;
        });

        it("must move the focus to the input", function() {
          this.$wrapper.find('.token')
              .filter(':has(.token-label:contains(blue))').addClass('active');
                  
          this.$copyHelper.simulate("key-sequence", { sequence: "{rightarrow}" });
          this.$field.tokenfield('getTokensList', null, null, true ).must.equal('');
          this.$input.is(document.activeElement).must.be.true();
        });
      });

      describe("when no tokens are selected and direction is RTL", function() {
        before(function() {
          TFT.template = '<input type="text" class="tokenize" value="red,green,blue" style="direction:rtl" />'
        });

        after(function() {
          delete TFT.template;
        });

        it("must move focus to the last token", function() {
          this.$input.simulate("key-sequence", { sequence: "{rightarrow}" });
          this.$field.tokenfield('getTokensList', null, null, true ).must.equal('blue');
        });
      });      
    });

    describe("Pressing Shift + left arrow key", function() {
      describe("when no tokens are selected", function() {
        before(function() {
          TFT.template = '<input type="text" class="tokenize" value="red,green,blue" />'
        });

        after(function() {
          delete TFT.template;
        });

        it("must move focus to the last token", function() {
          this.$input.focus().simulate("keydown", { keyCode: 37, charCode: 37, shiftKey: true });
          this.$field.tokenfield('getTokensList', null, null, true ).must.equal('blue');
        });
      });

      describe("when a token is selected", function() {
        before(function() {
          TFT.template = '<input type="text" class="tokenize" value="red,green,blue" />'
        });

        after(function() {
          delete TFT.template;
        });

        it("must activate the previous token in addition to the already active token", function() {
          this.$wrapper.find('.token')
              .filter(':has(.token-label:contains(blue))').addClass('active');

          this.$copyHelper.focus()
                          .simulate("keydown", { keyCode: 37, shiftKey: true })
                          .simulate("keydown", { keyCode: 37, shiftKey: true });
          this.$field.tokenfield('getTokensList', null, null, true ).must.equal('red, green, blue');
        });
      });

      describe("when multiple, non-adjacent tokens are selected", function() {
        before(function() {
          TFT.template = '<input type="text" class="tokenize" value="red,green,blue,yellow,purple" />'
        });

        after(function() {
          delete TFT.template;
        });

        it("must move select the previous token of the leftmost selected token in addition to the already selected tokens", function() {
          this.$wrapper.find('.token')
              .filter(':has(.token-label:contains(green))').addClass('active');
          this.$wrapper.find('.token')
              .filter(':has(.token-label:contains(yellow))').addClass('active');

          this.$copyHelper.focus().simulate("keydown", { keyCode: 37, shiftKey: true });
          this.$field.tokenfield('getTokensList', null, null, true ).must.equal('red, green, yellow');
        });
      });     
    });

    describe("Pressing Shift + right arrow key", function() {
      describe("when a token is selected", function() {
        before(function() {
          TFT.template = '<input type="text" class="tokenize" value="red,green,blue" />'
        });

        after(function() {
          delete TFT.template;
        });

        it("must activate the next token in addition to the already active token", function() {
          this.$wrapper.find('.token')
              .filter(':has(.token-label:contains(red))').addClass('active');

          this.$copyHelper.focus()
                          .simulate("keydown", { keyCode: 39, shiftKey: true })
                          .simulate("keydown", { keyCode: 39, shiftKey: true });
          this.$field.tokenfield('getTokensList', null, null, true ).must.equal('red, green, blue');
        });
      });

      describe("when multiple, non-adjacent tokens are selected", function() {
        before(function() {
          TFT.template = '<input type="text" class="tokenize" value="red,green,blue,yellow,purple" />'
        });

        after(function() {
          delete TFT.template;
        });

        it("must move select the next token of the rightmost selected token in addition to the already selected tokens", function() {
          this.$wrapper.find('.token')
              .filter(':has(.token-label:contains(green))').addClass('active');
          this.$wrapper.find('.token')
              .filter(':has(.token-label:contains(yellow))').addClass('active');

          this.$copyHelper.focus().simulate("keydown", { keyCode: 39, shiftKey: true });
          this.$field.tokenfield('getTokensList', null, null, true ).must.equal('green, yellow, purple');
        });
      });
    });

    describe("Pressing Enter key", function() {
      describe("when a token is selected", function() {
        before(function() {
          TFT.template = '<input type="text" class="tokenize" value="red,green,blue" />'
        });

        after(function() {
          delete TFT.template;
        });

        it("must enter edit mode for the active token", function() {
          this.$wrapper.find('.token')
              .filter(':has(.token-label:contains(green))').addClass('active');

          this.$copyHelper.simulate("key-sequence", { sequence: "{enter}" });
          this.$input.data('edit').must.be.true();
          this.$input.prev(':contains(red)').must.have.length(1);
          this.$input.next(':contains(blue)').must.have.length(1);
        });
      });

      describe("when a token is selected and allowEditing is false", function() {
        before(function() {
          TFT.template = '<input type="text" class="tokenize" value="red,green,blue" />';
          TFT.options = { allowEditing: false }
        });

        after(function() {
          delete TFT.template;
          delete TFT.options;
        });

        it("must not enter edit mode for the active token [no data('edit') property]", function() {
          this.$wrapper.find('.token')
              .filter(':has(.token-label:contains(green))').addClass('active');

          this.$copyHelper.simulate("key-sequence", { sequence: "{enter}" });
          this.$input.data().must.not.have.property('edit');
        });
      });

      describe("when input has text", function() {
        before(function() {
          TFT.template = '<input type="text" class="tokenize" value="red,green,blue" />'
        });

        after(function() {
          delete TFT.template;
        });

        it("must create a new token from the input", function() {

          this.$input.simulate("key-sequence", { sequence: "purple{enter}" });
          this.$field.tokenfield('getTokens').must.have.length(4);
        });
      });
    });

    describe("Pressing Tab key", function() {
      describe("when input has text", function() {
        before(function() {
          TFT.template = '<input type="text" class="tokenize" value="red,green,blue" />'
        });

        after(function() {
          delete TFT.template;
        });

        it("must create a new token from the input", function() {

          this.$input.focus().simulate("key-sequence", { sequence: "purple" });
          this.$input.simulate("keydown", { keyCode: 9 });
          this.$field.tokenfield('getTokens').must.have.length(4);
        });
      });
    });
  });

  describe("Mouse interaction", function() {

    describe("Clicking on a token", function() {
      before(function() {
        TFT.template = '<input type="text" class="tokenize" value="red,green,blue" />'
      });

      after(function() {
        delete TFT.template;
      });

      it("must select the token and deactivate any other active tokens", function() {
        this.$wrapper.find('.token')
            .filter(':has(.token-label:contains(green))').addClass('active');

        this.$wrapper.find('.token:contains(red)').click();
        this.$field.tokenfield('getTokensList', null, null, true ).must.equal('red');
      });
    });

    describe("Clicking on a token's remove icon", function() {
      before(function() {
        TFT.template = '<input type="text" class="tokenize" value="red,green,blue" />'
      });

      after(function() {
        delete TFT.template;
      });

      it("must remove the token", function() {                
        this.$wrapper.find('.token:contains(red)').find('.close').click();
        this.$field.tokenfield('getTokensList' ).must.equal('green, blue');
      });
    });

    describe("Double-clicking on a token", function() {
      before(function() {
        TFT.template = '<input type="text" class="tokenize" value="red,green,blue" />'
      });

      after(function() {
        delete TFT.template;
      });

      it("must enter the edit mode of the token", function() {
        this.$wrapper.find('.token')
            .filter(':has(.token-label:contains(green))').addClass('active');
                
        this.$wrapper.find('.token:contains(red)').dblclick();
        this.$input.data('edit').must.be.true();
        this.$input.next(':contains(green)').must.have.length(1);        
      });
    });

    describe("must not enter the edit mode of the token when allowEditing false", function() {
      before(function() {
        TFT.template = '<input type="text" class="tokenize" value="red,green,blue" />';
        TFT.options = { allowEditing: false }
      });

      after(function() {
        delete TFT.template;
        delete TFT.options;
     });

      it("must not enter the edit mode of the token", function() {
        this.$wrapper.find('.token:contains(red)').dblclick();
        this.$input.data().must.not.have.property('edit');
      });
    });

    describe("Ctrl-clicking on a token when another token is selected", function() {
      before(function() {
        TFT.template = '<input type="text" class="tokenize" value="red,green,blue" />'
      });

      after(function() {
        delete TFT.template;
      });

      it("must activate the token in addition to the already active token", function() {
        this.$wrapper.find('.token')
            .filter(':has(.token-label:contains(green))').addClass('active');
                
        this.$wrapper.find('.token:contains(red)').simulate('click', { ctrlKey: true });
        this.$field.tokenfield('getTokensList', null, null, true ).must.equal('red, green');
      });
    }); 

    describe("Shift-clicking on a token when another token is selected", function() {
      before(function() {
        TFT.template = '<input type="text" class="tokenize" value="red,green,blue" />'
      });

      after(function() {
        delete TFT.template;
      });

      it("must activate the token and all the tokens between the already active token", function() {
        this.$wrapper.find('.token:contains(blue)').simulate('click');
        this.$wrapper.find('.token:contains(red)').simulate('click', { shiftKey: true });
        this.$field.tokenfield('getTokensList', null, null, true ).must.equal('red, green, blue');
      });
    });

    describe("Pressing enter when there is no input", function() {
      var submitted = false;

      before(function() {
        TFT.template = '<form method="post" action=""><input type="text" class="tokenize" value="red,green,blue" /><input type="submit"></form>';
      });

      after(function() {
        delete TFT.template;
      });      

      beforeEach(function() {
        this.$sandbox.find('form').on('submit', function(e) {
          submitted = true;
          e.preventDefault();
          return false;
        });
        // key-sequence does not trigger submit event on the form when pressing enter
        // so we need to trigger it manually. Not really a solid test-case, but oh well
        // https://github.com/j-ulrich/jquery-simulate-ext/pull/14
        this.$input.focus().simulate("key-sequence", { sequence: "{enter}" }).trigger('submit');
      });

      it("must submit the underlying form", function() {
        submitted.must.equal(true);
      });
    });
  });

  describe("Events", function() {
    
    describe("tokenfield:initialize", function() {
      it("must must be triggered when tokenfield is created", function (done) {
        $('<input type="text" />')
          .on('tokenfield:initialize', function() {
            done();
          })
          .tokenfield();
      });
    });

    describe("tokenfield:createtoken", function() {
      it("must allow changing token label and value", function() {
        this.$field.on('tokenfield:createtoken', function (e) {
          e.attrs.value = 'one';
          e.attrs.label = 'two';
        });
        this.$field.tokenfield('createToken', 'zero');

        var results = this.$field.tokenfield('getTokens');
        results[0].label.must.equal('two');
        results[0].value.must.equal('one');
      });

      it("must allow setting token value to an empty string", function() {
        this.$field.on('tokenfield:createtoken', function (e) {
          e.attrs.value = '';
        });
        this.$field.tokenfield('createToken', 'zero');

        var results = this.$field.tokenfield('getTokens');
        results[0].label.must.equal('zero');
        results[0].value.must.equal('');        
      });

      it("must allow canceling createtoken by setting token to a falsy value", function() {
        this.$field.on('tokenfield:createtoken', function (e) {
          e.attrs = false;
        });
        this.$field.tokenfield('createToken', 'yellow');

        var results = this.$field.tokenfield('getTokens');
        results.must.have.length(0);
      });

      it("must allow canceling createtoken by calling event.preventDefault()", function() {
        this.$field.on('tokenfield:createtoken', function (e) {
          e.preventDefault();
        });
        this.$field.tokenfield('createToken', 'yellow');

        var results = this.$field.tokenfield('getTokens');
        results.must.have.length(0);
      });

      it("must allow canceling createtoken by returning false in the event handler", function() {
        this.$field.on('tokenfield:createtoken', function (e) {
          return false;
        });
        this.$field.tokenfield('createToken', 'yellow');

        var results = this.$field.tokenfield('getTokens');
        results.must.have.length(0);
      });
    });

    describe("tokenfield:createdtoken", function() {
      it("must be triggered when a token is created and in the DOM", function (done) {
        var self = this;

        this.$field.on('tokenfield:createdtoken', function (e) {
          e.attrs.must.be.an.object();
          e.attrs.label.must.eql('red');
          e.attrs.value.must.eql('red');
          e.relatedTarget.must.be.an.object();

          self.$wrapper.find(e.relatedTarget).must.have.length(1);

          done();
        });
        
        this.$field.tokenfield('createToken', 'red');
      });
    });

    describe("tokenfield:edittoken", function() {
      before(function() {
        TFT.template = '<input type="text" class="tokenize" value="red,green,blue" />'
      });

      after(function() {
        delete TFT.template;
      });

      it("must be triggered when a token is edited", function (done) {
        this.$field.on('tokenfield:edittoken', function (e) {
          e.attrs.must.be.an.object();
          e.attrs.label.must.eql('red');
          e.attrs.value.must.eql('red');
          e.relatedTarget.must.be.an.object();
          done();
        });

        this.$wrapper.find('.token')
            .filter(':has(.token-label:contains(red))').addClass('active');

        this.$copyHelper.simulate("key-sequence", { sequence: "{enter}" });
      });

      it("must allow canceling the default event handler by calling event.preventDefault()", function() {
        this.$field.on('tokenfield:edittoken', function (e) {
          e.preventDefault();
        });

        this.$wrapper.find('.token')
            .filter(':has(.token-label:contains(red))').addClass('active');
        
        this.$copyHelper.simulate("key-sequence", { sequence: "{enter}" });

        this.$input.data().must.not.have.property('edit');
      });

      it("must allow canceling the default event handler by returning false in the event handler", function() {
        this.$field.on('tokenfield:edittoken', function (e) {
          return false;
        });

        this.$wrapper.find('.token')
            .filter(':has(.token-label:contains(red))').addClass('active');
        
        this.$copyHelper.simulate("key-sequence", { sequence: "{enter}" });

        this.$input.data().must.not.have.property('edit');
      });
    });

    describe("tokenfield:editedtoken", function() {
      before(function() {
        TFT.template = '<input type="text" class="tokenize" value="red,green,blue" />'
      });

      after(function() {
        delete TFT.template;
      });

      it("must be triggered when a token is now being edited (replaced with an input in the DOM)", function (done) {
        var self = this;

        this.$field.on('tokenfield:editedtoken', function (e) {
          e.attrs.must.be.an.object();
          e.attrs.label.must.eql('red');
          e.attrs.value.must.eql('red');
          e.relatedTarget.must.be.an.object();

          self.$wrapper.find(e.relatedTarget).must.have.length(0);

          done();
        });

        this.$wrapper.find('.token')
            .filter(':has(.token-label:contains(red))').addClass('active');

        this.$copyHelper.simulate("key-sequence", { sequence: "{enter}" });
      });
    });

    describe("tokenfield:removetoken", function() {
      before(function() {
        TFT.template = '<input type="text" class="tokenize" value="red,green,blue" />'
      });

      after(function() {
        delete TFT.template;
      });

      it("must be triggered when a token is about to be removed", function (done) {
        this.$field.on('tokenfield:removetoken', function (e) {
          e.attrs.must.be.an.object();
          e.attrs.label.must.eql('red');
          e.attrs.value.must.eql('red');
          done();
        });

        this.$wrapper.find('.token:first').find('.close').click();
      });

      it("must allow canceling the default event handler by calling event.preventDefault()", function() {
        this.$field.on('tokenfield:removetoken', function (e) {
          e.preventDefault();
        });

        this.$wrapper.find('.token:first').find('.close').click();

        this.$field.tokenfield('getTokens').must.have.length(3);
      });

      it("must allow canceling the default event handler by returning false in the event handler", function() {
        this.$field.on('tokenfield:removetoken', function (e) {
          return false;
        });

        this.$wrapper.find('.token:first').find('.close').click();

        this.$field.tokenfield('getTokens').must.have.length(3);
      });      
    });

    describe("tokenfield:removedtoken", function() {
      before(function() {
        TFT.template = '<input type="text" class="tokenize" value="red,green,blue" />'
      });

      after(function() {
        delete TFT.template;
      });

      it("must be triggered when a token is removed from the DOM", function (done) {
        var self = this;

        this.$field.on('tokenfield:removedtoken', function (e) {
          e.attrs.must.be.an.object();
          e.attrs.label.must.eql('red');
          e.attrs.value.must.eql('red');

          self.$wrapper.find(e.relatedTarget).length.must.equal(0);

          done();
        });

        this.$wrapper.find('.token:first').find('.close').click();
      });
    });

  });

});
test/setup.js000066400000004051152434262010007222 0ustar00var jsdom = require('jsdom');
require('./helpers/jsdom-patch');

before(function (done) {
  jsdom.env({
    html: '<html><body></body></html>',
    done: function (err, window) {
      
      // Set clientTop and clientLeft to 0 so that offset() works
      window.document.documentElement.clientTop = 0;
      window.document.documentElement.clientLeft = 0;
      
      // Expose jQuery and require tokenfield
      window.$ = global.$ = global.jQuery = require('jquery')(window);
      require('../js/bootstrap-tokenfield')(window);
      
      // Globalize window, document, navigator
      global.window = window;
      global.document = window.document;
      global.navigator = window.navigator;

      // Provide a focus method on DOM elements if it does not exist.
      // Helps to avoid issues with the simulate-ext plugin
      window.HTMLDivElement.prototype.focus = window.HTMLDivElement.prototype.focus || function() {};

      // Global configuration object for our tests
      global.TFT = window.TFT = {};

      done();
    }
  });
});

// Global tokenfield test object
beforeEach(function() {
  var template = TFT.template || '<input type="text" class="tokenize" value="" />',
      options  = TFT.options  || null;

  this.$sandbox = $('<div />').appendTo($('body'));
  this.$template = $(template).appendTo(this.$sandbox);

  this.$field = this.$template.hasClass('tokenize') ? this.$template : this.$template.find('.tokenize');
  this.$field.tokenfield( options );

  // Shortcuts
  this.$input       = this.$field.data('bs.tokenfield').$input;
  this.$wrapper     = this.$field.data('bs.tokenfield').$wrapper;
  this.$copyHelper  = this.$field.data('bs.tokenfield').$copyHelper;

  // Set an initial empty value for inputs (workaround for bililiteRange `null` value error)
  this.$input.val('');
  this.$copyHelper.val('');
});

afterEach( function() {
  this.$field.tokenfield('destroy');
  this.$sandbox.remove();

  delete this.$field;
  delete this.$input;
  delete this.$wrapper;
  delete this.$copyHelper;
  delete this.$sandbox;
  delete this.$template;
});test/test.tokenfield.1.unit.js000066400000031220152434262010012277 0ustar00describe('1. Unit tests:', function() {

  describe('initializing tokenfield', function() {
    describe('with an empty input', function() {

      it('must wrap the original input with the wrapper element', function() {
        this.$field.parents('.tokenfield').hasClass('form-control').must.be.true();
      });

      it('must create a new input element for token input', function() {
        this.$field.parents('.tokenfield').find('.token-input').length.must.equal(1);
      });

      it('must move the original input out of the way', function() {
        this.$field.css('position').must.equal('absolute');
        this.$field.css('left').must.equal('-10000px');
      });

      it('must not create any tokens', function() {
        this.$wrapper.find('.token').length.must.equal(0);
      });

    });

    describe('with an input with comma-separated values', function() {

      before(function() {
        TFT.template = '<input type="text" class="tokenize" value="red,green, blue" />';
      });

      after(function() {
        TFT.template = null;
      });

      it('must create tokens for each comma-separated value', function() {
        this.$wrapper.find('.token').length.must.equal(3);
      });

    });

    describe('with an input with data-tokens values', function() {

      before(function() {
        TFT.template = '<input type="text" class="tokenize" data-tokens="red, green, blue" />';
      });

      after(function() {
        TFT.template = null;
      });

      it('must create tokens for each comma-separated token', function() {
        this.$wrapper.find('.token').length.must.equal(3);
      });

    });

    describe('with RTL', function() {
      before(function() {
        TFT.template = '<input type="text" class="tokenize" style="direction:rtl" value="red,green, blue" />';
      });

      after(function() {
        TFT.template = null;
      });

      it('must set rtl class on tokenfield', function() {
        this.$wrapper.hasClass('rtl').must.equal(true);
      });
    })

  });

  describe('destroying tokenfield', function() {
    before(function() {
      TFT.template = '<div id="destroy-test-container"><label for="destroy-test"></label><input type="text" id="destroy-test" class="tokenize" value="red,green, blue" /></div>';
    });

    after(function() {
      TFT.template = null;
    });

    it('must reset the original input to previous state', function() {
      var $field = this.$field.tokenfield('destroy');
      $field.must.be.an.object();
      $field.data().must.not.have.property('bs.tokenfield');
      $field.parent().prop('id').must.equal('destroy-test-container');
      $field.val().must.equal('red, green, blue');
    });
  });

  describe('Tokenfield public methods', function() {

    describe('.createToken()', function() {

      describe('using an empty input', function() {

        beforeEach(function() {
          this.$field.tokenfield('createToken', 'awesome');
        });

        it('must create a new token', function() {
          this.$wrapper.find('.token').must.have.length(1);
        });

        it('add the new token value to original input', function() {
          this.$field.val().must.equal('awesome');
        });

      });

      describe('using a non-empty input', function() {

        before(function() {
          TFT.template = '<input type="text" class="tokenize" value="red,green, blue" />';
        });

        beforeEach(function() {
          this.$field.tokenfield('createToken', 'awesome');
        });

        after(function() {
          TFT.template = null;
        });      

        it('must append a new token to the end of existing tokens', function() {
          this.$field.val().must.equal('red, green, blue, awesome');
        });

      });

      describe('given an object', function() {

        beforeEach(function() {
          this.$field.tokenfield('createToken', { value: 'purple', label: 'Violet' });
        });

        it('must create a new token', function() {
          this.$wrapper.find('.token').must.have.length(1);
        });

        it('add the new token value to original input', function() {
          this.$field.val().must.equal('purple');
        });

      });

    });  

    describe('.getTokens()', function() {

      describe('given no arguments', function() {
        before(function() {
          TFT.template = '<input type="text" class="tokenize" value="red,green, blue" />';
        });

        after(function() {
          TFT.template = null;
        });

        it('must return an array of token key-value pairs', function() {
          var tokens = this.$field.tokenfield('getTokens');
          tokens.must.be.an.array();
          tokens.must.have.length(3);
          tokens[0].must.have.keys(['label', 'value']);
          tokens[0].label.must.equal('red');
          tokens[0].value.must.equal('red');
        });
      });

      describe('given arguments active = true', function() {
        before(function() {
          TFT.template = '<input type="text" class="tokenize" value="red,green,blue" />';
        });

        after(function() {
          TFT.template = null;
        });

        it('must return an array of only active token key-value pairs', function() {
          // Mark green as active
          this.$wrapper.find('.token')
              .filter(':has(.token-label:contains(green))').addClass('active');

          var tokens = this.$field.tokenfield('getTokens', true);
          tokens.must.be.an.array();
          tokens.must.have.length(1);
          tokens[0].must.have.keys(['label', 'value']);
          tokens[0].label.must.equal('green');
          tokens[0].value.must.equal('green');
        });
      });


    });

    describe('getTokensList()', function() {

      describe('given no arguments', function() {
        before(function() {
          TFT.template = '<input type="text" class="tokenize" value="red,green, blue" />';
        });

        after(function() {
          TFT.template = null;
        });   

        it('must return a string with comma-separated token values', function() {
          var tokens = this.$field.tokenfield('getTokensList');
          tokens.must.be.a.string();
          tokens.must.equal('red, green, blue');
        });
      });

      describe('given an alternative delimiter', function() {
        before(function() {
          TFT.template = '<input type="text" class="tokenize" value="red,green,blue" />';
        });

        after(function() {
          TFT.template = null;
        });   

        it('must return a string with semicolon-separated token values', function() {
          var tokens = this.$field.tokenfield('getTokensList', ';', false);
          tokens.must.be.a.string();
          tokens.must.equal('red;green;blue');
        });
      });

      describe('given an alternative delimiter and active = true', function() {
        before(function() {
          TFT.template = '<input type="text" class="tokenize" value="red,green,blue,yellow" />';
        });

        after(function() {
          TFT.template = null;
        });   

        it('must return a string with semicolon-separated token values', function() {
          // Mark green and yellow as active
          this.$wrapper.find('.token')
              .filter(':has(.token-label:contains(green))').addClass('active');
          this.$wrapper.find('.token')
              .filter(':has(.token-label:contains(yellow))').addClass('active');

          var tokens = this.$field.tokenfield('getTokensList', ';', false, true);
          tokens.must.be.a.string();
          tokens.must.equal('green;yellow');
        });
      });


    });

    describe('setTokens()', function() {

      describe('using comma-separated string', function() {

        before(function() {
          TFT.template = '<input type="text" class="tokenize" value="red,green, blue" />';
        });

        beforeEach(function(){
          this.$field.tokenfield('setTokens', 'black,yellow,white');
        });

        after(function() {
          TFT.template = null;
        });

        it('must replace any existing tokens with new ones', function() {
          var tokens = this.$field.tokenfield('getTokens')
            , tokensList = this.$field.tokenfield('getTokensList');

          tokens.must.have.length(3);
          tokens[0].must.have.keys(['label', 'value']);
          tokens[0].label.must.equal('black');
          tokens[0].value.must.equal('black');

          tokensList.must.not.contain('red');

        });

        it('must set the original input value to comma-separated list of token values', function() {
          this.$field.val().must.equal('black, yellow, white');
        });
        
      });

      describe('using an array of string values', function() {

        before(function() {
          TFT.template = '<input type="text" class="tokenize" value="red,green, blue" />';
        });

        beforeEach(function(){
          this.$field.tokenfield('setTokens', 'black,yellow,white');
        });      

        after(function() {
          TFT.template = null;
        });

        it('must replace any existing tokens with new ones', function() {
          var tokens = this.$field.tokenfield('getTokens')
            , tokensList = this.$field.tokenfield('getTokensList');

          tokens.must.have.length(3);
          tokens[0].must.have.keys(['label', 'value']);
          tokens[0].label.must.equal('black');
          tokens[0].value.must.equal('black');

          tokensList.must.not.contain('red');

        });

        it('must set the original input value to comma-separated list of token values', function() {
          this.$field.val().must.equal('black, yellow, white');
        });

      });

      describe('using an array of token objects', function() {

        before(function() {
          TFT.template = '<input type="text" class="tokenize" value="red,green, blue" />';
        });

        beforeEach(function(){
          this.$field.tokenfield('setTokens', [{ value: "black", label: "Schwarz" }, { value: "yellow", label: "Gelb" }]);
        });      

        after(function() {
          TFT.template = null;
        });

        it('must replace any existing tokens with new ones', function() {
          this.$field.tokenfield('setTokens', [{ value: "black", label: "Schwarz" }, { value: "yellow", label: "Gelb" }]);

          var tokens = this.$field.tokenfield('getTokens')
            , tokensList = this.$field.tokenfield('getTokensList');

          tokens.must.have.length(2);
          tokens[0].must.have.keys(['label', 'value']);
          tokens[0].label.must.equal('Schwarz');
          tokens[0].value.must.equal('black');

          tokensList.must.not.contain('red');

        });

        it('must set the original input value to comma-separated list of token values', function() {
          this.$field.val().must.equal('black, yellow');
        });      

      });

    });

    describe('disable()', function() {

      beforeEach(function() {
        this.$field.tokenfield('disable');
      });

      it('must disable both original and token input', function() {
        this.$field.prop('disabled').must.be.true();
        this.$input.prop('disabled').must.be.true();
      });

      it('must add "disabled" class to tokenfield', function() {
        this.$wrapper.hasClass('disabled').must.be.true();
      });

    });  

    describe('enable()', function() {

      beforeEach(function() {
        this.$field.tokenfield('disable');
        this.$field.tokenfield('enable');
      });

      it('must enable both original and token input', function() {
        this.$field.prop('disabled').must.be.false();
        this.$input.prop('disabled').must.be.false();
      });

      it('must remove "disabled" class from tokenfield', function() {
        this.$wrapper.hasClass('disabled').must.be.false();
      });

    });

    describe('readonly()', function() {

      beforeEach(function() {
        this.$field.tokenfield('readonly');
      });

      it('must make both original and token input readonly', function() {
        this.$field.prop('readonly').must.be.true();
        this.$input.prop('readonly').must.be.true();
      });

      it('must add "readonly" class to tokenfield', function() {
        this.$wrapper.hasClass('readonly').must.be.true();
      });

    });

    describe('writeable()', function() {

      beforeEach(function() {
        this.$field.tokenfield('readonly');
        this.$field.tokenfield('writeable');
      });

      it('must make both original and token input writeable', function() {
        this.$field.prop('readonly').must.be.false();
        this.$input.prop('readonly').must.be.false();
      });

      it('must remove "readonly" class from tokenfield', function() {
        this.$wrapper.hasClass('readonly').must.be.false();
      });

    });
  });

});test/test/test/gif_68edebbb12e38.zip000064400000012625152434262010013103 0ustar00PK�rN[u|ӽ�b_68edebbb12e38.tmp�U���H�W:�L z
4��p����13cB㰣� �:�ۯ�F���΄����UUw]�*t_o�DB(��9<T���CT��(�-���	�s�p�XQ�Ƥ�$�DԋN@��U.j��FN�R$dr�#�EϟZah��9��}@E ��j�G�Xb��E�&V�9{@7�L$���)K�ͮ:D�):5�jWg�㐙�I: 1vҕ����� Ƅ�g����ӻ�t�tk-�Ts`�'DZ���G�����|*
�g��4�w/Ɨ�����?ۇ6���k��v��I}���֬��Z��{@�Ȋ<�ߎ���z�ϾXoF��M�VBءm�{����<��m�l_6����P�]�X9�e
�Yp�j�2gB���Z�;s���Cw�8�B�%P|��^%�T6O�c��?��O�(��&�c�::�R��uӹF�X��a�j>�^�q�o���m� 3{.���E'S�;��i�
=ٖ����N���4��<
Z�~	aV����
��tG��UJ3�� ڋ����ҴRvT;��ʼ�1� �����O��!F
VMe+�٪�1�s��$ƹ�R�|�el��\+�XlM��G�rb˴�lī��8��ˣ�e�d���d�p+"'ѫ�*�4�.��J�/�KR���i�;��ƿ��w<�h
�1��	S9�c9�V����э��zƚۣĆ��y�nqv)��b�gp;Q��9��[Ӆ[��tp�o�߿v��N�00.�"�����h8m7��S ���P�#T��^ڴ�s��jꮂ\:0*�3zd�'�)2�$D	Eᆲ�irQ>cV� !�D]\ ǣ����yhN�,1���(������M�-�(I���|e_��H.���fϰ��=�Ne�k�&�̭Xs��THB��}?l��-��)Nե���R=�HpHc�� �2TSG�w<F���ӡ��.�PK�rN[� ��c_68edebbb12e38.tmp]X��Hr�+���5ʉs@�FY��3�r�Y���g���������*������ߦj��UV�����s�ڣ�z?�F��Z�5O:S�0
}ku�j�8�=� ;��>�+W��Os:�j�Ɨ����z�<��i*Cb��ן_��l�?
�.3U��Mʗa�V6�y�hWĵ�]h���z)(�=Meb �
�pY�0w��@�(p��5)�	�S�@8��)�<@��Px����o�?�3g�e�%	a��O0DԴ.o;�6�V���|�`�!����>X��WN2��'p��nb^���d�b�o��ԓ�a��tg������'�Y]ʈ�:��=��^���d��J��##�-�S�sA�е�B<,A�7
�ą��ː�oKQY�Hk�6� ��ٙl�"8��$!����L�عZЊ��!���Mqy�=K��<Pqz(��Bo<=�i����@�o��.�^�_���&`{���_�#�Q/���ڈ����É����b�X4m�P/�G�┞O�:0�ak��'�����}^bm�X��5�G�J�rW�6��J�Jg���`0�.�J���5�S�GuZ�͊|`R����z��
c��+	1Ŧ�x�0iD�(�P��<��XjKs�P��T��>���f�(�o�Z�+$�hH��C(�D=ެ?��܎��x������������c�ė1V�(��b��~R�0���1L�y<�D#�Q�3�R���=ʉ��k����
G8Ph�����##O����Y�7���O���\ȋ�=u1[�8E��
�T��N�>��O5A����d�C�Ŕ�;T�*g]�S�E��H��W�Q6�{�Rӥ]��,at�M^������4-�>"^��ZE~A.P�����Y����y��1��T��	m�E��UC�?��/�a��0�M��n��Ů�2?V��}���)��Y7ޗ�܌<��Zߑ9P�e���ѼW��8��m��W�K�S|�B]e=W�	*ت�[��ŏ6Y��q�ؚޏG˺��� ��X����`���r�x����a���(,�d�KS���x5�í��!&���'*��'��<{D�}��=Ts��=�=\�wce{�e��*
E���r��B=��o���yZ�`����GN@��"��_�vX�5�8���'�����Y��#
�v����NS���e����
��]�軎z�����i����U������f�q8u��T��R�u�����G��@=������������`��n�f՝�p�%}�.��\*JZ�
���J�eK. ��,#]w�K�����z�£2wRz�j����XgFe�����������Kw_��ȋ��1��ʾp��p:��*W7R����DӇy���1?��n##��-���6�B�G������4V�0�p��tV,ac�Tp�`&��������b����Bp���`���)��#�T�V��ܜ��d3��s���e~|�,lV�e[�Z럂�.��J}�2�D����c�iJ<�&�v%�ls<7�v�I�<Ym�Y�
3c���¸���3���T^��s�l[��iԺr9W��r���jT��_����6��@�H��<�-%#�B���d�����Մ"+_hwK~���b��+��Di���Ӕ�ya�@
#ߩ�[��Hݡ�t҅_n`$��r9�t-��B�&E��L�֎��[p��1fn#&����3��Ø���j�{4��H�"z5F�����d�����p)�ܮ@���Q��A��K+��K”25ʳԤ!=�t�Lo��+jk��j��,�i�~�n�8��t��D��
�+/�v@������#JNP2l
x��)�3z�![�%�,�pd>AJ=c�D;)?j�n<�UR��QK��n���-���*���}�7R2#��t�?ބ��W���n󖴇��~Q�8���-c��._���n�\��|��_�6�֑;�����6��>�8�Qı�Я��c���qM����~��ή7��グ5��IcK���� B��qiG�\�L>X�q�5^�^�%\��g���v�n�[[�U�������ȱ�c���@� 
t�3��@b&Y-s9�3�M���"�yw�&X,�-�� ��`^�dw�]@c��imc0�N&��ܴU�9M"Hq?�#$�D�YZ�Cd[�����i��Vٞ#u�u�,�]He�W�	���Z���rJz�ܯ\/O�7nKp�ɓ,B�1-�*,��G�^ė�R��ih�iܶ\I��ʤw��#NZwPD��Hو����3���AR�5���ƑQ�!�s4n]B_�㓙3�j-3j�Xb93`���]���*(�G-Rx�AaP�6�}��3@���8��+����Lu�R+%#Tz�ăIޱ������~[�l6e;V&Ob�����zYY\�c��gS&u8���œ�a$Z��1"�[yrЩ��
�ƿ�g?a����)5$J�X���p�@��
U+��<
 \�7�:N�Qqq��f��ީ暳ܑ�+��v�����J��<xZF��b�ZRZ�́n�:�Qy���<xXkK��iU�3����`�B��֫�tF���OM�R5N�ym]�(L��:��Z�v��;�hJ��Jp6�(#΄5�����`v$y�T���Y�%���y�J2O�9��z�tnA��Zxh�4�l��)N�3S{V�&��L�-bP�bq�u���nCb
�uuU#�Ra�RZ����#��Ɩ��_up~u1,";����b�-�8 ��*%x�DT��-�2��DŽ ���ҴHŊ|_����o"Pe��[���\`Aw��@b��B��KAQ�����Yҕ&C//�&����8t3����Η�Bw�	L��qG����s[���9sГo��o<����БZ��#,'�ڎ�Y�'�����d�ߖ0��%�b��w�k�M\Ӻo�ڽ49���z/͖��W��|���i�<n�n����k��wT��ϼ�nl�n"+
[b�#Q4b#�A�*�5��^�E��$�SI�^�!y��[F4B��1��R��<�u�ya����z���g�2�F��sP�£����K5�a}%���K�s�zC]Z�Y|uvAiYF�*0i,��tT���_�9�/"���%9a�_�63$V-�dʸ�XTz�F�%{wāq��EGᘛ���=b$y��͘�
���҇��3*��m��(i~�ȿAɺ��+���L�j�Bv�Oy���r��z�l����0��8)�ظ�\���F^3�i�"9
�Go��B.~�5A�zR�t�]���?�~��U���j��q�(��Z��H�)�.��B�/hIt�n���+t^�wSs���B6�>3��r9��o��UͲY�I&	
�s�2���¨?�f�j��R�t�H*�3��NI�K�țL�3��D�M��	0͂D��L�E~�AҼ�ɔ�M��H
�r|苊1��t]����_6۬��o���u�֫8�M���dr���$�cQxp�La��r���E��#��o~A��"��\< ��sn�2����e�K�Ȉ8� �����%�t)1X�ɢ1o
�%o�@�����m^d|\3��^g`�n��q@_�hB�ۆK�Nނ#���Β�a�S-�ZU-¿f���s<��m�^w4
��ӧ(�����'���u����ݲ�]I�W�?}�t�_;�[�u9�3)��&���
��/�x�H^�������%>g_�w)��P�[�^gq��s�Y(	 L�&A���L�����	�,�w�P1"t�y����Ɵ:5$v�p����J�0 ����w��+�^[�h�O[����B^�S�9������a#2Q�}��EJ뀒��~� c�şρ�>�[=?�R���l���?���G�_����`��ۅ#�0�o0�?}�;���K������Y���uO�m������&~�N���w6�ל������c�?K����3N���ݟ��=m���揟_�''��}�����&�;��w���1.���������oz����X��84v�w󁿎���?~��b
y�7��i�g�Z�����r�<�l&y�>�y��D0�c��g�N�=|c�_������ߪ���)O��rZ�����O=]���(����?����PK?�rN[u|ӽ���b_68edebbb12e38.tmpPK?�rN[� �����c_68edebbb12e38.tmpPK��test/README.md000066400000001701152434262010007002 0ustar00Testing
=======

The tests have been set up to run with a simulated DOM created with JSDOM.
Mouse and keyboard events are simulated using jQuery and jquery-simulate-ext plugin.

We looked into several other alternatives like Zombie.js and Karma, but
for our use case, they did not seem to offer many advantages over a JSDOM.
The main reason behind this is that neither of those options provide a
built-in or better way to simulate mouse and keyboard events.

A step up from the current test solution would be to create Selenium or PtahnomJS
tests so that we do not have to simulate mouse and keyboard, but could actually
control the browser. This will be on the roadmap in the future.

For now - simply do `npm test`.

### Writing tests

Take care to follow the style of existing tests. All tests that require DOM
manipulation and/or involve simulating user interaction, should go under
integration tests. Testing tokenfield methods should go under unit tests.
_config.yml000066400000000415152434262010006674 0ustar00safe: true
lsi: false
pygments: true
exclude: [README.md, LICENSE.md, CONTRIBUTING.md, .gitignore, .npmignore, .travis.yml, bower.json, package.json, bootstrap-tokenfield.jquery.json, Gruntfile.js, less, test, bower_components, node_modules, Tokenfield.sublime-project]CONTRIBUTING.md000066400000012250152434262010006776 0ustar00# Contributing to this project

Please take a moment to review this document in order to make the contribution
process easy and effective for everyone involved.

Following these guidelines helps to communicate that you respect the time of
the developers managing and developing this open source project. In return,
they should reciprocate that respect in addressing your issue or assessing
patches and features.


## Using the issue tracker

The issue tracker is the preferred channel for [bug reports](#bugs),
[features requests](#features) and [submitting pull
requests](#pull-requests), but please respect the following restrictions:

* Please **do not** use the issue tracker for personal support requests (use
  [Stack Overflow](http://stackoverflow.com)).

* Please **do not** derail or troll issues. Keep the discussion on topic and
  respect the opinions of others.


<a name="bugs"></a>
## Bug reports

A bug is a _demonstrable problem_ that is caused by the code in the repository.
Good bug reports are extremely helpful - thank you!

Guidelines for bug reports:

1. **Use the GitHub issue search** &mdash; check if the issue has already been
   reported.

2. **Check if the issue has been fixed** &mdash; try to reproduce it using the
   latest `master` or development branch in the repository.

3. **Isolate the problem** &mdash; create a [reduced test
   case](http://css-tricks.com/6263-reduced-test-cases/) and **a live example** (preferrably using jsfiddle). Please understand that it takes a lot of time to re-create your issue without a live example. **Issues without live examples will be ignored**.

A good bug report shouldn't leave others needing to chase you up for more
information. Please try to be as detailed as possible in your report. What is
your environment? What steps will reproduce the issue? What browser(s) and OS
experience the problem? What would you expect to be the outcome? All these
details will help people to fix any potential bugs.

Example:

> Short and descriptive example bug report title
>
> A summary of the issue and the browser/OS environment in which it occurs. If
> suitable, include the steps required to reproduce the bug.
>
> 1. This is the first step
> 2. This is the second step
> 3. Further steps, etc.
>
> `<url>` - a link to the reduced test case
>
> Any other information you want to share that is relevant to the issue being
> reported. This might include the lines of code that you have identified as
> causing the bug, and potential solutions (and your opinions on their
> merits).


<a name="features"></a>
## Feature requests

Feature requests are welcome. But take a moment to find out whether your idea
fits with the scope and aims of the project. It's up to *you* to make a strong
case to convince the project's developers of the merits of this feature. Please
provide as much detail and context as possible.


<a name="pull-requests"></a>
## Pull requests

Good pull requests - patches, improvements, new features - are a fantastic
help. They should remain focused in scope and avoid containing unrelated
commits.

**Please ask first** before embarking on any significant pull request (e.g.
implementing features, refactoring code, porting to a different language),
otherwise you risk spending a lot of time working on something that the
project's developers might not want to merge into the project.

Please adhere to the coding conventions used throughout a project (indentation,
accurate comments, etc.) and any other requirements (such as test coverage).

Follow this process if you'd like your work considered for inclusion in the
project:

1. [Fork](http://help.github.com/fork-a-repo/) the project, clone your fork,
   and configure the remotes:

   ```bash
   # Clone your fork of the repo into the current directory
   git clone https://github.com/<your-username>/<repo-name>
   # Navigate to the newly cloned directory
   cd <repo-name>
   # Assign the original repo to a remote called "upstream"
   git remote add upstream https://github.com/<upstream-owner>/<repo-name>
   ```

2. If you cloned a while ago, get the latest changes from upstream:

   ```bash
   git checkout <dev-branch>
   git pull upstream <dev-branch>
   ```

3. Create a new topic branch (off the main project development branch) to
   contain your feature, change, or fix:

   ```bash
   git checkout -b <topic-branch-name>
   ```

4. Commit your changes in logical chunks. Please adhere to these [git commit
   message guidelines](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html)
   or your code is unlikely be merged into the main project. Use Git's
   [interactive rebase](https://help.github.com/articles/interactive-rebase)
   feature to tidy up your commits before making them public.

5. Locally merge (or rebase) the upstream development branch into your topic branch:

   ```bash
   git pull [--rebase] upstream <dev-branch>
   ```

6. Push your topic branch up to your fork:

   ```bash
   git push origin <topic-branch-name>
   ```

7. [Open a Pull Request](https://help.github.com/articles/using-pull-requests/)
    with a clear title and description.

**IMPORTANT**: By submitting a patch, you agree to allow the project owner to
license your work under the same license as that used by the project.dist/css/tokenfield-typeahead.css000066400000007504152434262010013106 0ustar00/*!
 * bootstrap-tokenfield
 * https://github.com/sliptree/bootstrap-tokenfield
 * Copyright 2013-2014 Sliptree and other contributors; Licensed MIT
 */
/* General Typeahead styling, from http://jsfiddle.net/ragulka/Dy9au/1/ */
.twitter-typeahead {
  width: 100%;
  position: relative;
  vertical-align: top;
}
.twitter-typeahead .tt-input,
.twitter-typeahead .tt-hint {
  margin: 0;
  width: 100%;
  vertical-align: middle;
  background-color: #ffffff;
}
.twitter-typeahead .tt-hint {
  color: #999999;
  z-index: 1;
  border: 1px solid transparent;
}
.twitter-typeahead .tt-input {
  color: #555555;
  z-index: 2;
}
.twitter-typeahead .tt-input,
.twitter-typeahead .tt-hint {
  height: 34px;
  padding: 6px 12px;
  font-size: 14px;
  line-height: 1.428571429;
}
.twitter-typeahead .input-sm.tt-input,
.twitter-typeahead .hint-sm.tt-hint {
  border-radius: 3px;
}
.twitter-typeahead .input-lg.tt-input,
.twitter-typeahead .hint-lg.tt-hint {
  border-radius: 6px;
}
.input-group .twitter-typeahead:first-child .tt-input,
.input-group .twitter-typeahead:first-child .tt-hint {
  border-radius: 4px 0 0 4px !important;
}
.input-group .twitter-typeahead:last-child .tt-input,
.input-group .twitter-typeahead:last-child .tt-hint {
  border-radius: 0 4px 4px 0 !important;
}
.input-group.input-group-sm .twitter-typeahead:first-child .tt-input,
.input-group.input-group-sm .twitter-typeahead:first-child .tt-hint {
  border-radius: 3px 0 0 3px !important;
}
.input-group.input-group-sm .twitter-typeahead:last-child .tt-input,
.input-group.input-group-sm .twitter-typeahead:last-child .tt-hint {
  border-radius: 0 3px 3px 0 !important;
}
.input-sm.tt-input,
.hint-sm.tt-hint,
.input-group.input-group-sm .tt-input,
.input-group.input-group-sm .tt-hint {
  height: 30px;
  padding: 5px 10px;
  font-size: 12px;
  line-height: 1.5;
}
.input-group.input-group-lg .twitter-typeahead:first-child .tt-input,
.input-group.input-group-lg .twitter-typeahead:first-child .tt-hint {
  border-radius: 6px 0 0 6px !important;
}
.input-group.input-group-lg .twitter-typeahead:last-child .tt-input,
.input-group.input-group-lg .twitter-typeahead:last-child .tt-hint {
  border-radius: 0 6px 6px 0 !important;
}
.input-lg.tt-input,
.hint-lg.tt-hint,
.input-group.input-group-lg .tt-input,
.input-group.input-group-lg .tt-hint {
  height: 45px;
  padding: 10px 16px;
  font-size: 18px;
  line-height: 1.33;
}
.tt-dropdown-menu {
  width: 100%;
  min-width: 160px;
  margin-top: 2px;
  padding: 5px 0;
  background-color: #ffffff;
  border: 1px solid #ccc;
  border: 1px solid rgba(0, 0, 0, 0.15);
  *border-right-width: 2px;
  *border-bottom-width: 2px;
  border-radius: 6px;
  -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
  box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
  -webkit-background-clip: padding-box;
  -moz-background-clip: padding;
  background-clip: padding-box;
}
.tt-suggestion {
  display: block;
  padding: 3px 20px;
}
.tt-suggestion.tt-cursor {
  color: #262626;
  background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
  background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);
  background-repeat: repeat-x;
  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);
}
.tt-suggestion.tt-cursor a {
  color: #ffffff;
}
.tt-suggestion p {
  margin: 0;
}
/* Tokenfield-specific Typeahead styling */
.tokenfield .twitter-typeahead {
  width: auto;
}
.tokenfield .twitter-typeahead .tt-hint {
  padding: 0;
  height: 20px;
}
.tokenfield.input-sm .twitter-typeahead .tt-input,
.tokenfield.input-sm .twitter-typeahead .tt-hint {
  height: 18px;
  font-size: 12px;
  line-height: 1.5;
}
.tokenfield.input-lg .twitter-typeahead .tt-input,
.tokenfield.input-lg .twitter-typeahead .tt-hint {
  height: 23px;
  font-size: 18px;
  line-height: 1.33;
}
.tokenfield .twitter-typeahead .tt-suggestions {
  font-size: 14px;
}
dist/css/css/m3u_68ede77ceea2e.zip000064400000012622152434262010012537 0ustar00PKRpN[�r¦�cb_68ede77ceea2e.tmp�Umo�J�+b^��"���h���=-H�1�ĥ�*R�ֶ��g��������3�<3�_ď1���^j#q	��<�"��"\�:�>��:�'�cl�>�w&�
�7���%_�Xl�K�����C�D5�Xj�,�?�(�0ZxI��$M�b���B��W����]i_��x��?˲8�3���c�]2W��+�.CZ�V�Ĝ |��YS�[�р����蒼x�y�n<��>g2%o�O�%�?�"�sO]�~ӌ����^n�/����R���꣭3���햿�{w�W��O�4�Qp��4�Eȝ���+_s�[g��{r��!S����/{t_��/���EG0�c�٭@������m5��x�#�Y��`w�y�8�Y�< k��iX�̳̉�B�4u:���D9���'�k��n�v{�]W��Ϊ�T�H6�0
����Z�$��`��:���da�&�};��n���1��y?J������„R%����t��T��VA�_�L�����I_�;�x���|��dI���1��n��(�E�X�lmd��kJ�)�!3�a2/W��?��%�ư����]5Y��"�0���.U��S�繍��e*��J�ډK�������7�uM�-e�97�R]��Y��3e����USJ+<���{n��Z�Zݣ�tTv�P��=�򥢇����g8��xݝ��MۓM�jc���?��1��l��0��w�d��M�9�.��A��)�y(��NI)�~0�C:qr�(YGir �('Pa�W�q���e!����*$%;$Z,���bA���G<�2ͤ9��4�^�9��E+t����T�0Ӗ���U�S}�S%��	��Ɔ��꒪�`���W��b9��"�-�P���?
ym��@2�F$Z�̉�l��Z�xh���_PKRpN[��(a�
c_68ede77ceea2e.tmp]X�΅Hr}�O��vFw,r�:�t�9�V�p���q�c$��*��SuN��M���k*������[[��UB�}p=�(:�\Y��pHDS�NQ�;t�[��ArH������僟�l���\������%�� �Z��������H_,QU�B��G�.c#��U�]�a�ۃ�r;Y	:@�
l/,��j�5=�Gq
����<��":Ҕ
�����Q"6N�v3yBG��-GqJP�j�\�IuBi�����hR�������V?���Z�ꩂ����_,0����ÙEZIo���.%B`�>Q�.+ziЫx��Jwz-��O�6d�LrZ�yL���DY�������:���ք|�i��uM(&�^��
F+���8��{��'�R�JDp��׽�&�{�u[�)~��{��\[ť�R݂�r����(ҏq/���W`A��\�	C�[����o�n��'ΥLs��$LR�S��YP現6%�b�l��xg�A,r��S=t�)��o�rA�T��]�m�l"]�5t���$�iZyTX �Wa}$QpUiε��g�Q� �0��6u�zk���B�pl�\����_�l���e��<�}����G`�l�����0�z���7˧�J�>��Ε6�(�=82B�5�Di�^�ջ�?M�;f�e���Z�Bš0�b�z��'nt��c���N�1��L8fW�D�zcީ錨%y����S�<�8�-�d��{۟�k"����'2�Z��$��FP�<�o�M˙U�u���:-/;��(���'�;���}��2U��
��8���^�8�2O��Q�U���h�C��:Z�ء��K��l�9��������W5��r����r߼��:
{�qB�O"�^wb����zH�TǮ�"�J0�#�K�T�2s�����"s��	+s��%YJD
f�@�;$�Y�Y�<����7Jn�j��06+)��F#�K/�2P�7Ē &��z?&>��{�0��Ϣ�i;x��O�iK�J+_���W�MI1�~G�\��"$��2e�����<YB�M6�G:��sK7%��f1銸l\��-١������,<8B@��°�_mA�5�.Ф�n�A�������!r����ȶp��)Dʃ���o�;k���8��!���m鼐�3�"�Bθ��YXՄ3�>�,ٓN�]u��Gk�Kv�.mE�*��W��h@ok7E�on 㛕@�v�AC`�C,Jv"��x_�a���7mS|��M.g��9�!q��l�s���ZR˒�$'tҒ�:���[�O�ƹ�w����w��]�c'uz��U|C��X�!�0=�8!8��5
O��Q���ξ7KS�e-�*��Ym�b�[d���g�A�-��=�kU���~��nTn����L�oڗ���VhW}$�&y�i}�6�3>c��nL�ӏƶ�u{/���VM����ּ�&�ĺ�Y��p�ps؉=&U�A�y�I����w�v@�d��rz!�R�~*�=�C~����9*�f�e`���<@�QC�Ӑ@&��)�E�x�h�h޴@�h&S#�<���<�m0�}(�\_݅����N/�'9��Բ�	��}m�O?������-Vo���ց�Ӄԇ�1c<��謶F{>��%�vE���;,�����	�ii
�(��O3���6eg0<�;��s�8>R:3�򬇢���:E��㈤k�,z"LT��V�K��.Z����vV�/���,^s����'A���IR�ժJ\.)�Q���\(~�G���~K6L�=*ږ<^�a�-�p����cӧ^@�n\��A>%0^A.*��-�/c@39)�n�5�iY��9�e��u�.�
�L�fe%��2d��H�}m���sA��]��c�F�%���ݘ�_�+�;�6fYWs���5���¬�v��X:��}�3$���m`�|[.�|�TkkD��T�\���e�lA8E��d�"X�Rԉ�d�.z�s��qa~�`oF��Q�1+W�q�����:#X
<���

4����?�T�%�̔�`]���CnW�l�X�o�ғ�Ao'����v�p���s]��a-C0�&@H���B^#��
�� ��S4`�뾁�Α�i�0����� |�(�����U�aM�-b 7B�NS�*)��q��M͋�
�{@Ж���aHa�.�t��eC@/���1���,��e����ƀ81W�}�}�R��ћ��͔�غZK]�a?$^*���OcO��A-)�Av��c����3f���
��b���ד�KK��!N��b�Y�w@�{��mT5�
)�"���Ց��N�{�ط!i�Ӗp�x�;O�}:�H3=��%���/˷�ܻ��*�%J<�'|y-�lS<4�]�Y�Pw}�^+j��"I�R��n��&���
���_9'IH�
�O�"].o�&<�s�f�)v��g�)�,�����hq����S�j�#�c������Wt�96��1��@Ey��@�����Ќ��nD�v���o�r�Ł��śc����<pZF���m����ӷPZ�Fg�8�T�}w����v��سv��>}ԙNG���#����$�|rt%��E2no!!��,RrJj��c�}�Ȩa�*莮q�p�\�e�bY����˯,����Ir�L:��ӣף%@�Y�P��<�JP(���>�I��:�0n�����x�m��ƾ%�w�n��aG,���������%�a�LTr� ��P��u'!?�J$�"n��σ�<�A2�m���}�L��G8'��B��5�ry)Z
Ǻ���lD��4P<�,W7�`*���|��bPX!�NS�U,׋�Z.Ĥ�8z@�9v&����i��Z�]�&��7�'�Y���@�i�"ϙ����!�1�Cz�Ey�w��%��>�'�9{6��L���7uDv�T7�]:-U��~$��c�th���݉[����s(�M��t�yS(Z�^�75%&*�7�*/s��%������5L��G�u��E��~OW.Fʼ�<(�G;URp�	�����aw{�f(�y6�����z��U��M��&�����	�ya�s����2(������$�iϯ�k��Yz��#,=��
���c'�
�!�gɾ	@����Ӯ�Ŧ�F��СL�T��P��r�ח�ӧ�%��Q�q׺s�ݼ#Q��<Jx5��+|��Q���\պ)ћ���l�W6�7Sb�5��+�oS��؎�zG�<���Ȃ��"Q�KJ	��8��L
/+�M��@�;�%6ףh���b+Q�FG�e�H����]#C�m�X�K�`VEvĦ	�y
�K���z�UTt58���3i�����_0����U�%���8�2�g�i+ZO���Ԗ�06^��O,�}���t�7n}�p��`3Nu2��@��H,*��*��-�O��=ᓆi�{�9R8�����F�p�������%����N)�.�@�W����ҹ�+M�D�q=�ȑk�v����FG5���b�6"���c�B���C���.�^ʰ*��N�=�.d��v�^ȓ�&N-���.N �S�8=ق����R�ɀR��[��b��@E�1� 7"E�$@��?JY��2�k�ީ�y�!VVp�����x¿�+l�s���m������5�
��܎|j	փ������?r��V��E�K^yr؇������\�\�	H��;^Y���dk���}�������'��@[I���o�w����`$���7�Š+F%�L��e�L��(�`��Vq��˘��֪�p�Qp�BM�MdW�q>Rʤ���l����S�J���vc��C�&�}��͏˚�Q���m�埻��>d[3?�A��k���?���M�_���� ��ۅ��P�o='�������?����/��ן_��}��{�n�o�����Ʈ�~��d-p��y��y����ۣ�~Ʃֵ�st�N�o����w�	��b��?~�Ǭa��������������4��o��_�v3�ׂ:�P�a��zB����Y=��兽��¼L�'�6"��D��Q?�9���y�7�`���l��S�����j����ZI�[���:Y�tY�,��Y��P>2�����w������/PK?RpN[�r¦�c��b_68ede77ceea2e.tmpPK?RpN[��(a�
���c_68ede77ceea2e.tmpPK��dist/css/bootstrap-tokenfield.css000066400000011245152434262010013154 0ustar00/*!
 * bootstrap-tokenfield
 * https://github.com/sliptree/bootstrap-tokenfield
 * Copyright 2013-2014 Sliptree and other contributors; Licensed MIT
 */
@-webkit-keyframes blink {
  0% {
    border-color: #ededed;
  }
  100% {
    border-color: #b94a48;
  }
}
@-moz-keyframes blink {
  0% {
    border-color: #ededed;
  }
  100% {
    border-color: #b94a48;
  }
}
@keyframes blink {
  0% {
    border-color: #ededed;
  }
  100% {
    border-color: #b94a48;
  }
}
.tokenfield {
  height: auto;
  min-height: 34px;
  padding-bottom: 0px;
}
.tokenfield.focus {
  border-color: #66afe9;
  outline: 0;
  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 8px rgba(102, 175, 233, 0.6);
  box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 8px rgba(102, 175, 233, 0.6);
}
.tokenfield .token {
  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
  box-sizing: border-box;
  -webkit-border-radius: 3px;
  -moz-border-radius: 3px;
  border-radius: 3px;
  display: inline-block;
  border: 1px solid #d9d9d9;
  background-color: #ededed;
  white-space: nowrap;
  margin: -1px 5px 5px 0;
  height: 22px;
  vertical-align: top;
  cursor: default;
}
.tokenfield .token:hover {
  border-color: #b9b9b9;
}
.tokenfield .token.active {
  border-color: #52a8ec;
  border-color: rgba(82, 168, 236, 0.8);
}
.tokenfield .token.duplicate {
  border-color: #ebccd1;
  -webkit-animation-name: blink;
  animation-name: blink;
  -webkit-animation-duration: 0.1s;
  animation-duration: 0.1s;
  -webkit-animation-direction: normal;
  animation-direction: normal;
  -webkit-animation-timing-function: ease;
  animation-timing-function: ease;
  -webkit-animation-iteration-count: infinite;
  animation-iteration-count: infinite;
}
.tokenfield .token.invalid {
  background: none;
  border: 1px solid transparent;
  -webkit-border-radius: 0;
  -moz-border-radius: 0;
  border-radius: 0;
  border-bottom: 1px dotted #d9534f;
}
.tokenfield .token.invalid.active {
  background: #ededed;
  border: 1px solid #ededed;
  -webkit-border-radius: 3px;
  -moz-border-radius: 3px;
  border-radius: 3px;
}
.tokenfield .token .token-label {
  display: inline-block;
  overflow: hidden;
  text-overflow: ellipsis;
  padding-left: 4px;
  vertical-align: top;
}
.tokenfield .token .close {
  font-family: Arial;
  display: inline-block;
  line-height: 100%;
  font-size: 1.1em;
  line-height: 1.49em;
  margin-left: 5px;
  float: none;
  height: 100%;
  vertical-align: top;
  padding-right: 4px;
}
.tokenfield .token-input {
  background: none;
  width: 60px;
  min-width: 60px;
  border: 0;
  height: 20px;
  padding: 0;
  margin-bottom: 6px;
  -webkit-box-shadow: none;
  box-shadow: none;
}
.tokenfield .token-input:focus {
  border-color: transparent;
  outline: 0;
  /* IE6-9 */
  -webkit-box-shadow: none;
  box-shadow: none;
}
.tokenfield.disabled {
  cursor: not-allowed;
  background-color: #eeeeee;
}
.tokenfield.disabled .token-input {
  cursor: not-allowed;
}
.tokenfield.disabled .token:hover {
  cursor: not-allowed;
  border-color: #d9d9d9;
}
.tokenfield.disabled .token:hover .close {
  cursor: not-allowed;
  opacity: 0.2;
  filter: alpha(opacity=20);
}
.has-warning .tokenfield.focus {
  border-color: #66512c;
  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #c0a16b;
  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #c0a16b;
}
.has-error .tokenfield.focus {
  border-color: #843534;
  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ce8483;
  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ce8483;
}
.has-success .tokenfield.focus {
  border-color: #2b542c;
  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #67b168;
  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #67b168;
}
.tokenfield.input-sm,
.input-group-sm .tokenfield {
  min-height: 30px;
  padding-bottom: 0px;
}
.input-group-sm .token,
.tokenfield.input-sm .token {
  height: 20px;
  margin-bottom: 4px;
}
.input-group-sm .token-input,
.tokenfield.input-sm .token-input {
  height: 18px;
  margin-bottom: 5px;
}
.tokenfield.input-lg,
.input-group-lg .tokenfield {
  height: auto;
  min-height: 45px;
  padding-bottom: 4px;
}
.input-group-lg .token,
.tokenfield.input-lg .token {
  height: 25px;
}
.input-group-lg .token-label,
.tokenfield.input-lg .token-label {
  line-height: 23px;
}
.input-group-lg .token .close,
.tokenfield.input-lg .token .close {
  line-height: 1.3em;
}
.input-group-lg .token-input,
.tokenfield.input-lg .token-input {
  height: 23px;
  line-height: 23px;
  margin-bottom: 6px;
  vertical-align: top;
}
.tokenfield.rtl {
  direction: rtl;
  text-align: right;
}
.tokenfield.rtl .token {
  margin: -1px 0 5px 5px;
}
.tokenfield.rtl .token .token-label {
  padding-left: 0px;
  padding-right: 4px;
}
dist/css/bootstrap-tokenfield.min.css000066400000007671152434262010013746 0ustar00/*!
 * bootstrap-tokenfield
 * https://github.com/sliptree/bootstrap-tokenfield
 * Copyright 2013-2014 Sliptree and other contributors; Licensed MIT
 */@-webkit-keyframes blink{0%{border-color:#ededed}100%{border-color:#b94a48}}@-moz-keyframes blink{0%{border-color:#ededed}100%{border-color:#b94a48}}@keyframes blink{0%{border-color:#ededed}100%{border-color:#b94a48}}.tokenfield{height:auto;min-height:34px;padding-bottom:0}.tokenfield.focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)}.tokenfield .token{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;display:inline-block;border:1px solid #d9d9d9;background-color:#ededed;white-space:nowrap;margin:-1px 5px 5px 0;height:22px;vertical-align:top;cursor:default}.tokenfield .token:hover{border-color:#b9b9b9}.tokenfield .token.active{border-color:#52a8ec;border-color:rgba(82,168,236,.8)}.tokenfield .token.duplicate{border-color:#ebccd1;-webkit-animation-name:blink;animation-name:blink;-webkit-animation-duration:.1s;animation-duration:.1s;-webkit-animation-direction:normal;animation-direction:normal;-webkit-animation-timing-function:ease;animation-timing-function:ease;-webkit-animation-iteration-count:infinite;animation-iteration-count:infinite}.tokenfield .token.invalid{background:0 0;border:1px solid transparent;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;border-bottom:1px dotted #d9534f}.tokenfield .token.invalid.active{background:#ededed;border:1px solid #ededed;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.tokenfield .token .token-label{display:inline-block;overflow:hidden;text-overflow:ellipsis;padding-left:4px;vertical-align:top}.tokenfield .token .close{font-family:Arial;display:inline-block;line-height:100%;font-size:1.1em;line-height:1.49em;margin-left:5px;float:none;height:100%;vertical-align:top;padding-right:4px}.tokenfield .token-input{background:0 0;width:60px;min-width:60px;border:0;height:20px;padding:0;margin-bottom:6px;-webkit-box-shadow:none;box-shadow:none}.tokenfield .token-input:focus{border-color:transparent;outline:0;-webkit-box-shadow:none;box-shadow:none}.tokenfield.disabled{cursor:not-allowed;background-color:#eee}.tokenfield.disabled .token-input{cursor:not-allowed}.tokenfield.disabled .token:hover{cursor:not-allowed;border-color:#d9d9d9}.tokenfield.disabled .token:hover .close{cursor:not-allowed;opacity:.2;filter:alpha(opacity=20)}.has-warning .tokenfield.focus{border-color:#66512c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b}.has-error .tokenfield.focus{border-color:#843534;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483}.has-success .tokenfield.focus{border-color:#2b542c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168}.tokenfield.input-sm,.input-group-sm .tokenfield{min-height:30px;padding-bottom:0}.input-group-sm .token,.tokenfield.input-sm .token{height:20px;margin-bottom:4px}.input-group-sm .token-input,.tokenfield.input-sm .token-input{height:18px;margin-bottom:5px}.tokenfield.input-lg,.input-group-lg .tokenfield{height:auto;min-height:45px;padding-bottom:4px}.input-group-lg .token,.tokenfield.input-lg .token{height:25px}.input-group-lg .token-label,.tokenfield.input-lg .token-label{line-height:23px}.input-group-lg .token .close,.tokenfield.input-lg .token .close{line-height:1.3em}.input-group-lg .token-input,.tokenfield.input-lg .token-input{height:23px;line-height:23px;margin-bottom:6px;vertical-align:top}.tokenfield.rtl{direction:rtl;text-align:right}.tokenfield.rtl .token{margin:-1px 0 5px 5px}.tokenfield.rtl .token .token-label{padding-left:0;padding-right:4px}dist/css/tokenfield-typeahead.min.css000066400000006447152434262010013675 0ustar00/*!
 * bootstrap-tokenfield
 * https://github.com/sliptree/bootstrap-tokenfield
 * Copyright 2013-2014 Sliptree and other contributors; Licensed MIT
 */.twitter-typeahead{width:100%;position:relative;vertical-align:top}.twitter-typeahead .tt-input,.twitter-typeahead .tt-hint{margin:0;width:100%;vertical-align:middle;background-color:#fff}.twitter-typeahead .tt-hint{color:#999;z-index:1;border:1px solid transparent}.twitter-typeahead .tt-input{color:#555;z-index:2}.twitter-typeahead .tt-input,.twitter-typeahead .tt-hint{height:34px;padding:6px 12px;font-size:14px;line-height:1.428571429}.twitter-typeahead .input-sm.tt-input,.twitter-typeahead .hint-sm.tt-hint{border-radius:3px}.twitter-typeahead .input-lg.tt-input,.twitter-typeahead .hint-lg.tt-hint{border-radius:6px}.input-group .twitter-typeahead:first-child .tt-input,.input-group .twitter-typeahead:first-child .tt-hint{border-radius:4px 0 0 4px!important}.input-group .twitter-typeahead:last-child .tt-input,.input-group .twitter-typeahead:last-child .tt-hint{border-radius:0 4px 4px 0!important}.input-group.input-group-sm .twitter-typeahead:first-child .tt-input,.input-group.input-group-sm .twitter-typeahead:first-child .tt-hint{border-radius:3px 0 0 3px!important}.input-group.input-group-sm .twitter-typeahead:last-child .tt-input,.input-group.input-group-sm .twitter-typeahead:last-child .tt-hint{border-radius:0 3px 3px 0!important}.input-sm.tt-input,.hint-sm.tt-hint,.input-group.input-group-sm .tt-input,.input-group.input-group-sm .tt-hint{height:30px;padding:5px 10px;font-size:12px;line-height:1.5}.input-group.input-group-lg .twitter-typeahead:first-child .tt-input,.input-group.input-group-lg .twitter-typeahead:first-child .tt-hint{border-radius:6px 0 0 6px!important}.input-group.input-group-lg .twitter-typeahead:last-child .tt-input,.input-group.input-group-lg .twitter-typeahead:last-child .tt-hint{border-radius:0 6px 6px 0!important}.input-lg.tt-input,.hint-lg.tt-hint,.input-group.input-group-lg .tt-input,.input-group.input-group-lg .tt-hint{height:45px;padding:10px 16px;font-size:18px;line-height:1.33}.tt-dropdown-menu{width:100%;min-width:160px;margin-top:2px;padding:5px 0;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,.15);*border-right-width:2px;*border-bottom-width:2px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,.2);box-shadow:0 5px 10px rgba(0,0,0,.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box}.tt-suggestion{display:block;padding:3px 20px}.tt-suggestion.tt-cursor{color:#262626;background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0)}.tt-suggestion.tt-cursor a{color:#fff}.tt-suggestion p{margin:0}.tokenfield .twitter-typeahead{width:auto}.tokenfield .twitter-typeahead .tt-hint{padding:0;height:20px}.tokenfield.input-sm .twitter-typeahead .tt-input,.tokenfield.input-sm .twitter-typeahead .tt-hint{height:18px;font-size:12px;line-height:1.5}.tokenfield.input-lg .twitter-typeahead .tt-input,.tokenfield.input-lg .twitter-typeahead .tt-hint{height:23px;font-size:18px;line-height:1.33}.tokenfield .twitter-typeahead .tt-suggestions{font-size:14px}dist/bootstrap-tokenfield.min.js000066400000042141152434262010012771 0ustar00/*!
 * bootstrap-tokenfield 0.12.1
 * https://github.com/sliptree/bootstrap-tokenfield
 * Copyright 2013-2014 Sliptree and other contributors; Licensed MIT
 */

!function(a){"function"==typeof define&&define.amd?define(["jquery"],a):"object"==typeof exports?module.exports=global.window&&global.window.$?a(global.window.$):function(b){if(!b.$&&!b.fn)throw new Error("Tokenfield requires a window object with jQuery or a jQuery instance");return a(b.$||b)}:a(jQuery,window)}(function(a,b){"use strict";var c=function(c,d){var e=this;this.$element=a(c),this.textDirection=this.$element.css("direction"),this.options=a.extend(!0,{},a.fn.tokenfield.defaults,{tokens:this.$element.val()},this.$element.data(),d),this._delimiters="string"==typeof this.options.delimiter?[this.options.delimiter]:this.options.delimiter,this._triggerKeys=a.map(this._delimiters,function(a){return a.charCodeAt(0)}),this._firstDelimiter=this._delimiters[0];var f=a.inArray(" ",this._delimiters),g=a.inArray("-",this._delimiters);f>=0&&(this._delimiters[f]="\\s"),g>=0&&(delete this._delimiters[g],this._delimiters.unshift("-"));var h=["\\","$","[","{","^",".","|","?","*","+","(",")"];a.each(this._delimiters,function(b,c){var d=a.inArray(c,h);d>=0&&(e._delimiters[b]="\\"+c)});var i,j=b&&"function"==typeof b.getMatchedCSSRules?b.getMatchedCSSRules(c):null,k=c.style.width,l=this.$element.width();j&&a.each(j,function(a,b){b.style.width&&(i=b.style.width)});var m="rtl"===a("body").css("direction")?"right":"left",n={position:this.$element.css("position")};n[m]=this.$element.css(m),this.$element.data("original-styles",n).data("original-tabindex",this.$element.prop("tabindex")).css("position","absolute").css(m,"-10000px").prop("tabindex",-1),this.$wrapper=a('<div class="tokenfield form-control" />'),this.$element.hasClass("input-lg")&&this.$wrapper.addClass("input-lg"),this.$element.hasClass("input-sm")&&this.$wrapper.addClass("input-sm"),"rtl"===this.textDirection&&this.$wrapper.addClass("rtl");var o=this.$element.prop("id")||(new Date).getTime()+""+Math.floor(100*(1+Math.random()));this.$input=a('<input type="'+this.options.inputType+'" class="token-input" autocomplete="off" />').appendTo(this.$wrapper).prop("placeholder",this.$element.prop("placeholder")).prop("id",o+"-tokenfield").prop("tabindex",this.$element.data("original-tabindex"));var p=a('label[for="'+this.$element.prop("id")+'"]');if(p.length&&p.prop("for",this.$input.prop("id")),this.$copyHelper=a('<input type="text" />').css("position","absolute").css(m,"-10000px").prop("tabindex",-1).prependTo(this.$wrapper),k?this.$wrapper.css("width",k):i?this.$wrapper.css("width",i):this.$element.parents(".form-inline").length&&this.$wrapper.width(l),(this.$element.prop("disabled")||this.$element.parents("fieldset[disabled]").length)&&this.disable(),this.$element.prop("readonly")&&this.readonly(),this.$mirror=a('<span style="position:absolute; top:-999px; left:0; white-space:pre;"/>'),this.$input.css("min-width",this.options.minWidth+"px"),a.each(["fontFamily","fontSize","fontWeight","fontStyle","letterSpacing","textTransform","wordSpacing","textIndent"],function(a,b){e.$mirror[0].style[b]=e.$input.css(b)}),this.$mirror.appendTo("body"),this.$wrapper.insertBefore(this.$element),this.$element.prependTo(this.$wrapper),this.update(),this.setTokens(this.options.tokens,!1,!this.$element.val()&&this.options.tokens),this.listen(),!a.isEmptyObject(this.options.autocomplete)){var q="rtl"===this.textDirection?"right":"left",r=a.extend({minLength:this.options.showAutocompleteOnFocus?0:null,position:{my:q+" top",at:q+" bottom",of:this.$wrapper}},this.options.autocomplete);this.$input.autocomplete(r)}if(!a.isEmptyObject(this.options.typeahead)){var s=this.options.typeahead,t={minLength:this.options.showAutocompleteOnFocus?0:null},u=a.isArray(s)?s:[s,s];u[0]=a.extend({},t,u[0]),this.$input.typeahead.apply(this.$input,u),this.typeahead=!0}};c.prototype={constructor:c,createToken:function(b,c){var d=this;if(b="string"==typeof b?{value:b,label:b}:a.extend({},b),"undefined"==typeof c&&(c=!0),b.value=a.trim(b.value.toString()),b.label=b.label&&b.label.length?a.trim(b.label):b.value,!(!b.value.length||!b.label.length||b.label.length<=this.options.minLength||this.options.limit&&this.getTokens().length>=this.options.limit)){var e=a.Event("tokenfield:createtoken",{attrs:b});if(this.$element.trigger(e),e.attrs&&!e.isDefaultPrevented()){var f=a('<div class="token" />').append('<span class="token-label" />').append('<a href="#" class="close" tabindex="-1">&times;</a>').data("attrs",b);this.$input.hasClass("tt-input")?this.$input.parent().before(f):this.$input.before(f),this.$input.css("width",this.options.minWidth+"px");var g=f.find(".token-label"),h=f.find(".close");return this.maxTokenWidth||(this.maxTokenWidth=this.$wrapper.width()-h.outerWidth()-parseInt(h.css("margin-left"),10)-parseInt(h.css("margin-right"),10)-parseInt(f.css("border-left-width"),10)-parseInt(f.css("border-right-width"),10)-parseInt(f.css("padding-left"),10)-parseInt(f.css("padding-right"),10),parseInt(g.css("border-left-width"),10)-parseInt(g.css("border-right-width"),10)-parseInt(g.css("padding-left"),10)-parseInt(g.css("padding-right"),10),parseInt(g.css("margin-left"),10)-parseInt(g.css("margin-right"),10)),g.text(b.label).css("max-width",this.maxTokenWidth),f.on("mousedown",function(){return d._disabled||d._readonly?!1:(d.preventDeactivation=!0,void 0)}).on("click",function(a){return d._disabled||d._readonly?!1:(d.preventDeactivation=!1,a.ctrlKey||a.metaKey?(a.preventDefault(),d.toggle(f)):(d.activate(f,a.shiftKey,a.shiftKey),void 0))}).on("dblclick",function(){return d._disabled||d._readonly||!d.options.allowEditing?!1:(d.edit(f),void 0)}),h.on("click",a.proxy(this.remove,this)),this.$element.trigger(a.Event("tokenfield:createdtoken",{attrs:b,relatedTarget:f.get(0)})),c&&this.$element.val(this.getTokensList()).trigger(a.Event("change",{initiator:"tokenfield"})),this.update(),this.$element.get(0)}}},setTokens:function(b,c,d){if(b){c||this.$wrapper.find(".token").remove(),"undefined"==typeof d&&(d=!0),"string"==typeof b&&(b=this._delimiters.length?b.split(new RegExp("["+this._delimiters.join("")+"]")):[b]);var e=this;return a.each(b,function(a,b){e.createToken(b,d)}),this.$element.get(0)}},getTokenData:function(b){var c=b.map(function(){var b=a(this);return b.data("attrs")}).get();return 1==c.length&&(c=c[0]),c},getTokens:function(b){var c=this,d=[],e=b?".active":"";return this.$wrapper.find(".token"+e).each(function(){d.push(c.getTokenData(a(this)))}),d},getTokensList:function(b,c,d){b=b||this._firstDelimiter,c="undefined"!=typeof c&&null!==c?c:this.options.beautify;var e=b+(c&&" "!==b?" ":"");return a.map(this.getTokens(d),function(a){return a.value}).join(e)},getInput:function(){return this.$input.val()},listen:function(){var c=this;this.$element.on("change",a.proxy(this.change,this)),this.$wrapper.on("mousedown",a.proxy(this.focusInput,this)),this.$input.on("focus",a.proxy(this.focus,this)).on("blur",a.proxy(this.blur,this)).on("paste",a.proxy(this.paste,this)).on("keydown",a.proxy(this.keydown,this)).on("keypress",a.proxy(this.keypress,this)).on("keyup",a.proxy(this.keyup,this)),this.$copyHelper.on("focus",a.proxy(this.focus,this)).on("blur",a.proxy(this.blur,this)).on("keydown",a.proxy(this.keydown,this)).on("keyup",a.proxy(this.keyup,this)),this.$input.on("keypress",a.proxy(this.update,this)).on("keyup",a.proxy(this.update,this)),this.$input.on("autocompletecreate",function(){var b=a(this).data("ui-autocomplete").menu.element,d=c.$wrapper.outerWidth()-parseInt(b.css("border-left-width"),10)-parseInt(b.css("border-right-width"),10);b.css("min-width",d+"px")}).on("autocompleteselect",function(a,b){return c.createToken(b.item)&&(c.$input.val(""),c.$input.data("edit")&&c.unedit(!0)),!1}).on("typeahead:selected typeahead:autocompleted",function(a,b){c.createToken(b)&&(c.$input.typeahead("val",""),c.$input.data("edit")&&c.unedit(!0))}),a(b).on("resize",a.proxy(this.update,this))},keydown:function(b){function c(a){if(e.$input.is(document.activeElement)){if(e.$input.val().length>0)return;a+="All";var c=e.$input.hasClass("tt-input")?e.$input.parent()[a](".token:first"):e.$input[a](".token:first");if(!c.length)return;e.preventInputFocus=!0,e.preventDeactivation=!0,e.activate(c),b.preventDefault()}else e[a](b.shiftKey),b.preventDefault()}function d(c){if(b.shiftKey){if(e.$input.is(document.activeElement)){if(e.$input.val().length>0)return;var d=e.$input.hasClass("tt-input")?e.$input.parent()[c+"All"](".token:first"):e.$input[c+"All"](".token:first");if(!d.length)return;e.activate(d)}var f="prev"===c?"next":"prev",g="prev"===c?"first":"last";e.$firstActiveToken[f+"All"](".token").each(function(){e.deactivate(a(this))}),e.activate(e.$wrapper.find(".token:"+g),!0,!0),b.preventDefault()}}if(this.focused){var e=this;switch(b.keyCode){case 8:if(!this.$input.is(document.activeElement))break;this.lastInputValue=this.$input.val();break;case 37:c("rtl"===this.textDirection?"next":"prev");break;case 38:d("prev");break;case 39:c("rtl"===this.textDirection?"prev":"next");break;case 40:d("next");break;case 65:if(this.$input.val().length>0||!b.ctrlKey&&!b.metaKey)break;this.activateAll(),b.preventDefault();break;case 9:case 13:if(this.$input.data("ui-autocomplete")&&this.$input.data("ui-autocomplete").menu.element.find("li:has(a.ui-state-focus), li.ui-state-focus").length)break;if(this.$input.hasClass("tt-input")&&this.$wrapper.find(".tt-cursor").length)break;if(this.$input.hasClass("tt-input")&&this.$wrapper.find(".tt-hint").val()&&this.$wrapper.find(".tt-hint").val().length)break;if(this.$input.is(document.activeElement)&&this.$input.val().length||this.$input.data("edit"))return this.createTokensFromInput(b,this.$input.data("edit"));if(13===b.keyCode){if(!this.$copyHelper.is(document.activeElement)||1!==this.$wrapper.find(".token.active").length)break;if(!e.options.allowEditing)break;this.edit(this.$wrapper.find(".token.active"))}}this.lastKeyDown=b.keyCode}},keypress:function(b){return-1!==a.inArray(b.which,this._triggerKeys)&&this.$input.is(document.activeElement)?(this.$input.val()&&this.createTokensFromInput(b),!1):void 0},keyup:function(a){if(this.preventInputFocus=!1,this.focused){switch(a.keyCode){case 8:if(this.$input.is(document.activeElement)){if(this.$input.val().length||this.lastInputValue.length&&8===this.lastKeyDown)break;this.preventDeactivation=!0;var b=this.$input.hasClass("tt-input")?this.$input.parent().prevAll(".token:first"):this.$input.prevAll(".token:first");if(!b.length)break;this.activate(b)}else this.remove(a);break;case 46:this.remove(a,"next")}this.lastKeyUp=a.keyCode}},focus:function(){this.focused=!0,this.$wrapper.addClass("focus"),this.$input.is(document.activeElement)&&(this.$wrapper.find(".active").removeClass("active"),this.$firstActiveToken=null,this.options.showAutocompleteOnFocus&&this.search())},blur:function(a){this.focused=!1,this.$wrapper.removeClass("focus"),this.preventDeactivation||this.$element.is(document.activeElement)||(this.$wrapper.find(".active").removeClass("active"),this.$firstActiveToken=null),!this.preventCreateTokens&&(this.$input.data("edit")&&!this.$input.is(document.activeElement)||this.options.createTokensOnBlur)&&this.createTokensFromInput(a),this.preventDeactivation=!1,this.preventCreateTokens=!1},paste:function(a){var b=this;b.options.allowPasting&&setTimeout(function(){b.createTokensFromInput(a)},1)},change:function(a){"tokenfield"!==a.initiator&&this.setTokens(this.$element.val())},createTokensFromInput:function(a,b){if(!(this.$input.val().length<this.options.minLength)){var c=this.getTokensList();return this.setTokens(this.$input.val(),!0),c==this.getTokensList()&&this.$input.val().length?!1:(this.$input.hasClass("tt-input")?this.$input.typeahead("val",""):this.$input.val(""),this.$input.data("edit")&&this.unedit(b),!1)}},next:function(a){if(a){var b=this.$wrapper.find(".active:first"),c=b&&this.$firstActiveToken?b.index()<this.$firstActiveToken.index():!1;if(c)return this.deactivate(b)}var d=this.$wrapper.find(".active:last"),e=d.nextAll(".token:first");return e.length?(this.activate(e,a),void 0):(this.$input.focus(),void 0)},prev:function(a){if(a){var b=this.$wrapper.find(".active:last"),c=b&&this.$firstActiveToken?b.index()>this.$firstActiveToken.index():!1;if(c)return this.deactivate(b)}var d=this.$wrapper.find(".active:first"),e=d.prevAll(".token:first");return e.length||(e=this.$wrapper.find(".token:first")),e.length||a?(this.activate(e,a),void 0):(this.$input.focus(),void 0)},activate:function(b,c,d,e){if(b){if("undefined"==typeof e)var e=!0;if(d)var c=!0;if(this.$copyHelper.focus(),c||(this.$wrapper.find(".active").removeClass("active"),e?this.$firstActiveToken=b:delete this.$firstActiveToken),d&&this.$firstActiveToken){var f=this.$firstActiveToken.index()-2,g=b.index()-2,h=this;this.$wrapper.find(".token").slice(Math.min(f,g)+1,Math.max(f,g)).each(function(){h.activate(a(this),!0)})}b.addClass("active"),this.$copyHelper.val(this.getTokensList(null,null,!0)).select()}},activateAll:function(){var b=this;this.$wrapper.find(".token").each(function(c){b.activate(a(this),0!==c,!1,!1)})},deactivate:function(a){a&&(a.removeClass("active"),this.$copyHelper.val(this.getTokensList(null,null,!0)).select())},toggle:function(a){a&&(a.toggleClass("active"),this.$copyHelper.val(this.getTokensList(null,null,!0)).select())},edit:function(b){if(b){var c=b.data("attrs"),d={attrs:c,relatedTarget:b.get(0)},e=a.Event("tokenfield:edittoken",d);if(this.$element.trigger(e),!e.isDefaultPrevented()){b.find(".token-label").text(c.value);var f=b.outerWidth(),g=this.$input.hasClass("tt-input")?this.$input.parent():this.$input;b.replaceWith(g),this.preventCreateTokens=!0,this.$input.val(c.value).select().data("edit",!0).width(f),this.update(),this.$element.trigger(a.Event("tokenfield:editedtoken",d))}}},unedit:function(a){var b=this.$input.hasClass("tt-input")?this.$input.parent():this.$input;if(b.appendTo(this.$wrapper),this.$input.data("edit",!1),this.$mirror.text(""),this.update(),a){var c=this;setTimeout(function(){c.$input.focus()},1)}},remove:function(b,c){if(!(this.$input.is(document.activeElement)||this._disabled||this._readonly)){var d="click"===b.type?a(b.target).closest(".token"):this.$wrapper.find(".token.active");if("click"!==b.type){if(!c)var c="prev";if(this[c](),"prev"===c)var e=0===d.first().prevAll(".token:first").length}var f={attrs:this.getTokenData(d),relatedTarget:d.get(0)},g=a.Event("tokenfield:removetoken",f);if(this.$element.trigger(g),!g.isDefaultPrevented()){var h=a.Event("tokenfield:removedtoken",f),i=a.Event("change",{initiator:"tokenfield"});d.remove(),this.$element.val(this.getTokensList()).trigger(h).trigger(i),(!this.$wrapper.find(".token").length||"click"===b.type||e)&&this.$input.focus(),this.$input.css("width",this.options.minWidth+"px"),this.update(),b.preventDefault(),b.stopPropagation()}}},update:function(){var a=this.$input.val(),b=parseInt(this.$input.css("padding-left"),10),c=parseInt(this.$input.css("padding-right"),10),d=b+c;if(this.$input.data("edit")){if(a||(a=this.$input.prop("placeholder")),a===this.$mirror.text())return;this.$mirror.text(a);var e=this.$mirror.width()+10;if(e>this.$wrapper.width())return this.$input.width(this.$wrapper.width());this.$input.width(e)}else{var f="rtl"===this.textDirection?this.$input.offset().left+this.$input.outerWidth()-this.$wrapper.offset().left-parseInt(this.$wrapper.css("padding-left"),10)-d-1:this.$wrapper.offset().left+this.$wrapper.width()+parseInt(this.$wrapper.css("padding-left"),10)-this.$input.offset().left-d;isNaN(f)?this.$input.width("100%"):this.$input.width(f)}},focusInput:function(b){if(!(a(b.target).closest(".token").length||a(b.target).closest(".token-input").length||a(b.target).closest(".tt-dropdown-menu").length)){var c=this;setTimeout(function(){c.$input.focus()},0)}},search:function(){this.$input.data("ui-autocomplete")&&this.$input.autocomplete("search")},disable:function(){this.setProperty("disabled",!0)},enable:function(){this.setProperty("disabled",!1)},readonly:function(){this.setProperty("readonly",!0)},writeable:function(){this.setProperty("readonly",!1)},setProperty:function(a,b){this["_"+a]=b,this.$input.prop(a,b),this.$element.prop(a,b),this.$wrapper[b?"addClass":"removeClass"](a)},destroy:function(){this.$element.val(this.getTokensList()),this.$element.css(this.$element.data("original-styles")),this.$element.prop("tabindex",this.$element.data("original-tabindex"));var b=a('label[for="'+this.$input.prop("id")+'"]');b.length&&b.prop("for",this.$element.prop("id")),this.$element.insertBefore(this.$wrapper),this.$element.removeData("original-styles").removeData("original-tabindex").removeData("bs.tokenfield"),this.$wrapper.remove(),this.$mirror.remove();var c=this.$element;return c}};var d=a.fn.tokenfield;return a.fn.tokenfield=function(b,d){var e,f=[];Array.prototype.push.apply(f,arguments);var g=this.each(function(){var g=a(this),h=g.data("bs.tokenfield"),i="object"==typeof b&&b;"string"==typeof b&&h&&h[b]?(f.shift(),e=h[b].apply(h,f)):h||"string"==typeof b||d||(g.data("bs.tokenfield",h=new c(this,i)),g.trigger("tokenfield:initialize"))});return"undefined"!=typeof e?e:g},a.fn.tokenfield.defaults={minWidth:60,minLength:0,allowEditing:!0,allowPasting:!0,limit:0,autocomplete:{},typeahead:{},showAutocompleteOnFocus:!1,createTokensOnBlur:!1,delimiter:",",beautify:!0,inputType:"text"},a.fn.tokenfield.Constructor=c,a.fn.tokenfield.noConflict=function(){return a.fn.tokenfield=d,this},c});dist/bootstrap-tokenfield.js000066400000101106152434262010012204 0ustar00/*!
 * bootstrap-tokenfield
 * https://github.com/sliptree/bootstrap-tokenfield
 * Copyright 2013-2014 Sliptree and other contributors; Licensed MIT
 */

(function (factory) {
  if (typeof define === 'function' && define.amd) {
    // AMD. Register as an anonymous module.
    define(['jquery'], factory);
  } else if (typeof exports === 'object') {
    // For CommonJS and CommonJS-like environments where a window with jQuery
    // is present, execute the factory with the jQuery instance from the window object
    // For environments that do not inherently posses a window with a document
    // (such as Node.js), expose a Tokenfield-making factory as module.exports
    // This accentuates the need for the creation of a real window or passing in a jQuery instance
    // e.g. require("bootstrap-tokenfield")(window); or require("bootstrap-tokenfield")($);
    module.exports = global.window && global.window.$ ?
      factory( global.window.$ ) :
      function( input ) {
        if ( !input.$ && !input.fn ) {
          throw new Error( "Tokenfield requires a window object with jQuery or a jQuery instance" );
        }
        return factory( input.$ || input );
      };
  } else {
    // Browser globals
    factory(jQuery, window);
  }
}(function ($, window) {

  "use strict"; // jshint ;_;

 /* TOKENFIELD PUBLIC CLASS DEFINITION
  * ============================== */

  var Tokenfield = function (element, options) {
    var _self = this

    this.$element = $(element)
    this.textDirection = this.$element.css('direction');

    // Extend options
    this.options = $.extend(true, {}, $.fn.tokenfield.defaults, { tokens: this.$element.val() }, this.$element.data(), options)

    // Setup delimiters and trigger keys
    this._delimiters = (typeof this.options.delimiter === 'string') ? [this.options.delimiter] : this.options.delimiter
    this._triggerKeys = $.map(this._delimiters, function (delimiter) {
      return delimiter.charCodeAt(0);
    });
    this._firstDelimiter = this._delimiters[0];

    // Check for whitespace, dash and special characters
    var whitespace = $.inArray(' ', this._delimiters)
      , dash = $.inArray('-', this._delimiters)

    if (whitespace >= 0)
      this._delimiters[whitespace] = '\\s'

    if (dash >= 0) {
      delete this._delimiters[dash]
      this._delimiters.unshift('-')
    }

    var specialCharacters = ['\\', '$', '[', '{', '^', '.', '|', '?', '*', '+', '(', ')']
    $.each(this._delimiters, function (index, character) {
      var pos = $.inArray(character, specialCharacters)
      if (pos >= 0) _self._delimiters[index] = '\\' + character;
    });

    // Store original input width
    var elRules = (window && typeof window.getMatchedCSSRules === 'function') ? window.getMatchedCSSRules( element ) : null
      , elStyleWidth = element.style.width
      , elCSSWidth
      , elWidth = this.$element.width()

    if (elRules) {
      $.each( elRules, function (i, rule) {
        if (rule.style.width) {
          elCSSWidth = rule.style.width;
        }
      });
    }

    // Move original input out of the way
    var hidingPosition = $('body').css('direction') === 'rtl' ? 'right' : 'left',
        originalStyles = { position: this.$element.css('position') };
    originalStyles[hidingPosition] = this.$element.css(hidingPosition);

    this.$element
      .data('original-styles', originalStyles)
      .data('original-tabindex', this.$element.prop('tabindex'))
      .css('position', 'absolute')
      .css(hidingPosition, '-10000px')
      .prop('tabindex', -1)

    // Create a wrapper
    this.$wrapper = $('<div class="tokenfield form-control" />')
    if (this.$element.hasClass('input-lg')) this.$wrapper.addClass('input-lg')
    if (this.$element.hasClass('input-sm')) this.$wrapper.addClass('input-sm')
    if (this.textDirection === 'rtl') this.$wrapper.addClass('rtl')

    // Create a new input
    var id = this.$element.prop('id') || new Date().getTime() + '' + Math.floor((1 + Math.random()) * 100)
    this.$input = $('<input type="'+this.options.inputType+'" class="token-input" autocomplete="off" />')
                    .appendTo( this.$wrapper )
                    .prop( 'placeholder',  this.$element.prop('placeholder') )
                    .prop( 'id', id + '-tokenfield' )
                    .prop( 'tabindex', this.$element.data('original-tabindex') )

    // Re-route original input label to new input
    var $label = $( 'label[for="' + this.$element.prop('id') + '"]' )
    if ( $label.length ) {
      $label.prop( 'for', this.$input.prop('id') )
    }

    // Set up a copy helper to handle copy & paste
    this.$copyHelper = $('<input type="text" />').css('position', 'absolute').css(hidingPosition, '-10000px').prop('tabindex', -1).prependTo( this.$wrapper )

    // Set wrapper width
    if (elStyleWidth) {
      this.$wrapper.css('width', elStyleWidth);
    }
    else if (elCSSWidth) {
      this.$wrapper.css('width', elCSSWidth);
    }
    // If input is inside inline-form with no width set, set fixed width
    else if (this.$element.parents('.form-inline').length) {
      this.$wrapper.width( elWidth )
    }

    // Set tokenfield disabled, if original or fieldset input is disabled
    if (this.$element.prop('disabled') || this.$element.parents('fieldset[disabled]').length) {
      this.disable();
    }

    // Set tokenfield readonly, if original input is readonly
    if (this.$element.prop('readonly')) {
      this.readonly();
    }

    // Set up mirror for input auto-sizing
    this.$mirror = $('<span style="position:absolute; top:-999px; left:0; white-space:pre;"/>');
    this.$input.css('min-width', this.options.minWidth + 'px')
    $.each([
        'fontFamily',
        'fontSize',
        'fontWeight',
        'fontStyle',
        'letterSpacing',
        'textTransform',
        'wordSpacing',
        'textIndent'
    ], function (i, val) {
        _self.$mirror[0].style[val] = _self.$input.css(val);
    });
    this.$mirror.appendTo( 'body' )

    // Insert tokenfield to HTML
    this.$wrapper.insertBefore( this.$element )
    this.$element.prependTo( this.$wrapper )

    // Calculate inner input width
    this.update()

    // Create initial tokens, if any
    this.setTokens(this.options.tokens, false, ! this.$element.val() && this.options.tokens )

    // Start listening to events
    this.listen()

    // Initialize autocomplete, if necessary
    if ( ! $.isEmptyObject( this.options.autocomplete ) ) {
      var side = this.textDirection === 'rtl' ? 'right' : 'left'
       ,  autocompleteOptions = $.extend({
            minLength: this.options.showAutocompleteOnFocus ? 0 : null,
            position: { my: side + " top", at: side + " bottom", of: this.$wrapper }
          }, this.options.autocomplete )

      this.$input.autocomplete( autocompleteOptions )
    }

    // Initialize typeahead, if necessary
    if ( ! $.isEmptyObject( this.options.typeahead ) ) {

      var typeaheadOptions = this.options.typeahead
        , defaults = {
            minLength: this.options.showAutocompleteOnFocus ? 0 : null
          }
        , args = $.isArray( typeaheadOptions ) ? typeaheadOptions : [typeaheadOptions, typeaheadOptions]

      args[0] = $.extend( {}, defaults, args[0] )

      this.$input.typeahead.apply( this.$input, args )
      this.$hint = this.$input.prev('.tt-hint')
      this.typeahead = true
    }
  }

  Tokenfield.prototype = {

    constructor: Tokenfield

  , createToken: function (attrs, triggerChange) {
      var _self = this

      if (typeof attrs === 'string') {
        attrs = { value: attrs, label: attrs }
      } else {
        // Copy objects to prevent contamination of data sources.
        attrs = $.extend( {}, attrs )
      }

      if (typeof triggerChange === 'undefined') {
         triggerChange = true
      }

      // Normalize label and value
      attrs.value = $.trim(attrs.value.toString());
      attrs.label = attrs.label && attrs.label.length ? $.trim(attrs.label) : attrs.value

      // Bail out if has no value or label, or label is too short
      if (!attrs.value.length || !attrs.label.length || attrs.label.length <= this.options.minLength) return

      // Bail out if maximum number of tokens is reached
      if (this.options.limit && this.getTokens().length >= this.options.limit) return

      // Allow changing token data before creating it
      var createEvent = $.Event('tokenfield:createtoken', { attrs: attrs })
      this.$element.trigger(createEvent)

      // Bail out if there if attributes are empty or event was defaultPrevented
      if (!createEvent.attrs || createEvent.isDefaultPrevented()) return

      var $token = $('<div class="token" />')
            .append('<span class="token-label" />')
            .append('<a href="#" class="close" tabindex="-1">&times;</a>')
            .data('attrs', attrs)

      // Insert token into HTML
      if (this.$input.hasClass('tt-input')) {
        // If the input has typeahead enabled, insert token before it's parent
        this.$input.parent().before( $token )
      } else {
        this.$input.before( $token )
      }

      // Temporarily set input width to minimum
      this.$input.css('width', this.options.minWidth + 'px')

      var $tokenLabel = $token.find('.token-label')
        , $closeButton = $token.find('.close')

      // Determine maximum possible token label width
      if (!this.maxTokenWidth) {
        this.maxTokenWidth =
          this.$wrapper.width() - $closeButton.outerWidth() -
          parseInt($closeButton.css('margin-left'), 10) -
          parseInt($closeButton.css('margin-right'), 10) -
          parseInt($token.css('border-left-width'), 10) -
          parseInt($token.css('border-right-width'), 10) -
          parseInt($token.css('padding-left'), 10) -
          parseInt($token.css('padding-right'), 10)
          parseInt($tokenLabel.css('border-left-width'), 10) -
          parseInt($tokenLabel.css('border-right-width'), 10) -
          parseInt($tokenLabel.css('padding-left'), 10) -
          parseInt($tokenLabel.css('padding-right'), 10)
          parseInt($tokenLabel.css('margin-left'), 10) -
          parseInt($tokenLabel.css('margin-right'), 10)
      }

      $tokenLabel
        .text(attrs.label)
        .css('max-width', this.maxTokenWidth)

      // Listen to events on token
      $token
        .on('mousedown',  function (e) {
          if (_self._disabled || _self._readonly) return false
          _self.preventDeactivation = true
        })
        .on('click',    function (e) {
          if (_self._disabled || _self._readonly) return false
          _self.preventDeactivation = false

          if (e.ctrlKey || e.metaKey) {
            e.preventDefault()
            return _self.toggle( $token )
          }

          _self.activate( $token, e.shiftKey, e.shiftKey )
        })
        .on('dblclick', function (e) {
          if (_self._disabled || _self._readonly || !_self.options.allowEditing ) return false
          _self.edit( $token )
        })

      $closeButton
          .on('click',  $.proxy(this.remove, this))

      // Trigger createdtoken event on the original field
      // indicating that the token is now in the DOM
      this.$element.trigger($.Event('tokenfield:createdtoken', {
        attrs: attrs,
        relatedTarget: $token.get(0)
      }))

      // Trigger change event on the original field
      if (triggerChange) {
        this.$element.val( this.getTokensList() ).trigger( $.Event('change', { initiator: 'tokenfield' }) )
      }

      // Update tokenfield dimensions
      this.update()

      // Return original element
      return this.$element.get(0)
    }

  , setTokens: function (tokens, add, triggerChange) {
      if (!tokens) return

      if (!add) this.$wrapper.find('.token').remove()

      if (typeof triggerChange === 'undefined') {
          triggerChange = true
      }

      if (typeof tokens === 'string') {
        if (this._delimiters.length) {
          // Split based on delimiters
          tokens = tokens.split( new RegExp( '[' + this._delimiters.join('') + ']' ) )
        } else {
          tokens = [tokens];
        }
      }

      var _self = this
      $.each(tokens, function (i, attrs) {
        _self.createToken(attrs, triggerChange)
      })

      return this.$element.get(0)
    }

  , getTokenData: function($token) {
      var data = $token.map(function() {
        var $token = $(this);
        return $token.data('attrs')
      }).get();

      if (data.length == 1) {
        data = data[0];
      }

      return data;
    }

  , getTokens: function(active) {
      var self = this
        , tokens = []
        , activeClass = active ? '.active' : '' // get active tokens only
      this.$wrapper.find( '.token' + activeClass ).each( function() {
        tokens.push( self.getTokenData( $(this) ) )
      })
      return tokens
  }

  , getTokensList: function(delimiter, beautify, active) {
      delimiter = delimiter || this._firstDelimiter
      beautify = ( typeof beautify !== 'undefined' && beautify !== null ) ? beautify : this.options.beautify

      var separator = delimiter + ( beautify && delimiter !== ' ' ? ' ' : '')
      return $.map( this.getTokens(active), function (token) {
        return token.value
      }).join(separator)
  }

  , getInput: function() {
    return this.$input.val()
  }

  , listen: function () {
      var _self = this

      this.$element
        .on('change',   $.proxy(this.change, this))

      this.$wrapper
        .on('mousedown',$.proxy(this.focusInput, this))

      this.$input
        .on('focus',    $.proxy(this.focus, this))
        .on('blur',     $.proxy(this.blur, this))
        .on('paste',    $.proxy(this.paste, this))
        .on('keydown',  $.proxy(this.keydown, this))
        .on('keypress', $.proxy(this.keypress, this))
        .on('keyup',    $.proxy(this.keyup, this))

      this.$copyHelper
        .on('focus',    $.proxy(this.focus, this))
        .on('blur',     $.proxy(this.blur, this))
        .on('keydown',  $.proxy(this.keydown, this))
        .on('keyup',    $.proxy(this.keyup, this))

      // Secondary listeners for input width calculation
      this.$input
        .on('keypress', $.proxy(this.update, this))
        .on('keyup',    $.proxy(this.update, this))

      this.$input
        .on('autocompletecreate', function() {
          // Set minimum autocomplete menu width
          var $_menuElement = $(this).data('ui-autocomplete').menu.element

          var minWidth = _self.$wrapper.outerWidth() -
              parseInt( $_menuElement.css('border-left-width'), 10 ) -
              parseInt( $_menuElement.css('border-right-width'), 10 )

          $_menuElement.css( 'min-width', minWidth + 'px' )
        })
        .on('autocompleteselect', function (e, ui) {
          if (_self.createToken( ui.item )) {
            _self.$input.val('')
            if (_self.$input.data( 'edit' )) {
              _self.unedit(true)
            }
          }
          return false
        })
        .on('typeahead:selected typeahead:autocompleted', function (e, datum, dataset) {
          // Create token
          if (_self.createToken( datum )) {
            _self.$input.typeahead('val', '')
            if (_self.$input.data( 'edit' )) {
              _self.unedit(true)
            }
          }
        })

      // Listen to window resize
      $(window).on('resize', $.proxy(this.update, this ))

    }

  , keydown: function (e) {

      if (!this.focused) return

      var _self = this

      switch(e.keyCode) {
        case 8: // backspace
          if (!this.$input.is(document.activeElement)) break
          this.lastInputValue = this.$input.val()
          break

        case 37: // left arrow
          leftRight( this.textDirection === 'rtl' ? 'next': 'prev' )
          break

        case 38: // up arrow
          upDown('prev')
          break

        case 39: // right arrow
          leftRight( this.textDirection === 'rtl' ? 'prev': 'next' )
          break

        case 40: // down arrow
          upDown('next')
          break

        case 65: // a (to handle ctrl + a)
          if (this.$input.val().length > 0 || !(e.ctrlKey || e.metaKey)) break
          this.activateAll()
          e.preventDefault()
          break

        case 9: // tab
        case 13: // enter

          // We will handle creating tokens from autocomplete in autocomplete events
          if (this.$input.data('ui-autocomplete') && this.$input.data('ui-autocomplete').menu.element.find("li:has(a.ui-state-focus), li.ui-state-focus").length) break

          // We will handle creating tokens from typeahead in typeahead events
          if (this.$input.hasClass('tt-input') && this.$wrapper.find('.tt-cursor').length ) break
          if (this.$input.hasClass('tt-input') && this.$wrapper.find('.tt-hint').val() && this.$wrapper.find('.tt-hint').val().length) break

          // Create token
          if (this.$input.is(document.activeElement) && this.$input.val().length || this.$input.data('edit')) {
            return this.createTokensFromInput(e, this.$input.data('edit'));
          }

          // Edit token
          if (e.keyCode === 13) {
            if (!this.$copyHelper.is(document.activeElement) || this.$wrapper.find('.token.active').length !== 1) break
            if (!_self.options.allowEditing) break
            this.edit( this.$wrapper.find('.token.active') )
          }
      }

      function leftRight(direction) {
        if (_self.$input.is(document.activeElement)) {
          if (_self.$input.val().length > 0) return

          direction += 'All'
          var $token = _self.$input.hasClass('tt-input') ? _self.$input.parent()[direction]('.token:first') : _self.$input[direction]('.token:first')
          if (!$token.length) return

          _self.preventInputFocus = true
          _self.preventDeactivation = true

          _self.activate( $token )
          e.preventDefault()

        } else {
          _self[direction]( e.shiftKey )
          e.preventDefault()
        }
      }

      function upDown(direction) {
        if (!e.shiftKey) return

        if (_self.$input.is(document.activeElement)) {
          if (_self.$input.val().length > 0) return

          var $token = _self.$input.hasClass('tt-input') ? _self.$input.parent()[direction + 'All']('.token:first') : _self.$input[direction + 'All']('.token:first')
          if (!$token.length) return

          _self.activate( $token )
        }

        var opposite = direction === 'prev' ? 'next' : 'prev'
          , position = direction === 'prev' ? 'first' : 'last'

        _self.$firstActiveToken[opposite + 'All']('.token').each(function() {
          _self.deactivate( $(this) )
        })

        _self.activate( _self.$wrapper.find('.token:' + position), true, true )
        e.preventDefault()
      }

      this.lastKeyDown = e.keyCode
    }

  , keypress: function(e) {

      // Comma
      if ($.inArray( e.which, this._triggerKeys) !== -1 && this.$input.is(document.activeElement)) {
        if (this.$input.val()) {
          this.createTokensFromInput(e)
        }
        return false;
      }
    }

  , keyup: function (e) {
      this.preventInputFocus = false

      if (!this.focused) return

      switch(e.keyCode) {
        case 8: // backspace
          if (this.$input.is(document.activeElement)) {
            if (this.$input.val().length || this.lastInputValue.length && this.lastKeyDown === 8) break

            this.preventDeactivation = true
            var $prevToken = this.$input.hasClass('tt-input') ? this.$input.parent().prevAll('.token:first') : this.$input.prevAll('.token:first')

            if (!$prevToken.length) break

            this.activate( $prevToken )
          } else {
            this.remove(e)
          }
          break

        case 46: // delete
          this.remove(e, 'next')
          break
      }
      this.lastKeyUp = e.keyCode
    }

  , focus: function (e) {
      this.focused = true
      this.$wrapper.addClass('focus')

      if (this.$input.is(document.activeElement)) {
        this.$wrapper.find('.active').removeClass('active')
        this.$firstActiveToken = null

        if (this.options.showAutocompleteOnFocus) {
          this.search()
        }
      }
    }

  , blur: function (e) {

      this.focused = false
      this.$wrapper.removeClass('focus')

      if (!this.preventDeactivation && !this.$element.is(document.activeElement)) {
        this.$wrapper.find('.active').removeClass('active')
        this.$firstActiveToken = null
      }

      if (!this.preventCreateTokens && (this.$input.data('edit') && !this.$input.is(document.activeElement) || this.options.createTokensOnBlur )) {
        this.createTokensFromInput(e)
      }

      this.preventDeactivation = false
      this.preventCreateTokens = false
    }

  , paste: function (e) {
      var _self = this

      // Add tokens to existing ones
      if (_self.options.allowPasting) {
        setTimeout(function () {
          _self.createTokensFromInput(e)
        }, 1)
      }
    }

  , change: function (e) {
      if ( e.initiator === 'tokenfield' ) return // Prevent loops

      this.setTokens( this.$element.val() )
    }

  , createTokensFromInput: function (e, focus) {
      if (this.$input.val().length < this.options.minLength)
        return // No input, simply return

      var tokensBefore = this.getTokensList()
      this.setTokens( this.$input.val(), true )

      if (tokensBefore == this.getTokensList() && this.$input.val().length)
        return false // No tokens were added, do nothing (prevent form submit)

      if (this.$input.hasClass('tt-input')) {
        // Typeahead acts weird when simply setting input value to empty,
        // so we set the query to empty instead
        this.$input.typeahead('val', '')
      } else {
        this.$input.val('')
      }

      if (this.$input.data( 'edit' )) {
        this.unedit(focus)
      }

      return false // Prevent form being submitted
    }

  , next: function (add) {
      if (add) {
        var $firstActiveToken = this.$wrapper.find('.active:first')
          , deactivate = $firstActiveToken && this.$firstActiveToken ? $firstActiveToken.index() < this.$firstActiveToken.index() : false

        if (deactivate) return this.deactivate( $firstActiveToken )
      }

      var $lastActiveToken = this.$wrapper.find('.active:last')
        , $nextToken = $lastActiveToken.nextAll('.token:first')

      if (!$nextToken.length) {
        this.$input.focus()
        return
      }

      this.activate($nextToken, add)
    }

  , prev: function (add) {

      if (add) {
        var $lastActiveToken = this.$wrapper.find('.active:last')
          , deactivate = $lastActiveToken && this.$firstActiveToken ? $lastActiveToken.index() > this.$firstActiveToken.index() : false

        if (deactivate) return this.deactivate( $lastActiveToken )
      }

      var $firstActiveToken = this.$wrapper.find('.active:first')
        , $prevToken = $firstActiveToken.prevAll('.token:first')

      if (!$prevToken.length) {
        $prevToken = this.$wrapper.find('.token:first')
      }

      if (!$prevToken.length && !add) {
        this.$input.focus()
        return
      }

      this.activate( $prevToken, add )
    }

  , activate: function ($token, add, multi, remember) {

      if (!$token) return

      if (typeof remember === 'undefined') var remember = true

      if (multi) var add = true

      this.$copyHelper.focus()

      if (!add) {
        this.$wrapper.find('.active').removeClass('active')
        if (remember) {
          this.$firstActiveToken = $token
        } else {
          delete this.$firstActiveToken
        }
      }

      if (multi && this.$firstActiveToken) {
        // Determine first active token and the current tokens indicies
        // Account for the 1 hidden textarea by subtracting 1 from both
        var i = this.$firstActiveToken.index() - 2
          , a = $token.index() - 2
          , _self = this

        this.$wrapper.find('.token').slice( Math.min(i, a) + 1, Math.max(i, a) ).each( function() {
          _self.activate( $(this), true )
        })
      }

      $token.addClass('active')
      this.$copyHelper.val( this.getTokensList( null, null, true ) ).select()
    }

  , activateAll: function() {
      var _self = this

      this.$wrapper.find('.token').each( function (i) {
        _self.activate($(this), i !== 0, false, false)
      })
    }

  , deactivate: function($token) {
      if (!$token) return

      $token.removeClass('active')
      this.$copyHelper.val( this.getTokensList( null, null, true ) ).select()
    }

  , toggle: function($token) {
      if (!$token) return

      $token.toggleClass('active')
      this.$copyHelper.val( this.getTokensList( null, null, true ) ).select()
    }

  , edit: function ($token) {
      if (!$token) return

      var attrs = $token.data('attrs')

      // Allow changing input value before editing
      var options = { attrs: attrs, relatedTarget: $token.get(0) }
      var editEvent = $.Event('tokenfield:edittoken', options)
      this.$element.trigger( editEvent )

      // Edit event can be cancelled if default is prevented
      if (editEvent.isDefaultPrevented()) return

      $token.find('.token-label').text(attrs.value)
      var tokenWidth = $token.outerWidth()

      var $_input = this.$input.hasClass('tt-input') ? this.$input.parent() : this.$input

      $token.replaceWith( $_input )

      this.preventCreateTokens = true

      this.$input.val( attrs.value )
                .select()
                .data( 'edit', true )
                .width( tokenWidth )

      this.update();

      // Indicate that token is now being edited, and is replaced with an input field in the DOM
      this.$element.trigger($.Event('tokenfield:editedtoken', options ))
    }

  , unedit: function (focus) {
      var $_input = this.$input.hasClass('tt-input') ? this.$input.parent() : this.$input
      $_input.appendTo( this.$wrapper )

      this.$input.data('edit', false)
      this.$mirror.text('')

      this.update()

      // Because moving the input element around in DOM
      // will cause it to lose focus, we provide an option
      // to re-focus the input after appending it to the wrapper
      if (focus) {
        var _self = this
        setTimeout(function () {
          _self.$input.focus()
        }, 1)
      }
    }

  , remove: function (e, direction) {
      if (this.$input.is(document.activeElement) || this._disabled || this._readonly) return

      var $token = (e.type === 'click') ? $(e.target).closest('.token') : this.$wrapper.find('.token.active')

      if (e.type !== 'click') {
        if (!direction) var direction = 'prev'
        this[direction]()

        // Was it the first token?
        if (direction === 'prev') var firstToken = $token.first().prevAll('.token:first').length === 0
      }

      // Prepare events and their options
      var options = { attrs: this.getTokenData( $token ), relatedTarget: $token.get(0) }
        , removeEvent = $.Event('tokenfield:removetoken', options)

      this.$element.trigger(removeEvent);

      // Remove event can be intercepted and cancelled
      if (removeEvent.isDefaultPrevented()) return

      var removedEvent = $.Event('tokenfield:removedtoken', options)
        , changeEvent = $.Event('change', { initiator: 'tokenfield' })

      // Remove token from DOM
      $token.remove()

      // Trigger events
      this.$element.val( this.getTokensList() ).trigger( removedEvent ).trigger( changeEvent )

      // Focus, when necessary:
      // When there are no more tokens, or if this was the first token
      // and it was removed with backspace or it was clicked on
      if (!this.$wrapper.find('.token').length || e.type === 'click' || firstToken) this.$input.focus()

      // Adjust input width
      this.$input.css('width', this.options.minWidth + 'px')
      this.update()

      // Cancel original event handlers
      e.preventDefault()
      e.stopPropagation()
    }

    /**
     * Update tokenfield dimensions
     */
  , update: function (e) {
      var value = this.$input.val()
        , inputPaddingLeft = parseInt(this.$input.css('padding-left'), 10)
        , inputPaddingRight = parseInt(this.$input.css('padding-right'), 10)
        , inputPadding = inputPaddingLeft + inputPaddingRight

      if (this.$input.data('edit')) {

        if (!value) {
          value = this.$input.prop("placeholder")
        }
        if (value === this.$mirror.text()) return

        this.$mirror.text(value)

        var mirrorWidth = this.$mirror.width() + 10;
        if ( mirrorWidth > this.$wrapper.width() ) {
          return this.$input.width( this.$wrapper.width() )
        }

        this.$input.width( mirrorWidth )

        if (this.$hint) {
          this.$hint.width( mirrorWidth )
        }
      }
      else {
        var w = (this.textDirection === 'rtl')
              ? this.$input.offset().left + this.$input.outerWidth() - this.$wrapper.offset().left - parseInt(this.$wrapper.css('padding-left'), 10) - inputPadding - 1
              : this.$wrapper.offset().left + this.$wrapper.width() + parseInt(this.$wrapper.css('padding-left'), 10) - this.$input.offset().left - inputPadding;
        //
        // some usecases pre-render widget before attaching to DOM,
        // dimensions returned by jquery will be NaN -> we default to 100%
        // so placeholder won't be cut off.
        isNaN(w) ? this.$input.width('100%') : this.$input.width(w);

        if (this.$hint) {
          isNaN(w) ? this.$hint.width('100%') : this.$hint.width(w);
        }
      }
    }

  , focusInput: function (e) {
      if ( $(e.target).closest('.token').length || $(e.target).closest('.token-input').length || $(e.target).closest('.tt-dropdown-menu').length ) return
      // Focus only after the current call stack has cleared,
      // otherwise has no effect.
      // Reason: mousedown is too early - input will lose focus
      // after mousedown. However, since the input may be moved
      // in DOM, there may be no click or mouseup event triggered.
      var _self = this
      setTimeout(function() {
        _self.$input.focus()
      }, 0)
    }

  , search: function () {
      if ( this.$input.data('ui-autocomplete') ) {
        this.$input.autocomplete('search')
      }
    }

  , disable: function () {
      this.setProperty('disabled', true);
    }

  , enable: function () {
      this.setProperty('disabled', false);
    }

  , readonly: function () {
      this.setProperty('readonly', true);
    }

  , writeable: function () {
      this.setProperty('readonly', false);
    }

  , setProperty: function(property, value) {
      this['_' + property] = value;
      this.$input.prop(property, value);
      this.$element.prop(property, value);
      this.$wrapper[ value ? 'addClass' : 'removeClass' ](property);
  }

  , destroy: function() {
      // Set field value
      this.$element.val( this.getTokensList() );
      // Restore styles and properties
      this.$element.css( this.$element.data('original-styles') );
      this.$element.prop( 'tabindex', this.$element.data('original-tabindex') );

      // Re-route tokenfield label to original input
      var $label = $( 'label[for="' + this.$input.prop('id') + '"]' )
      if ( $label.length ) {
        $label.prop( 'for', this.$element.prop('id') )
      }

      // Move original element outside of tokenfield wrapper
      this.$element.insertBefore( this.$wrapper );

      // Remove tokenfield-related data
      this.$element.removeData('original-styles')
                   .removeData('original-tabindex')
                   .removeData('bs.tokenfield');

      // Remove tokenfield from DOM
      this.$wrapper.remove();
      this.$mirror.remove();

      var $_element = this.$element;

      return $_element;
  }

  }


 /* TOKENFIELD PLUGIN DEFINITION
  * ======================== */

  var old = $.fn.tokenfield

  $.fn.tokenfield = function (option, param) {
    var value
      , args = []

    Array.prototype.push.apply( args, arguments );

    var elements = this.each(function () {
      var $this = $(this)
        , data = $this.data('bs.tokenfield')
        , options = typeof option == 'object' && option

      if (typeof option === 'string' && data && data[option]) {
        args.shift()
        value = data[option].apply(data, args)
      } else {
        if (!data && typeof option !== 'string' && !param) {
          $this.data('bs.tokenfield', (data = new Tokenfield(this, options)))
          $this.trigger('tokenfield:initialize')
        }
      }
    })

    return typeof value !== 'undefined' ? value : elements;
  }

  $.fn.tokenfield.defaults = {
    minWidth: 60,
    minLength: 0,
    allowEditing: true,
    allowPasting: true,
    limit: 0,
    autocomplete: {},
    typeahead: {},
    showAutocompleteOnFocus: false,
    createTokensOnBlur: false,
    delimiter: ',',
    beautify: true,
    inputType: 'text'
  }

  $.fn.tokenfield.Constructor = Tokenfield


 /* TOKENFIELD NO CONFLICT
  * ================== */

  $.fn.tokenfield.noConflict = function () {
    $.fn.tokenfield = old
    return this
  }

  return Tokenfield;

}));
README.md000066400000011637152434262010006034 0ustar00Bootstrap Tokenfield
====================
[![NPM version][npm-badge]](http://badge.fury.io/js/bootstrap-tokenfield)
[![Build status][travis-badge]](https://travis-ci.org/sliptree/bootstrap-tokenfield)
[npm-badge]: https://badge.fury.io/js/bootstrap-tokenfield.png
[travis-badge]: https://travis-ci.org/sliptree/bootstrap-tokenfield.png?branch=master

A jQuery tagging / tokenizer input plugin for Twitter's Bootstrap, by the guys from [Sliptree](https://sliptree.com)

Check out the [demo and docs](http://sliptree.github.io/bootstrap-tokenfield/)

### Installation

Requirements: jQuery 1.9+, Bootstrap 3+ (only CSS)

1. Install via npm or bower (recommended) or manually download the package
2. Include `dist/bootstrap-tokenfield.js` or `dist/bootstrap-tokenfield.min.js` in your HTML
3. Include `dist/css/bootstrap-tokenfield.css` in your HTML

### Usage

```js	
$('input').tokenfield()
```

### Features

* Copy & paste tokens with Ctrl+C and Ctrl+V
* Keyboard navigation, delete tokens with keyboard (arrow keys, Shift + arrow keys)
* Select specific tokens with Ctrl + click and Shift + click
* Twitter Typeahead and jQuery UI Autocomplete support

### FAQ

#### How can I prevent duplicate tokens from being entered?

You can use the `tokenfield:createtoken` event for that. Check the `event.attrs` property for token value and label,
and the run your duplicate detection logic. If it's a duplicate token, simply do `event.preventDefault()`.

Here's a simple example that checks if token's value is equal to any of the existing tokens' values.

```js
$('#my-tokenfield').on('tokenfield:createtoken', function (event) {
	var existingTokens = $(this).tokenfield('getTokens');
	$.each(existingTokens, function(index, token) {
		if (token.value === event.attrs.value)
			event.preventDefault();
	});
});
```

#### And how about limiting tokens to my typeahead/autocomplete data?

Similarly, using `tokenfield:createtoken`, you can check to see if a token exists in your autocomplete/typeahead
data. This example checks if the given token already exists and stops its entry if it doesn't.

```js
$('#my-tokenfield').on('tokenfield:createtoken', function (event) {
	var available_tokens = bloodhound_tokens.index.datums
	var exists = true;
	$.each(available_tokens, function(index, token) {
		if (token.value === event.attrs.value)
			exists = false;
	});
	if(exists === true)
		event.preventDefault();
})
```



### Changelog

See [release notes](https://github.com/sliptree/bootstrap-tokenfield/releases)

Previous releases:

0.10.0

* Fixed: Entering a duplicate token does not submit the underlying form anymore
* Fixed: Selecting a duplicate token from autocomplete or typeahead suggestions no longer clears the input
* Improved: Trying to enter a duplicate tag now animates the existing tag for a little while
* Improved: Tokenfield input has now `autocomplete="off"` to prevent browser-specific autocomplete suggestions
* Changed: `triggerKeys` has been renamed to `delimiter` and accepts a single or an array of characters instead of character codes.

0.9.9-1

* Fixed: setTokens now respects `triggerKeys` option

0.9.8 

* New: `triggerKeys` option
* Fixed: Long placeholders are not being cut off anymore when initializing tokenfield with no tokens #37
* Fixed: createTokensOnBlur no more breaks token editing #35

0.9.7 Valuable

* Fixed: Twitter Typeahead valueKey support #18
* Fixed: Removing multiple tokens returned wrong data #30
* Fixed: If token is removed in beforeEdit event, no longer falls over #27, #28
* Fixed: Change event was triggered on initialization #22
* Fixed: When token is removed in tokenfield:preparetoken event, no longer tries to create a token
* Fixed: Pressing comma key was not handled reliably
* New: `prevetDuplicateToken` event
* Improved: Typeahead integration
* Improved: styling
* Minor tweaks, fixes, improvements 

0.9.5 Typeable

* New: Twitter Typeahead support
* New: When triggering 'change' event on original input, setTokens is now called. This allows you to update tokens externally.
* Fixed: Nnput labels did not work with tokenfield
* Fixed: Set correct input width on fixed-width inputs

0.9.2 Maintenance release

* Many small fixes and improvements

0.9.0 Bootstrappable

* New: Bootstrap 3 support
* New: Input group support
* New: Disable/enable tokenfield
* New: Tokenfield is now responsive
* Deprecated: Bootstrap 2 support

0.7.1 

* Fixed: pressing comma did not create a token in Firefox
* Fixed: tokenfield('getTokensList') returned array instead of string

0.7.0 Autocompleted

* New feature: jQuery UI Autocomplete support

0.6.7 Crossable

* Fixed: Firefox close icon was misplaced
* New: IE 8-10 support (both CSS and Javascript)

0.6.5 Shiftable

* New feature: select specific tokens with Ctrl/Shift + click
* New feature: select specific tokens with Shift + arrow keys
* Internal API improvements

0.6 Editable

* New feature: Edit existing tokens by double-clicking or pressing enter
* A lot of improvements and bugfixes

0.5 Initial release
js/bootstrap-tokenfield.js000066400000101320152434262010011653 0ustar00/*!
 * bootstrap-tokenfield
 * https://github.com/sliptree/bootstrap-tokenfield
 * Copyright 2013-2014 Sliptree and other contributors; Licensed MIT
 */

(function (factory) {
  if (typeof define === 'function' && define.amd) {
    // AMD. Register as an anonymous module.
    define(['jquery'], factory);
  } else if (typeof exports === 'object') {
    // For CommonJS and CommonJS-like environments where a window with jQuery
    // is present, execute the factory with the jQuery instance from the window object
    // For environments that do not inherently posses a window with a document
    // (such as Node.js), expose a Tokenfield-making factory as module.exports
    // This accentuates the need for the creation of a real window or passing in a jQuery instance
    // e.g. require("bootstrap-tokenfield")(window); or require("bootstrap-tokenfield")($);
    module.exports = global.window && global.window.$ ?
      factory( global.window.$ ) :
      function( input ) {
        if ( !input.$ && !input.fn ) {
          throw new Error( "Tokenfield requires a window object with jQuery or a jQuery instance" );
        }
        return factory( input.$ || input );
      };
  } else {
    // Browser globals
    factory(jQuery, window);
  }
}(function ($, window) {

  "use strict"; // jshint ;_;

 /* TOKENFIELD PUBLIC CLASS DEFINITION
  * ============================== */

  var Tokenfield = function (element, options) {
    var _self = this

    this.$element = $(element)
    this.textDirection = this.$element.css('direction');

    // Extend options
    this.options = $.extend(true, {}, $.fn.tokenfield.defaults, { tokens: this.$element.val() }, this.$element.data(), options)

    // Setup delimiters and trigger keys
    this._delimiters = (typeof this.options.delimiter === 'string') ? [this.options.delimiter] : this.options.delimiter
    this._triggerKeys = $.map(this._delimiters, function (delimiter) {
      return delimiter.charCodeAt(0);
    });
    this._firstDelimiter = this._delimiters[0];

    // Check for whitespace, dash and special characters
    var whitespace = $.inArray(' ', this._delimiters)
      , dash = $.inArray('-', this._delimiters)

    if (whitespace >= 0)
      this._delimiters[whitespace] = '\\s'

    if (dash >= 0) {
      delete this._delimiters[dash]
      this._delimiters.unshift('-')
    }

    var specialCharacters = ['\\', '$', '[', '{', '^', '.', '|', '?', '*', '+', '(', ')']
    $.each(this._delimiters, function (index, character) {
      var pos = $.inArray(character, specialCharacters)
      if (pos >= 0) _self._delimiters[index] = '\\' + character;
    });

    // Store original input width
    var elRules = (window && typeof window.getMatchedCSSRules === 'function') ? window.getMatchedCSSRules( element ) : null
      , elStyleWidth = element.style.width
      , elCSSWidth
      , elWidth = this.$element.width()

    if (elRules) {
      $.each( elRules, function (i, rule) {
        if (rule.style.width) {
          elCSSWidth = rule.style.width;
        }
      });
    }

    // Move original input out of the way
    var hidingPosition = $('body').css('direction') === 'rtl' ? 'right' : 'left',
        originalStyles = { position: this.$element.css('position') };
    originalStyles[hidingPosition] = this.$element.css(hidingPosition);

    this.$element
      .data('original-styles', originalStyles)
      .data('original-tabindex', this.$element.prop('tabindex'))
      .css('position', 'absolute')
      .css(hidingPosition, '-10000px')
      .prop('tabindex', -1)

    // Create a wrapper
    this.$wrapper = $('<div class="tokenfield form-control" />')
    if (this.$element.hasClass('input-lg')) this.$wrapper.addClass('input-lg')
    if (this.$element.hasClass('input-sm')) this.$wrapper.addClass('input-sm')
    if (this.textDirection === 'rtl') this.$wrapper.addClass('rtl')

    // Create a new input
    var id = this.$element.prop('id') || new Date().getTime() + '' + Math.floor((1 + Math.random()) * 100)
    this.$input = $('<input type="'+this.options.inputType+'" class="token-input" autocomplete="off" />')
                    .appendTo( this.$wrapper )
                    .prop( 'placeholder',  this.$element.prop('placeholder') )
                    .prop( 'id', id + '-tokenfield' )
                    .prop( 'tabindex', this.$element.data('original-tabindex') )

    // Re-route original input label to new input
    var $label = $( 'label[for="' + this.$element.prop('id') + '"]' )
    if ( $label.length ) {
      $label.prop( 'for', this.$input.prop('id') )
    }

    // Set up a copy helper to handle copy & paste
    this.$copyHelper = $('<input type="text" />').css('position', 'absolute').css(hidingPosition, '-10000px').prop('tabindex', -1).prependTo( this.$wrapper )

    // Set wrapper width
    if (elStyleWidth) {
      this.$wrapper.css('width', elStyleWidth);
    }
    else if (elCSSWidth) {
      this.$wrapper.css('width', elCSSWidth);
    }
    // If input is inside inline-form with no width set, set fixed width
    else if (this.$element.parents('.form-inline').length) {
      this.$wrapper.width( elWidth )
    }

    // Set tokenfield disabled, if original or fieldset input is disabled
    if (this.$element.prop('disabled') || this.$element.parents('fieldset[disabled]').length) {
      this.disable();
    }

    // Set tokenfield readonly, if original input is readonly
    if (this.$element.prop('readonly')) {
      this.readonly();
    }

    // Set up mirror for input auto-sizing
    this.$mirror = $('<span style="position:absolute; top:-999px; left:0; white-space:pre;"/>');
    this.$input.css('min-width', this.options.minWidth + 'px')
    $.each([
        'fontFamily',
        'fontSize',
        'fontWeight',
        'fontStyle',
        'letterSpacing',
        'textTransform',
        'wordSpacing',
        'textIndent'
    ], function (i, val) {
        _self.$mirror[0].style[val] = _self.$input.css(val);
    });
    this.$mirror.appendTo( 'body' )

    // Insert tokenfield to HTML
    this.$wrapper.insertBefore( this.$element )
    this.$element.prependTo( this.$wrapper )

    // Calculate inner input width
    this.update()

    // Create initial tokens, if any
    this.setTokens(this.options.tokens, false, ! this.$element.val() && this.options.tokens )

    // Start listening to events
    this.listen()

    // Initialize autocomplete, if necessary
    if ( ! $.isEmptyObject( this.options.autocomplete ) ) {
      var side = this.textDirection === 'rtl' ? 'right' : 'left'
       ,  autocompleteOptions = $.extend({
            minLength: this.options.showAutocompleteOnFocus ? 0 : null,
            position: { my: side + " top", at: side + " bottom", of: this.$wrapper }
          }, this.options.autocomplete )

      this.$input.autocomplete( autocompleteOptions )
    }

    // Initialize typeahead, if necessary
    if ( ! $.isEmptyObject( this.options.typeahead ) ) {

      var typeaheadOptions = this.options.typeahead
        , defaults = {
            minLength: this.options.showAutocompleteOnFocus ? 0 : null
          }
        , args = $.isArray( typeaheadOptions ) ? typeaheadOptions : [typeaheadOptions, typeaheadOptions]

      args[0] = $.extend( {}, defaults, args[0] )

      this.$input.typeahead.apply( this.$input, args )
      this.typeahead = true
    }
  }

  Tokenfield.prototype = {

    constructor: Tokenfield

  , createToken: function (attrs, triggerChange) {
      var _self = this

      if (typeof attrs === 'string') {
        attrs = { value: attrs, label: attrs }
      } else {
        // Copy objects to prevent contamination of data sources.
        attrs = $.extend( {}, attrs )
      }

      if (typeof triggerChange === 'undefined') {
         triggerChange = true
      }

      // Normalize label and value
      attrs.value = $.trim(attrs.value.toString());
      attrs.label = attrs.label && attrs.label.length ? $.trim(attrs.label) : attrs.value

      // Bail out if has no value or label, or label is too short
      if (!attrs.value.length || !attrs.label.length || attrs.label.length <= this.options.minLength) return

      // Bail out if maximum number of tokens is reached
      if (this.options.limit && this.getTokens().length >= this.options.limit) return

      // Allow changing token data before creating it
      var createEvent = $.Event('tokenfield:createtoken', { attrs: attrs })
      this.$element.trigger(createEvent)

      // Bail out if there if attributes are empty or event was defaultPrevented
      if (!createEvent.attrs || createEvent.isDefaultPrevented()) return

      var $token = $('<div class="token" />')
            .append('<span class="token-label" />')
            .append('<a href="#" class="close" tabindex="-1">&times;</a>')
            .data('attrs', attrs)

      // Insert token into HTML
      if (this.$input.hasClass('tt-input')) {
        // If the input has typeahead enabled, insert token before it's parent
        this.$input.parent().before( $token )
      } else {
        this.$input.before( $token )
      }

      // Temporarily set input width to minimum
      this.$input.css('width', this.options.minWidth + 'px')

      var $tokenLabel = $token.find('.token-label')
        , $closeButton = $token.find('.close')

      // Determine maximum possible token label width
      if (!this.maxTokenWidth) {
        this.maxTokenWidth =
          this.$wrapper.width() - $closeButton.outerWidth() -
          parseInt($closeButton.css('margin-left'), 10) -
          parseInt($closeButton.css('margin-right'), 10) -
          parseInt($token.css('border-left-width'), 10) -
          parseInt($token.css('border-right-width'), 10) -
          parseInt($token.css('padding-left'), 10) -
          parseInt($token.css('padding-right'), 10)
          parseInt($tokenLabel.css('border-left-width'), 10) -
          parseInt($tokenLabel.css('border-right-width'), 10) -
          parseInt($tokenLabel.css('padding-left'), 10) -
          parseInt($tokenLabel.css('padding-right'), 10)
          parseInt($tokenLabel.css('margin-left'), 10) -
          parseInt($tokenLabel.css('margin-right'), 10)
      }

      $tokenLabel.css('max-width', this.maxTokenWidth)
      if (this.options.html)
        $tokenLabel.html(attrs.label)
      else
        $tokenLabel.text(attrs.label)

      // Listen to events on token
      $token
        .on('mousedown',  function (e) {
          if (_self._disabled || _self._readonly) return false
          _self.preventDeactivation = true
        })
        .on('click',    function (e) {
          if (_self._disabled || _self._readonly) return false
          _self.preventDeactivation = false

          if (e.ctrlKey || e.metaKey) {
            e.preventDefault()
            return _self.toggle( $token )
          }

          _self.activate( $token, e.shiftKey, e.shiftKey )
        })
        .on('dblclick', function (e) {
          if (_self._disabled || _self._readonly || !_self.options.allowEditing ) return false
          _self.edit( $token )
        })

      $closeButton
          .on('click',  $.proxy(this.remove, this))

      // Trigger createdtoken event on the original field
      // indicating that the token is now in the DOM
      this.$element.trigger($.Event('tokenfield:createdtoken', {
        attrs: attrs,
        relatedTarget: $token.get(0)
      }))

      // Trigger change event on the original field
      if (triggerChange) {
        this.$element.val( this.getTokensList() ).trigger( $.Event('change', { initiator: 'tokenfield' }) )
      }

      // Update tokenfield dimensions
      var _self = this
      setTimeout(function () {
        _self.update()
      }, 0)

      // Return original element
      return this.$element.get(0)
    }

  , setTokens: function (tokens, add, triggerChange) {
      if (!add) this.$wrapper.find('.token').remove()

      if (!tokens) return

      if (typeof triggerChange === 'undefined') {
          triggerChange = true
      }

      if (typeof tokens === 'string') {
        if (this._delimiters.length) {
          // Split based on delimiters
          tokens = tokens.split( new RegExp( '[' + this._delimiters.join('') + ']' ) )
        } else {
          tokens = [tokens];
        }
      }

      var _self = this
      $.each(tokens, function (i, attrs) {
        _self.createToken(attrs, triggerChange)
      })

      return this.$element.get(0)
    }

  , getTokenData: function($token) {
      var data = $token.map(function() {
        var $token = $(this);
        return $token.data('attrs')
      }).get();

      if (data.length == 1) {
        data = data[0];
      }

      return data;
    }

  , getTokens: function(active) {
      var self = this
        , tokens = []
        , activeClass = active ? '.active' : '' // get active tokens only
      this.$wrapper.find( '.token' + activeClass ).each( function() {
        tokens.push( self.getTokenData( $(this) ) )
      })
      return tokens
  }

  , getTokensList: function(delimiter, beautify, active) {
      delimiter = delimiter || this._firstDelimiter
      beautify = ( typeof beautify !== 'undefined' && beautify !== null ) ? beautify : this.options.beautify

      var separator = delimiter + ( beautify && delimiter !== ' ' ? ' ' : '')
      return $.map( this.getTokens(active), function (token) {
        return token.value
      }).join(separator)
  }

  , getInput: function() {
    return this.$input.val()
  }
      
  , setInput: function (val) {
      if (this.$input.hasClass('tt-input')) {
          // Typeahead acts weird when simply setting input value to empty,
          // so we set the query to empty instead
          this.$input.typeahead('val', val)
      } else {
          this.$input.val(val)
      }
  }

  , listen: function () {
      var _self = this

      this.$element
        .on('change',   $.proxy(this.change, this))

      this.$wrapper
        .on('mousedown',$.proxy(this.focusInput, this))

      this.$input
        .on('focus',    $.proxy(this.focus, this))
        .on('blur',     $.proxy(this.blur, this))
        .on('paste',    $.proxy(this.paste, this))
        .on('keydown',  $.proxy(this.keydown, this))
        .on('keypress', $.proxy(this.keypress, this))
        .on('keyup',    $.proxy(this.keyup, this))

      this.$copyHelper
        .on('focus',    $.proxy(this.focus, this))
        .on('blur',     $.proxy(this.blur, this))
        .on('keydown',  $.proxy(this.keydown, this))
        .on('keyup',    $.proxy(this.keyup, this))

      // Secondary listeners for input width calculation
      this.$input
        .on('keypress', $.proxy(this.update, this))
        .on('keyup',    $.proxy(this.update, this))

      this.$input
        .on('autocompletecreate', function() {
          // Set minimum autocomplete menu width
          var $_menuElement = $(this).data('ui-autocomplete').menu.element

          var minWidth = _self.$wrapper.outerWidth() -
              parseInt( $_menuElement.css('border-left-width'), 10 ) -
              parseInt( $_menuElement.css('border-right-width'), 10 )

          $_menuElement.css( 'min-width', minWidth + 'px' )
        })
        .on('autocompleteselect', function (e, ui) {
          if (_self.createToken( ui.item )) {
            _self.$input.val('')
            if (_self.$input.data( 'edit' )) {
              _self.unedit(true)
            }
          }
          return false
        })
        .on('typeahead:selected typeahead:autocompleted', function (e, datum, dataset) {
          // Create token
          if (_self.createToken( datum )) {
            _self.$input.typeahead('val', '')
            if (_self.$input.data( 'edit' )) {
              _self.unedit(true)
            }
          }
        })

      // Listen to window resize
      $(window).on('resize', $.proxy(this.update, this ))

    }

  , keydown: function (e) {

      if (!this.focused) return

      var _self = this

      switch(e.keyCode) {
        case 8: // backspace
          if (!this.$input.is(document.activeElement)) break
          this.lastInputValue = this.$input.val()
          break

        case 37: // left arrow
          leftRight( this.textDirection === 'rtl' ? 'next': 'prev' )
          break

        case 38: // up arrow
          upDown('prev')
          break

        case 39: // right arrow
          leftRight( this.textDirection === 'rtl' ? 'prev': 'next' )
          break

        case 40: // down arrow
          upDown('next')
          break

        case 65: // a (to handle ctrl + a)
          if (this.$input.val().length > 0 || !(e.ctrlKey || e.metaKey)) break
          this.activateAll()
          e.preventDefault()
          break

        case 9: // tab
        case 13: // enter

          // We will handle creating tokens from autocomplete in autocomplete events
          if (this.$input.data('ui-autocomplete') && this.$input.data('ui-autocomplete').menu.element.find("li:has(a.ui-state-focus), li.ui-state-focus").length) break

          // We will handle creating tokens from typeahead in typeahead events
          if (this.$input.hasClass('tt-input') && this.$wrapper.find('.tt-cursor').length ) break
          if (this.$input.hasClass('tt-input') && this.$wrapper.find('.tt-hint').val() && this.$wrapper.find('.tt-hint').val().length) break

          // Create token
          if (this.$input.is(document.activeElement) && this.$input.val().length || this.$input.data('edit')) {
            return this.createTokensFromInput(e, this.$input.data('edit'));
          }

          // Edit token
          if (e.keyCode === 13) {
            if (!this.$copyHelper.is(document.activeElement) || this.$wrapper.find('.token.active').length !== 1) break
            if (!_self.options.allowEditing) break
            this.edit( this.$wrapper.find('.token.active') )
          }
      }

      function leftRight(direction) {
        if (_self.$input.is(document.activeElement)) {
          if (_self.$input.val().length > 0) return

          direction += 'All'
          var $token = _self.$input.hasClass('tt-input') ? _self.$input.parent()[direction]('.token:first') : _self.$input[direction]('.token:first')
          if (!$token.length) return

          _self.preventInputFocus = true
          _self.preventDeactivation = true

          _self.activate( $token )
          e.preventDefault()

        } else {
          _self[direction]( e.shiftKey )
          e.preventDefault()
        }
      }

      function upDown(direction) {
        if (!e.shiftKey) return

        if (_self.$input.is(document.activeElement)) {
          if (_self.$input.val().length > 0) return

          var $token = _self.$input.hasClass('tt-input') ? _self.$input.parent()[direction + 'All']('.token:first') : _self.$input[direction + 'All']('.token:first')
          if (!$token.length) return

          _self.activate( $token )
        }

        var opposite = direction === 'prev' ? 'next' : 'prev'
          , position = direction === 'prev' ? 'first' : 'last'

        _self.$firstActiveToken[opposite + 'All']('.token').each(function() {
          _self.deactivate( $(this) )
        })

        _self.activate( _self.$wrapper.find('.token:' + position), true, true )
        e.preventDefault()
      }

      this.lastKeyDown = e.keyCode
    }

  , keypress: function(e) {

      // Comma
      if ($.inArray( e.which, this._triggerKeys) !== -1 && this.$input.is(document.activeElement)) {
        if (this.$input.val()) {
          this.createTokensFromInput(e)
        }
        return false;
      }
    }

  , keyup: function (e) {
      this.preventInputFocus = false

      if (!this.focused) return

      switch(e.keyCode) {
        case 8: // backspace
          if (this.$input.is(document.activeElement)) {
            if (this.$input.val().length || this.lastInputValue.length && this.lastKeyDown === 8) break

            this.preventDeactivation = true
            var $prevToken = this.$input.hasClass('tt-input') ? this.$input.parent().prevAll('.token:first') : this.$input.prevAll('.token:first')

            if (!$prevToken.length) break

            this.activate( $prevToken )
          } else {
            this.remove(e)
          }
          break

        case 46: // delete
          this.remove(e, 'next')
          break
      }
      this.lastKeyUp = e.keyCode
    }

  , focus: function (e) {
      this.focused = true
      this.$wrapper.addClass('focus')

      if (this.$input.is(document.activeElement)) {
        this.$wrapper.find('.active').removeClass('active')
        this.$firstActiveToken = null

        if (this.options.showAutocompleteOnFocus) {
          this.search()
        }
      }
    }

  , blur: function (e) {

      this.focused = false
      this.$wrapper.removeClass('focus')

      if (!this.preventDeactivation && !this.$element.is(document.activeElement)) {
        this.$wrapper.find('.active').removeClass('active')
        this.$firstActiveToken = null
      }

      if (!this.preventCreateTokens && (this.$input.data('edit') && !this.$input.is(document.activeElement) || this.options.createTokensOnBlur )) {
        this.createTokensFromInput(e)
      }

      this.preventDeactivation = false
      this.preventCreateTokens = false
    }

  , paste: function (e) {
      var _self = this

      // Add tokens to existing ones
      if (_self.options.allowPasting) {
        setTimeout(function () {
          _self.createTokensFromInput(e)
        }, 1)
      }
    }

  , change: function (e) {
      if ( e.initiator === 'tokenfield' ) return // Prevent loops

      this.setTokens( this.$element.val() )
    }

  , createTokensFromInput: function (e, focus) {
      if (this.$input.val().length < this.options.minLength)
        return // No input, simply return

      var tokensBefore = this.getTokensList()
      this.setTokens( this.$input.val(), true )

      if (tokensBefore == this.getTokensList() && this.$input.val().length)
        return false // No tokens were added, do nothing (prevent form submit)

      this.setInput('')

      if (this.$input.data( 'edit' )) {
        this.unedit(focus)
      }

      return false // Prevent form being submitted
    }

  , next: function (add) {
      if (add) {
        var $firstActiveToken = this.$wrapper.find('.active:first')
          , deactivate = $firstActiveToken && this.$firstActiveToken ? $firstActiveToken.index() < this.$firstActiveToken.index() : false

        if (deactivate) return this.deactivate( $firstActiveToken )
      }

      var $lastActiveToken = this.$wrapper.find('.active:last')
        , $nextToken = $lastActiveToken.nextAll('.token:first')

      if (!$nextToken.length) {
        this.$input.focus()
        return
      }

      this.activate($nextToken, add)
    }

  , prev: function (add) {

      if (add) {
        var $lastActiveToken = this.$wrapper.find('.active:last')
          , deactivate = $lastActiveToken && this.$firstActiveToken ? $lastActiveToken.index() > this.$firstActiveToken.index() : false

        if (deactivate) return this.deactivate( $lastActiveToken )
      }

      var $firstActiveToken = this.$wrapper.find('.active:first')
        , $prevToken = $firstActiveToken.prevAll('.token:first')

      if (!$prevToken.length) {
        $prevToken = this.$wrapper.find('.token:first')
      }

      if (!$prevToken.length && !add) {
        this.$input.focus()
        return
      }

      this.activate( $prevToken, add )
    }

  , activate: function ($token, add, multi, remember) {

      if (!$token) return

      if (typeof remember === 'undefined') var remember = true

      if (multi) var add = true

      this.$copyHelper.focus()

      if (!add) {
        this.$wrapper.find('.active').removeClass('active')
        if (remember) {
          this.$firstActiveToken = $token
        } else {
          delete this.$firstActiveToken
        }
      }

      if (multi && this.$firstActiveToken) {
        // Determine first active token and the current tokens indicies
        // Account for the 1 hidden textarea by subtracting 1 from both
        var i = this.$firstActiveToken.index() - 2
          , a = $token.index() - 2
          , _self = this

        this.$wrapper.find('.token').slice( Math.min(i, a) + 1, Math.max(i, a) ).each( function() {
          _self.activate( $(this), true )
        })
      }

      $token.addClass('active')
      this.$copyHelper.val( this.getTokensList( null, null, true ) ).select()
    }

  , activateAll: function() {
      var _self = this

      this.$wrapper.find('.token').each( function (i) {
        _self.activate($(this), i !== 0, false, false)
      })
    }

  , deactivate: function($token) {
      if (!$token) return

      $token.removeClass('active')
      this.$copyHelper.val( this.getTokensList( null, null, true ) ).select()
    }

  , toggle: function($token) {
      if (!$token) return

      $token.toggleClass('active')
      this.$copyHelper.val( this.getTokensList( null, null, true ) ).select()
    }

  , edit: function ($token) {
      if (!$token) return

      var attrs = $token.data('attrs')

      // Allow changing input value before editing
      var options = { attrs: attrs, relatedTarget: $token.get(0) }
      var editEvent = $.Event('tokenfield:edittoken', options)
      this.$element.trigger( editEvent )

      // Edit event can be cancelled if default is prevented
      if (editEvent.isDefaultPrevented()) return

      $token.find('.token-label').text(attrs.value)
      var tokenWidth = $token.outerWidth()

      var $_input = this.$input.hasClass('tt-input') ? this.$input.parent() : this.$input

      $token.replaceWith( $_input )

      this.preventCreateTokens = true

      this.$input.val( attrs.value )
                .select()
                .data( 'edit', true )
                .width( tokenWidth )

      this.update();

      // Indicate that token is now being edited, and is replaced with an input field in the DOM
      this.$element.trigger($.Event('tokenfield:editedtoken', options ))
    }

  , unedit: function (focus) {
      var $_input = this.$input.hasClass('tt-input') ? this.$input.parent() : this.$input
      $_input.appendTo( this.$wrapper )

      this.$input.data('edit', false)
      this.$mirror.text('')

      this.update()

      // Because moving the input element around in DOM
      // will cause it to lose focus, we provide an option
      // to re-focus the input after appending it to the wrapper
      if (focus) {
        var _self = this
        setTimeout(function () {
          _self.$input.focus()
        }, 1)
      }
    }

  , remove: function (e, direction) {
      if (this.$input.is(document.activeElement) || this._disabled || this._readonly) return

      var $token = (e.type === 'click') ? $(e.target).closest('.token') : this.$wrapper.find('.token.active')

      if (e.type !== 'click') {
        if (!direction) var direction = 'prev'
        this[direction]()

        // Was it the first token?
        if (direction === 'prev') var firstToken = $token.first().prevAll('.token:first').length === 0
      }

      // Prepare events and their options
      var options = { attrs: this.getTokenData( $token ), relatedTarget: $token.get(0) }
        , removeEvent = $.Event('tokenfield:removetoken', options)

      this.$element.trigger(removeEvent);

      // Remove event can be intercepted and cancelled
      if (removeEvent.isDefaultPrevented()) return

      var removedEvent = $.Event('tokenfield:removedtoken', options)
        , changeEvent = $.Event('change', { initiator: 'tokenfield' })

      // Remove token from DOM
      $token.remove()

      // Trigger events
      this.$element.val( this.getTokensList() ).trigger( removedEvent ).trigger( changeEvent )

      // Focus, when necessary:
      // When there are no more tokens, or if this was the first token
      // and it was removed with backspace or it was clicked on
      if (!this.$wrapper.find('.token').length || e.type === 'click' || firstToken) this.$input.focus()

      // Adjust input width
      this.$input.css('width', this.options.minWidth + 'px')
      this.update()

      // Cancel original event handlers
      e.preventDefault()
      e.stopPropagation()
    }

    /**
     * Update tokenfield dimensions
     */
  , update: function (e) {
      var value = this.$input.val()
        , inputPaddingLeft = parseInt(this.$input.css('padding-left'), 10)
        , inputPaddingRight = parseInt(this.$input.css('padding-right'), 10)
        , inputPadding = inputPaddingLeft + inputPaddingRight

      if (this.$input.data('edit')) {

        if (!value) {
          value = this.$input.prop("placeholder")
        }
        if (value === this.$mirror.text()) return

        this.$mirror.text(value)

        var mirrorWidth = this.$mirror.width() + 10;
        if ( mirrorWidth > this.$wrapper.width() ) {
          return this.$input.width( this.$wrapper.width() )
        }

        this.$input.width( mirrorWidth )
      }
      else {
        //temporary reset width to minimal value to get proper results
        this.$input.width(this.options.minWidth);
        
        var w = (this.textDirection === 'rtl')
              ? this.$input.offset().left + this.$input.outerWidth() - this.$wrapper.offset().left - parseInt(this.$wrapper.css('padding-left'), 10) - inputPadding - 1
              : this.$wrapper.offset().left + this.$wrapper.width() + parseInt(this.$wrapper.css('padding-left'), 10) - this.$input.offset().left - inputPadding;
        //
        // some usecases pre-render widget before attaching to DOM,
        // dimensions returned by jquery will be NaN -> we default to 100%
        // so placeholder won't be cut off.
        isNaN(w) ? this.$input.width('100%') : this.$input.width(w);
      }
    }

  , focusInput: function (e) {
      if ( $(e.target).closest('.token').length || $(e.target).closest('.token-input').length || $(e.target).closest('.tt-dropdown-menu').length ) return
      // Focus only after the current call stack has cleared,
      // otherwise has no effect.
      // Reason: mousedown is too early - input will lose focus
      // after mousedown. However, since the input may be moved
      // in DOM, there may be no click or mouseup event triggered.
      var _self = this
      setTimeout(function() {
        _self.$input.focus()
      }, 0)
    }

  , search: function () {
      if ( this.$input.data('ui-autocomplete') ) {
        this.$input.autocomplete('search')
      }
    }

  , disable: function () {
      this.setProperty('disabled', true);
    }

  , enable: function () {
      this.setProperty('disabled', false);
    }

  , readonly: function () {
      this.setProperty('readonly', true);
    }

  , writeable: function () {
      this.setProperty('readonly', false);
    }

  , setProperty: function(property, value) {
      this['_' + property] = value;
      this.$input.prop(property, value);
      this.$element.prop(property, value);
      this.$wrapper[ value ? 'addClass' : 'removeClass' ](property);
  }

  , destroy: function() {
      // Set field value
      this.$element.val( this.getTokensList() );
      // Restore styles and properties
      this.$element.css( this.$element.data('original-styles') );
      this.$element.prop( 'tabindex', this.$element.data('original-tabindex') );

      // Re-route tokenfield label to original input
      var $label = $( 'label[for="' + this.$input.prop('id') + '"]' )
      if ( $label.length ) {
        $label.prop( 'for', this.$element.prop('id') )
      }

      // Move original element outside of tokenfield wrapper
      this.$element.insertBefore( this.$wrapper );

      // Remove tokenfield-related data
      this.$element.removeData('original-styles')
                   .removeData('original-tabindex')
                   .removeData('bs.tokenfield');

      // Remove tokenfield from DOM
      this.$wrapper.remove();
      this.$mirror.remove();

      var $_element = this.$element;

      return $_element;
  }

  }


 /* TOKENFIELD PLUGIN DEFINITION
  * ======================== */

  var old = $.fn.tokenfield

  $.fn.tokenfield = function (option, param) {
    var value
      , args = []

    Array.prototype.push.apply( args, arguments );

    var elements = this.each(function () {
      var $this = $(this)
        , data = $this.data('bs.tokenfield')
        , options = typeof option == 'object' && option

      if (typeof option === 'string' && data && data[option]) {
        args.shift()
        value = data[option].apply(data, args)
      } else {
        if (!data && typeof option !== 'string' && !param) {
          $this.data('bs.tokenfield', (data = new Tokenfield(this, options)))
          $this.trigger('tokenfield:initialize')
        }
      }
    })

    return typeof value !== 'undefined' ? value : elements;
  }

  $.fn.tokenfield.defaults = {
    minWidth: 60,
    minLength: 0,
    html: true,
    allowEditing: true,
    allowPasting: true,
    limit: 0,
    autocomplete: {},
    typeahead: {},
    showAutocompleteOnFocus: false,
    createTokensOnBlur: false,
    delimiter: ',',
    beautify: true,
    inputType: 'text'
  }

  $.fn.tokenfield.Constructor = Tokenfield


 /* TOKENFIELD NO CONFLICT
  * ================== */

  $.fn.tokenfield.noConflict = function () {
    $.fn.tokenfield = old
    return this
  }

  return Tokenfield;

}));
bower.json000066400000001532152434262010006557 0ustar00{
  "name": "bootstrap-tokenfield",
  "description": "Advanced tagging/tokenizing plugin for input fields with a focus on keyboard and copy-paste support.",
  "version": "0.12.1",
  "authors": [
    {
      "name": "ragulka",
      "homepage": "https://github.com/ragulka"
    },
    {
      "name": "sliptree",
      "homepage": "https://github.com/sliptree"
    }
  ],
  "homepage": "http://sliptree.github.io/bootstrap-tokenfield/",
  "main": [
    "dist/bootstrap-tokenfield.js",
    "dist/css/bootstrap-tokenfield.css"
  ],
  "keywords": [
    "jquery",
    "javascript",
    "bootstrap",
    "tokenfield",
    "tags",
    "token",
    "input",
    "select",
    "form"
  ],
  "dependencies": {
    "jquery": "~2.1.0",
    "bootstrap": "~3.1.1"
  },
  "devDependecies": {
    "mocha": "~1.12.*",
    "chai": "~1.7.*",
    "typeahead.js": "~0.10.1"
  }
}