|
|
|
@ -11,11 +11,17 @@
|
|
|
|
|
itemText: function(item) {
|
|
|
|
|
return this.itemValue(item);
|
|
|
|
|
},
|
|
|
|
|
itemTitle: function(item) {
|
|
|
|
|
return null;
|
|
|
|
|
},
|
|
|
|
|
freeInput: true,
|
|
|
|
|
addOnBlur: true,
|
|
|
|
|
maxTags: undefined,
|
|
|
|
|
maxChars: undefined,
|
|
|
|
|
confirmKeys: [13, 44],
|
|
|
|
|
delimiter: ',',
|
|
|
|
|
delimiterRegex: null,
|
|
|
|
|
cancelConfirmKeysOnEmpty: true,
|
|
|
|
|
onTagExists: function(item, $tag) {
|
|
|
|
|
$tag.hide().fadeIn();
|
|
|
|
|
},
|
|
|
|
@ -41,10 +47,8 @@
|
|
|
|
|
this.$container = $('<div class="bootstrap-tagsinput"></div>');
|
|
|
|
|
this.$input = $('<input type="text" placeholder="' + this.placeholderText + '"/>').appendTo(this.$container);
|
|
|
|
|
|
|
|
|
|
this.$element.after(this.$container);
|
|
|
|
|
this.$element.before(this.$container);
|
|
|
|
|
|
|
|
|
|
// var inputWidth = (this.inputSize < 3 ? 3 : this.inputSize) + "em";
|
|
|
|
|
// this.$input.get(0).style.cssText = "width: " + inputWidth + " !important;";
|
|
|
|
|
this.build(options);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -55,7 +59,7 @@
|
|
|
|
|
* Adds the given item as a new tag. Pass true to dontPushVal to prevent
|
|
|
|
|
* updating the elements val()
|
|
|
|
|
*/
|
|
|
|
|
add: function(item, dontPushVal) {
|
|
|
|
|
add: function(item, dontPushVal, options) {
|
|
|
|
|
var self = this;
|
|
|
|
|
|
|
|
|
|
if (self.options.maxTags && self.itemsArray.length >= self.options.maxTags)
|
|
|
|
@ -83,7 +87,8 @@
|
|
|
|
|
self.remove(self.itemsArray[0]);
|
|
|
|
|
|
|
|
|
|
if (typeof item === "string" && this.$element[0].tagName === 'INPUT') {
|
|
|
|
|
var items = item.split(',');
|
|
|
|
|
var delimiter = (self.options.delimiterRegex) ? self.options.delimiterRegex : self.options.delimiter;
|
|
|
|
|
var items = item.split(delimiter);
|
|
|
|
|
if (items.length > 1) {
|
|
|
|
|
for (var i = 0; i < items.length; i++) {
|
|
|
|
|
this.add(items[i], true);
|
|
|
|
@ -95,10 +100,10 @@
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
var itemValue = self.options.itemValue(item),
|
|
|
|
|
itemText = self.options.itemText(item),
|
|
|
|
|
tagClass = self.options.tagClass(item);
|
|
|
|
|
tagClass = self.options.tagClass(item),
|
|
|
|
|
itemTitle = self.options.itemTitle(item);
|
|
|
|
|
|
|
|
|
|
// Ignore items allready added
|
|
|
|
|
var existing = $.grep(self.itemsArray, function(item) { return self.options.itemValue(item) === itemValue; } )[0];
|
|
|
|
@ -114,56 +119,19 @@
|
|
|
|
|
// if length greater than limit
|
|
|
|
|
if (self.items().toString().length + item.length + 1 > self.options.maxInputLength)
|
|
|
|
|
return;
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
// raise beforeItemAdd arg
|
|
|
|
|
var beforeItemAddEvent = $.Event('beforeItemAdd', { item: item, cancel: false });
|
|
|
|
|
var beforeItemAddEvent = $.Event('beforeItemAdd', { item: item, cancel: false, options: options});
|
|
|
|
|
self.$element.trigger(beforeItemAddEvent);
|
|
|
|
|
if (beforeItemAddEvent.cancel)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
// register item in internal array and map
|
|
|
|
|
//self.itemsArray.push(item);
|
|
|
|
|
|
|
|
|
|
// read var beforeItemAddEvent with new value
|
|
|
|
|
var item = beforeItemAddEvent.item; // Get text from event (BeforeItemAddEvent)
|
|
|
|
|
var itemValue = self.options.itemValue(item),
|
|
|
|
|
itemText = self.options.itemText(item),
|
|
|
|
|
tagClass = self.options.tagClass(item);
|
|
|
|
|
|
|
|
|
|
// Ignore items allready added
|
|
|
|
|
var existing = $.grep(self.itemsArray, function(item) { return self.options.itemValue(item) === itemValue; } )[0];
|
|
|
|
|
if (existing && !self.options.allowDuplicates) {
|
|
|
|
|
// Invoke onTagExists
|
|
|
|
|
if (self.options.onTagExists) {
|
|
|
|
|
var $existingTag = $(".tag", self.$container).filter(function() { return $(this).data("item") === existing; });
|
|
|
|
|
self.options.onTagExists(item, $existingTag);
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// if length greater than limit
|
|
|
|
|
if (self.items().toString().length + item.length + 1 > self.options.maxInputLength)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// register item in internal array and map
|
|
|
|
|
self.itemsArray.push(item);
|
|
|
|
|
|
|
|
|
|
if (beforeItemAddEvent.tagClass !== undefined){ var tagClass = beforeItemAddEvent.tagClass; }
|
|
|
|
|
if (item != undefined){
|
|
|
|
|
var items = item.toString().split(',');
|
|
|
|
|
if (items.length > 1) {
|
|
|
|
|
for (var i = 0; i < items.length; i++) {
|
|
|
|
|
this.add(items[i], true);
|
|
|
|
|
}
|
|
|
|
|
if (!dontPushVal)
|
|
|
|
|
self.pushVal(self.options.triggerChange);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// add a tag element
|
|
|
|
|
var $tag = $('<span class="tag ' + htmlEncode(tagClass) + '">' + htmlEncode(itemText) + '<span data-role="remove"></span></span>');
|
|
|
|
|
|
|
|
|
|
var $tag = $('<span class="tag ' + htmlEncode(tagClass) + (itemTitle !== null ? ('" title="' + itemTitle) : '') + '">' + htmlEncode(itemText) + '<span data-role="remove"></span></span>');
|
|
|
|
|
$tag.data('item', item);
|
|
|
|
|
self.findInputWrapper().before($tag);
|
|
|
|
|
$tag.after(' ');
|
|
|
|
@ -183,14 +151,14 @@
|
|
|
|
|
if (self.options.maxTags === self.itemsArray.length || self.items().toString().length === self.options.maxInputLength)
|
|
|
|
|
self.$container.addClass('bootstrap-tagsinput-max');
|
|
|
|
|
|
|
|
|
|
self.$element.trigger($.Event('itemAdded', { item: item }));
|
|
|
|
|
self.$element.trigger($.Event('itemAdded', { item: item, options: options }));
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Removes the given item. Pass true to dontPushVal to prevent updating the
|
|
|
|
|
* elements val()
|
|
|
|
|
*/
|
|
|
|
|
remove: function(item, dontPushVal) {
|
|
|
|
|
remove: function(item, dontPushVal, options) {
|
|
|
|
|
var self = this;
|
|
|
|
|
|
|
|
|
|
if (self.objectItems) {
|
|
|
|
@ -203,7 +171,7 @@
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (item) {
|
|
|
|
|
var beforeItemRemoveEvent = $.Event('beforeItemRemove', { item: item, cancel: false });
|
|
|
|
|
var beforeItemRemoveEvent = $.Event('beforeItemRemove', { item: item, cancel: false, options: options });
|
|
|
|
|
self.$element.trigger(beforeItemRemoveEvent);
|
|
|
|
|
if (beforeItemRemoveEvent.cancel)
|
|
|
|
|
return;
|
|
|
|
@ -221,7 +189,7 @@
|
|
|
|
|
if (self.options.maxTags > self.itemsArray.length)
|
|
|
|
|
self.$container.removeClass('bootstrap-tagsinput-max');
|
|
|
|
|
|
|
|
|
|
self.$element.trigger($.Event('itemRemoved', { item: item }));
|
|
|
|
|
self.$element.trigger($.Event('itemRemoved', { item: item, options: options }));
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
@ -338,6 +306,7 @@
|
|
|
|
|
},
|
|
|
|
|
updater: function (text) {
|
|
|
|
|
self.add(this.map[text]);
|
|
|
|
|
return this.map[text];
|
|
|
|
|
},
|
|
|
|
|
matcher: function (text) {
|
|
|
|
|
return (text.toLowerCase().indexOf(this.query.trim().toLowerCase()) !== -1);
|
|
|
|
@ -354,11 +323,21 @@
|
|
|
|
|
|
|
|
|
|
// typeahead.js
|
|
|
|
|
if (self.options.typeaheadjs) {
|
|
|
|
|
var typeaheadjs = self.options.typeaheadjs || {};
|
|
|
|
|
var typeaheadConfig = null;
|
|
|
|
|
var typeaheadDatasets = {};
|
|
|
|
|
|
|
|
|
|
// Determine if main configurations were passed or simply a dataset
|
|
|
|
|
var typeaheadjs = self.options.typeaheadjs;
|
|
|
|
|
if ($.isArray(typeaheadjs)) {
|
|
|
|
|
typeaheadConfig = typeaheadjs[0];
|
|
|
|
|
typeaheadDatasets = typeaheadjs[1];
|
|
|
|
|
} else {
|
|
|
|
|
typeaheadDatasets = typeaheadjs;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
self.$input.typeahead(null, typeaheadjs).on('typeahead:selected', $.proxy(function (obj, datum) {
|
|
|
|
|
if (typeaheadjs.valueKey)
|
|
|
|
|
self.add(datum[typeaheadjs.valueKey]);
|
|
|
|
|
self.$input.typeahead(typeaheadConfig, typeaheadDatasets).on('typeahead:selected', $.proxy(function (obj, datum) {
|
|
|
|
|
if (typeaheadDatasets.valueKey)
|
|
|
|
|
self.add(datum[typeaheadDatasets.valueKey]);
|
|
|
|
|
else
|
|
|
|
|
self.add(datum);
|
|
|
|
|
self.$input.typeahead('val', '');
|
|
|
|
@ -398,7 +377,7 @@
|
|
|
|
|
case 8:
|
|
|
|
|
if (doGetCaretPosition($input[0]) === 0) {
|
|
|
|
|
var prev = $inputWrapper.prev();
|
|
|
|
|
if (prev) {
|
|
|
|
|
if (prev.length) {
|
|
|
|
|
self.remove(prev.data('item'));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -408,7 +387,7 @@
|
|
|
|
|
case 46:
|
|
|
|
|
if (doGetCaretPosition($input[0]) === 0) {
|
|
|
|
|
var next = $inputWrapper.next();
|
|
|
|
|
if (next) {
|
|
|
|
|
if (next.length) {
|
|
|
|
|
self.remove(next.data('item'));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -454,10 +433,17 @@
|
|
|
|
|
var text = $input.val(),
|
|
|
|
|
maxLengthReached = self.options.maxChars && text.length >= self.options.maxChars;
|
|
|
|
|
if (self.options.freeInput && (keyCombinationInList(event, self.options.confirmKeys) || maxLengthReached)) {
|
|
|
|
|
// Only attempt to add a tag if there is data in the field
|
|
|
|
|
if (text.length !== 0) {
|
|
|
|
|
self.add(maxLengthReached ? text.substr(0, self.options.maxChars) : text);
|
|
|
|
|
$input.val('');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If the field is empty, let the event triggered fire as usual
|
|
|
|
|
if (self.options.cancelConfirmKeysOnEmpty === false) {
|
|
|
|
|
event.preventDefault();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Reset internal input's size
|
|
|
|
|
var textLength = $input.val().length,
|
|
|
|
@ -532,7 +518,7 @@
|
|
|
|
|
/**
|
|
|
|
|
* Register JQuery plugin
|
|
|
|
|
*/
|
|
|
|
|
$.fn.tagsinput = function(arg1, arg2) {
|
|
|
|
|
$.fn.tagsinput = function(arg1, arg2, arg3) {
|
|
|
|
|
var results = [];
|
|
|
|
|
|
|
|
|
|
this.each(function() {
|
|
|
|
@ -555,7 +541,11 @@
|
|
|
|
|
results.push(tagsinput);
|
|
|
|
|
} else if(tagsinput[arg1] !== undefined) {
|
|
|
|
|
// Invoke function on existing tags input
|
|
|
|
|
if(tagsinput[arg1].length === 3 && arg3 !== undefined){
|
|
|
|
|
var retVal = tagsinput[arg1](arg2, null, arg3);
|
|
|
|
|
}else{
|
|
|
|
|
var retVal = tagsinput[arg1](arg2);
|
|
|
|
|
}
|
|
|
|
|
if (retVal !== undefined)
|
|
|
|
|
results.push(retVal);
|
|
|
|
|
}
|
|
|
|
|