scratch

Subversion Repositories:
Compare Path: Rev
With Path: Rev
?path1? @ 133  →  ?path2? @ 134
/bower_components/bootstrap-tokenfield/.bower.json
@@ -0,0 +1,50 @@
{
"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"
},
"_release": "0.12.1",
"_resolution": {
"type": "version",
"tag": "v0.12.1",
"commit": "75302a3fb57dcb4979b9327fdb0457e7f1ea9fdb"
},
"_source": "https://github.com/sliptree/bootstrap-tokenfield.git",
"_target": "^0.12.1",
"_originalSource": "bootstrap-tokenfield",
"_direct": true
}
/bower_components/bootstrap-tokenfield/.gitignore
@@ -0,0 +1,7 @@
/_site/
/bower_components/
/node_modules/
/tmp/
*.tgz
*.sublime-project
*.sublime-workspace
/bower_components/bootstrap-tokenfield/.npmignore
@@ -0,0 +1,5 @@
/_site/
/bower_components/
/*.tgz
/tmp/
/.travis.yml
/bower_components/bootstrap-tokenfield/.travis.yml
@@ -0,0 +1,5 @@
language: node_js
node_js: ["0.10"]
 
notifications:
email: ["illimar@sliptree.com"]
/bower_components/bootstrap-tokenfield/CONTRIBUTING.md
@@ -0,0 +1,142 @@
# 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.
/bower_components/bootstrap-tokenfield/Gruntfile.js
@@ -0,0 +1,200 @@
module.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']);
}
/bower_components/bootstrap-tokenfield/LICENSE.md
@@ -0,0 +1,23 @@
#### 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.
/bower_components/bootstrap-tokenfield/README.md
@@ -0,0 +1,153 @@
Bootstrap 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
/bower_components/bootstrap-tokenfield/_config.yml
@@ -0,0 +1,4 @@
safe: 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]
/bower_components/bootstrap-tokenfield/bootstrap-tokenfield.jquery.json
@@ -0,0 +1,35 @@
{
"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"
}
}
/bower_components/bootstrap-tokenfield/bower.json
@@ -0,0 +1,40 @@
{
"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"
}
}
/bower_components/bootstrap-tokenfield/dist/bootstrap-tokenfield.js
@@ -0,0 +1,1029 @@
/*!
* 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
.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 )
}
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);
}
}
 
, 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;
 
}));
/bower_components/bootstrap-tokenfield/dist/bootstrap-tokenfield.min.js
@@ -0,0 +1,7 @@
/*!
* 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});
/bower_components/bootstrap-tokenfield/dist/css/bootstrap-tokenfield.css
@@ -0,0 +1,209 @@
/*!
* 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 {
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;
}
/bower_components/bootstrap-tokenfield/dist/css/bootstrap-tokenfield.min.css
@@ -0,0 +1,5 @@
/*!
* 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{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}
/bower_components/bootstrap-tokenfield/dist/css/tokenfield-typeahead.css
@@ -0,0 +1,141 @@
/*!
* 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;
}
/bower_components/bootstrap-tokenfield/dist/css/tokenfield-typeahead.min.css
@@ -0,0 +1,5 @@
/*!
* 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}
/bower_components/bootstrap-tokenfield/docs-assets/css/docs.css
@@ -0,0 +1,1117 @@
/*
* 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;
}
/bower_components/bootstrap-tokenfield/docs-assets/css/pygments-manni.css
@@ -0,0 +1,66 @@
.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; }
/bower_components/bootstrap-tokenfield/docs-assets/js/affix.js
@@ -0,0 +1,137 @@
/* ========================================================================
* 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);
/bower_components/bootstrap-tokenfield/docs-assets/js/docs.js
@@ -0,0 +1,94 @@
jQuery(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()
 
});
/bower_components/bootstrap-tokenfield/docs-assets/js/docs.min.js
@@ -0,0 +1,7 @@
/*!
* 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()});
/bower_components/bootstrap-tokenfield/docs-assets/js/scrollspy.js
@@ -0,0 +1,153 @@
/* ========================================================================
* 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);
/bower_components/bootstrap-tokenfield/docs-assets/js/typeahead.bundle.js
@@ -0,0 +1,1658 @@
/*!
* 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);
/bower_components/bootstrap-tokenfield/docs-assets/js/typeahead.bundle.min.js
@@ -0,0 +1,7 @@
/*!
* 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);
/bower_components/bootstrap-tokenfield/index.html
@@ -0,0 +1,661 @@
---
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>
/bower_components/bootstrap-tokenfield/js/bootstrap-tokenfield.js
@@ -0,0 +1,1029 @@
/*!
* 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
.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 )
}
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);
}
}
 
, 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;
 
}));
/bower_components/bootstrap-tokenfield/less/bootstrap-tokenfield.less
@@ -0,0 +1,240 @@
/*!
* 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 {
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;
}
/bower_components/bootstrap-tokenfield/less/tokenfield-typeahead.less
@@ -0,0 +1,142 @@
/*!
* 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;
}
/bower_components/bootstrap-tokenfield/package.json
@@ -0,0 +1,56 @@
{
"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"
}
}
/bower_components/bootstrap-tokenfield/test/README.md
@@ -0,0 +1,22 @@
Testing
=======
 
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.
/bower_components/bootstrap-tokenfield/test/helpers/jsdom-patch.js
@@ -0,0 +1,79 @@
/**
* 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);
}
};
}
/bower_components/bootstrap-tokenfield/test/setup.js
@@ -0,0 +1,65 @@
var 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;
});
/bower_components/bootstrap-tokenfield/test/test.tokenfield.1.unit.js
@@ -0,0 +1,431 @@
describe('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();
});
 
});
});
 
});
/bower_components/bootstrap-tokenfield/test/test.tokenfield.2.integration.js
@@ -0,0 +1,1028 @@
describe('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();
});
});
 
});
 
});