From 295536ae3092ce43e3b5e130878db34dd945101b Mon Sep 17 00:00:00 2001 From: Mitchell Cash Date: Tue, 13 Jun 2017 21:15:43 +1000 Subject: [PATCH] Updated: Bootstrap Tags Input (#1674) --- src/UI/Content/bootstrap.tagsinput.less | 0 src/UI/JsLibraries/bootstrap.tagsinput.js | 124 ++++++++++------------ 2 files changed, 57 insertions(+), 67 deletions(-) mode change 100644 => 100755 src/UI/Content/bootstrap.tagsinput.less mode change 100644 => 100755 src/UI/JsLibraries/bootstrap.tagsinput.js diff --git a/src/UI/Content/bootstrap.tagsinput.less b/src/UI/Content/bootstrap.tagsinput.less old mode 100644 new mode 100755 diff --git a/src/UI/JsLibraries/bootstrap.tagsinput.js b/src/UI/JsLibraries/bootstrap.tagsinput.js old mode 100644 new mode 100755 index c48401bd8..2b403f779 --- a/src/UI/JsLibraries/bootstrap.tagsinput.js +++ b/src/UI/JsLibraries/bootstrap.tagsinput.js @@ -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 = $('
'); this.$input = $('').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 = $('' + htmlEncode(itemText) + ''); + + var $tag = $('' + htmlEncode(itemText) + ''); $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 })); }, /** @@ -300,7 +268,7 @@ makeOptionItemFunction(self.options, 'itemValue'); makeOptionItemFunction(self.options, 'itemText'); makeOptionFunction(self.options, 'tagClass'); - + // Typeahead Bootstrap version 2.3.2 if (self.options.typeahead) { var typeahead = self.options.typeahead || {}; @@ -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 || {}; - - self.$input.typeahead(null, typeaheadjs).on('typeahead:selected', $.proxy(function (obj, datum) { - if (typeaheadjs.valueKey) - self.add(datum[typeaheadjs.valueKey]); + 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(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', ''); @@ -382,7 +361,7 @@ } }, self)); } - + self.$container.on('keydown', 'input', $.proxy(function(event) { var $input = $(event.target), @@ -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,9 +433,16 @@ var text = $input.val(), maxLengthReached = self.options.maxChars && text.length >= self.options.maxChars; if (self.options.freeInput && (keyCombinationInList(event, self.options.confirmKeys) || maxLengthReached)) { - self.add(maxLengthReached ? text.substr(0, self.options.maxChars) : text); - $input.val(''); - event.preventDefault(); + // 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 @@ -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 - var retVal = tagsinput[arg1](arg2); + 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); } @@ -618,7 +608,7 @@ } /** - * Returns boolean indicates whether user has pressed an expected key combination. + * Returns boolean indicates whether user has pressed an expected key combination. * @param object keyPressEvent: JavaScript event object, refer * http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html * @param object lookupList: expected key combinations, as in: