/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">×</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">×</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}); |