bootstrap5-tagsinput-rails 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE.txt +22 -0
- data/README.md +66 -0
- data/lib/bootstrap5/tagsinput/rails.rb +10 -0
- data/lib/bootstrap5/tagsinput/rails/version.rb +7 -0
- data/vendor/assets/javascripts/bootstrap-tagsinput-angular.js +92 -0
- data/vendor/assets/javascripts/bootstrap-tagsinput-angular.min.js +7 -0
- data/vendor/assets/javascripts/bootstrap-tagsinput-angular.min.js.map +1 -0
- data/vendor/assets/javascripts/bootstrap-tagsinput.js +677 -0
- data/vendor/assets/javascripts/bootstrap-tagsinput.min.js +7 -0
- data/vendor/assets/javascripts/bootstrap-tagsinput.min.js.map +1 -0
- data/vendor/assets/stylesheets/bootstrap-tagsinput-typeahead.css +54 -0
- data/vendor/assets/stylesheets/bootstrap-tagsinput.css +60 -0
- data/vendor/assets/stylesheets/bootstrap-tagsinput.less +50 -0
- metadata +99 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: d65e5aaf283900d8a80ecb68f6965ffd47a79699
|
4
|
+
data.tar.gz: e39fbfa7399e72cf32e461fac62fa2f575b1218d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 3c0f427e0b4977e27526ed6c3d2e8cd1f6f76cd22e1440f53824c234aa7dff0fc0627c76ba0f42b64f55ebefa433a97895f7503cab01f98be6b32457c6781654
|
7
|
+
data.tar.gz: 3a5b73ac09164cea4f9fd0a387accdba81d7a643d4f5ecc6f7b71c44451b0426a10fdcd81fb459dfd5ecb4902d73fd744daac8c0d16f52c900b23808c38feb5a
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Hyo Seong Choi
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
# Bootstrap5::Tagsinput::Rails
|
2
|
+
|
3
|
+
Bootstrap 5 compatible bootstrap-tagsinput-rails. Uses bootstrap-tagsinput 0.8.
|
4
|
+
|
5
|
+
## Compatibility
|
6
|
+
|
7
|
+
Tested on Bootstrap 5.0.0-beta3
|
8
|
+
|
9
|
+
## Installation
|
10
|
+
|
11
|
+
Add this line to your application's Gemfile:
|
12
|
+
|
13
|
+
gem 'bootstrap-tagsinput-rails'
|
14
|
+
|
15
|
+
And then execute:
|
16
|
+
|
17
|
+
$ bundle
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
|
21
|
+
$ gem install bootstrap-tagsinput-rails
|
22
|
+
|
23
|
+
## Usage
|
24
|
+
|
25
|
+
in app/assets/application.js
|
26
|
+
|
27
|
+
```
|
28
|
+
//= require bootstrap-tagsinput
|
29
|
+
```
|
30
|
+
|
31
|
+
in app/assets/application.css
|
32
|
+
|
33
|
+
```
|
34
|
+
*= require bootstrap-tagsinput
|
35
|
+
```
|
36
|
+
|
37
|
+
in form view, you should add `data-role='tagsinput'` within input tag as the follows: for example, in `simple-form` view template,
|
38
|
+
|
39
|
+
```
|
40
|
+
<%= f.input :tag_list, input_html:{data:{role:'tagsinput'}} %>
|
41
|
+
```
|
42
|
+
|
43
|
+
Or if using Rails 4 with Bootstrap, use the following,
|
44
|
+
|
45
|
+
```
|
46
|
+
<%= f.text_field :tag_list, 'data-role'=>'tagsinput' %>
|
47
|
+
```
|
48
|
+
|
49
|
+
That's it
|
50
|
+
|
51
|
+
## Contributing
|
52
|
+
|
53
|
+
1. Fork it
|
54
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
55
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
56
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
57
|
+
5. Create new Pull Request
|
58
|
+
|
59
|
+
|
60
|
+
## Credits
|
61
|
+
|
62
|
+
[bootstrap-tagsinput](https://github.com/bootstrap-tagsinput/bootstrap-tagsinput) - Original source
|
63
|
+
|
64
|
+
[bootstrap-tagsinput-rails](https://github.com/luciuschoi/bootstrap-tagsinput-rails) - Original gemified Rails source
|
65
|
+
|
66
|
+
[Tim Ville's bootstrap-tagsinput-rails fork](https://github.com/TimVille/bootstrap-tagsinput-rails) - Bootstrap 4 compatible version
|
@@ -0,0 +1,92 @@
|
|
1
|
+
/*
|
2
|
+
* bootstrap-tagsinput v0.8.0
|
3
|
+
*
|
4
|
+
*/
|
5
|
+
|
6
|
+
angular.module('bootstrap-tagsinput', [])
|
7
|
+
.directive('bootstrapTagsinput', [function() {
|
8
|
+
|
9
|
+
function getItemProperty(scope, property) {
|
10
|
+
if (!property)
|
11
|
+
return undefined;
|
12
|
+
|
13
|
+
if (angular.isFunction(scope.$parent[property]))
|
14
|
+
return scope.$parent[property];
|
15
|
+
|
16
|
+
return function(item) {
|
17
|
+
return item[property];
|
18
|
+
};
|
19
|
+
}
|
20
|
+
|
21
|
+
return {
|
22
|
+
restrict: 'EA',
|
23
|
+
scope: {
|
24
|
+
model: '=ngModel'
|
25
|
+
},
|
26
|
+
template: '<select multiple></select>',
|
27
|
+
replace: false,
|
28
|
+
link: function(scope, element, attrs) {
|
29
|
+
$(function() {
|
30
|
+
if (!angular.isArray(scope.model))
|
31
|
+
scope.model = [];
|
32
|
+
|
33
|
+
var select = $('select', element);
|
34
|
+
var typeaheadSourceArray = attrs.typeaheadSource ? attrs.typeaheadSource.split('.') : null;
|
35
|
+
var typeaheadSource = typeaheadSourceArray ?
|
36
|
+
(typeaheadSourceArray.length > 1 ?
|
37
|
+
scope.$parent[typeaheadSourceArray[0]][typeaheadSourceArray[1]]
|
38
|
+
: scope.$parent[typeaheadSourceArray[0]])
|
39
|
+
: null;
|
40
|
+
|
41
|
+
select.tagsinput(scope.$parent[attrs.options || ''] || {
|
42
|
+
typeahead : {
|
43
|
+
source : angular.isFunction(typeaheadSource) ? typeaheadSource : null
|
44
|
+
},
|
45
|
+
itemValue: getItemProperty(scope, attrs.itemvalue),
|
46
|
+
itemText : getItemProperty(scope, attrs.itemtext),
|
47
|
+
confirmKeys : getItemProperty(scope, attrs.confirmkeys) ? JSON.parse(attrs.confirmkeys) : [13],
|
48
|
+
tagClass : angular.isFunction(scope.$parent[attrs.tagclass]) ? scope.$parent[attrs.tagclass] : function(item) { return attrs.tagclass; }
|
49
|
+
});
|
50
|
+
|
51
|
+
for (var i = 0; i < scope.model.length; i++) {
|
52
|
+
select.tagsinput('add', scope.model[i]);
|
53
|
+
}
|
54
|
+
|
55
|
+
select.on('itemAdded', function(event) {
|
56
|
+
if (scope.model.indexOf(event.item) === -1)
|
57
|
+
scope.model.push(event.item);
|
58
|
+
});
|
59
|
+
|
60
|
+
select.on('itemRemoved', function(event) {
|
61
|
+
var idx = scope.model.indexOf(event.item);
|
62
|
+
if (idx !== -1)
|
63
|
+
scope.model.splice(idx, 1);
|
64
|
+
});
|
65
|
+
|
66
|
+
// create a shallow copy of model's current state, needed to determine
|
67
|
+
// diff when model changes
|
68
|
+
var prev = scope.model.slice();
|
69
|
+
scope.$watch("model", function() {
|
70
|
+
var added = scope.model.filter(function(i) {return prev.indexOf(i) === -1;}),
|
71
|
+
removed = prev.filter(function(i) {return scope.model.indexOf(i) === -1;}),
|
72
|
+
i;
|
73
|
+
|
74
|
+
prev = scope.model.slice();
|
75
|
+
|
76
|
+
// Remove tags no longer in binded model
|
77
|
+
for (i = 0; i < removed.length; i++) {
|
78
|
+
select.tagsinput('remove', removed[i]);
|
79
|
+
}
|
80
|
+
|
81
|
+
// Refresh remaining tags
|
82
|
+
select.tagsinput('refresh');
|
83
|
+
|
84
|
+
// Add new items in model as tags
|
85
|
+
for (i = 0; i < added.length; i++) {
|
86
|
+
select.tagsinput('add', added[i]);
|
87
|
+
}
|
88
|
+
}, true);
|
89
|
+
});
|
90
|
+
}
|
91
|
+
};
|
92
|
+
}]);
|
@@ -0,0 +1,7 @@
|
|
1
|
+
/*
|
2
|
+
* bootstrap-tagsinput v0.8.0
|
3
|
+
*
|
4
|
+
*/
|
5
|
+
|
6
|
+
angular.module("bootstrap-tagsinput",[]).directive("bootstrapTagsinput",[function(){function a(a,b){if(b)return angular.isFunction(a.$parent[b])?a.$parent[b]:function(a){return a[b]}}return{restrict:"EA",scope:{model:"=ngModel"},template:"<select multiple></select>",replace:!1,link:function(b,c,d){$(function(){angular.isArray(b.model)||(b.model=[]);var e=$("select",c),f=d.typeaheadSource?d.typeaheadSource.split("."):null,g=f?f.length>1?b.$parent[f[0]][f[1]]:b.$parent[f[0]]:null;e.tagsinput(b.$parent[d.options||""]||{typeahead:{source:angular.isFunction(g)?g:null},itemValue:a(b,d.itemvalue),itemText:a(b,d.itemtext),confirmKeys:a(b,d.confirmkeys)?JSON.parse(d.confirmkeys):[13],tagClass:angular.isFunction(b.$parent[d.tagclass])?b.$parent[d.tagclass]:function(a){return d.tagclass}});for(var h=0;h<b.model.length;h++)e.tagsinput("add",b.model[h]);e.on("itemAdded",function(a){b.model.indexOf(a.item)===-1&&b.model.push(a.item)}),e.on("itemRemoved",function(a){var c=b.model.indexOf(a.item);c!==-1&&b.model.splice(c,1)});var i=b.model.slice();b.$watch("model",function(){var a,c=b.model.filter(function(a){return i.indexOf(a)===-1}),d=i.filter(function(a){return b.model.indexOf(a)===-1});for(i=b.model.slice(),a=0;a<d.length;a++)e.tagsinput("remove",d[a]);for(e.tagsinput("refresh"),a=0;a<c.length;a++)e.tagsinput("add",c[a])},!0)})}}}]);
|
7
|
+
//# sourceMappingURL=bootstrap-tagsinput-angular.min.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"sources":["../src/bootstrap-tagsinput-angular.js"],"names":["angular","module","directive","getItemProperty","scope","property","isFunction","$parent","item","restrict","model","template","replace","link","element","attrs","$","isArray","select","typeaheadSourceArray","typeaheadSource","split","length","tagsinput","options","typeahead","source","itemValue","itemvalue","itemText","itemtext","confirmKeys","confirmkeys","JSON","parse","tagClass","tagclass","i","on","event","indexOf","push","idx","splice","prev","slice","$watch","added","filter","removed"],"mappings":";;;;;AAAAA,QAAQC,OAAO,0BACdC,UAAU,sBAAuB,WAEhC,QAASC,GAAgBC,EAAOC,GAC9B,GAAKA,EAGL,MAAIL,SAAQM,WAAWF,EAAMG,QAAQF,IAC5BD,EAAMG,QAAQF,GAEhB,SAASG,GACd,MAAOA,GAAKH,IAIhB,OACEI,SAAU,KACVL,OACEM,MAAO,YAETC,SAAU,6BACVC,SAAS,EACTC,KAAM,SAAST,EAAOU,EAASC,GAC7BC,EAAE,WACKhB,QAAQiB,QAAQb,EAAMM,SACzBN,EAAMM,SAER,IAAIQ,GAASF,EAAE,SAAUF,GACrBK,EAAuBJ,EAAMK,gBAAkBL,EAAMK,gBAAgBC,MAAM,KAAO,KAClFD,EAAkBD,EACjBA,EAAqBG,OAAS,EAC3BlB,EAAMG,QAAQY,EAAqB,IAAIA,EAAqB,IAC1Df,EAAMG,QAAQY,EAAqB,IACvC,IAEND,GAAOK,UAAUnB,EAAMG,QAAQQ,EAAMS,SAAW,MAC9CC,WACEC,OAAW1B,QAAQM,WAAWc,GAAmBA,EAAkB,MAErEO,UAAWxB,EAAgBC,EAAOW,EAAMa,WACxCC,SAAW1B,EAAgBC,EAAOW,EAAMe,UACxCC,YAAc5B,EAAgBC,EAAOW,EAAMiB,aAAeC,KAAKC,MAAMnB,EAAMiB,cAAgB,IAC3FG,SAAWnC,QAAQM,WAAWF,EAAMG,QAAQQ,EAAMqB,WAAahC,EAAMG,QAAQQ,EAAMqB,UAAY,SAAS5B,GAAQ,MAAOO,GAAMqB,WAG/H,KAAK,GAAIC,GAAI,EAAGA,EAAIjC,EAAMM,MAAMY,OAAQe,IACtCnB,EAAOK,UAAU,MAAOnB,EAAMM,MAAM2B,GAGtCnB,GAAOoB,GAAG,YAAa,SAASC,GAC1BnC,EAAMM,MAAM8B,QAAQD,EAAM/B,SAAU,GACtCJ,EAAMM,MAAM+B,KAAKF,EAAM/B,QAG3BU,EAAOoB,GAAG,cAAe,SAASC,GAChC,GAAIG,GAAMtC,EAAMM,MAAM8B,QAAQD,EAAM/B,KAChCkC,MAAQ,GACVtC,EAAMM,MAAMiC,OAAOD,EAAK,IAK5B,IAAIE,GAAOxC,EAAMM,MAAMmC,OACvBzC,GAAM0C,OAAO,QAAS,WACpB,GAEIT,GAFAU,EAAQ3C,EAAMM,MAAMsC,OAAO,SAASX,GAAI,MAAOO,GAAKJ,QAAQH,MAAO,IACnEY,EAAUL,EAAKI,OAAO,SAASX,GAAI,MAAOjC,GAAMM,MAAM8B,QAAQH,MAAO,GAMzE,KAHAO,EAAOxC,EAAMM,MAAMmC,QAGdR,EAAI,EAAGA,EAAIY,EAAQ3B,OAAQe,IAC9BnB,EAAOK,UAAU,SAAU0B,EAAQZ,GAOrC,KAHAnB,EAAOK,UAAU,WAGZc,EAAI,EAAGA,EAAIU,EAAMzB,OAAQe,IAC5BnB,EAAOK,UAAU,MAAOwB,EAAMV,MAE/B","file":"bootstrap-tagsinput-angular.min.js"}
|
@@ -0,0 +1,677 @@
|
|
1
|
+
/*
|
2
|
+
* bootstrap-tagsinput v0.8.0
|
3
|
+
*
|
4
|
+
*/
|
5
|
+
|
6
|
+
(function ($) {
|
7
|
+
"use strict";
|
8
|
+
|
9
|
+
var defaultOptions = {
|
10
|
+
tagClass: function(item) {
|
11
|
+
return 'badge bg-info';
|
12
|
+
},
|
13
|
+
focusClass: 'focus',
|
14
|
+
itemValue: function(item) {
|
15
|
+
return item ? item.toString() : item;
|
16
|
+
},
|
17
|
+
itemText: function(item) {
|
18
|
+
return this.itemValue(item);
|
19
|
+
},
|
20
|
+
itemTitle: function(item) {
|
21
|
+
return null;
|
22
|
+
},
|
23
|
+
freeInput: true,
|
24
|
+
addOnBlur: true,
|
25
|
+
maxTags: undefined,
|
26
|
+
maxChars: undefined,
|
27
|
+
confirmKeys: [13, 44],
|
28
|
+
delimiter: ',',
|
29
|
+
delimiterRegex: null,
|
30
|
+
cancelConfirmKeysOnEmpty: false,
|
31
|
+
onTagExists: function(item, $tag) {
|
32
|
+
$tag.hide().fadeIn();
|
33
|
+
},
|
34
|
+
trimValue: false,
|
35
|
+
allowDuplicates: false,
|
36
|
+
triggerChange: true
|
37
|
+
};
|
38
|
+
|
39
|
+
/**
|
40
|
+
* Constructor function
|
41
|
+
*/
|
42
|
+
function TagsInput(element, options) {
|
43
|
+
this.isInit = true;
|
44
|
+
this.itemsArray = [];
|
45
|
+
|
46
|
+
this.$element = $(element);
|
47
|
+
this.$element.hide();
|
48
|
+
|
49
|
+
this.isSelect = (element.tagName === 'SELECT');
|
50
|
+
this.multiple = (this.isSelect && element.hasAttribute('multiple'));
|
51
|
+
this.objectItems = options && options.itemValue;
|
52
|
+
this.placeholderText = element.hasAttribute('placeholder') ? this.$element.attr('placeholder') : '';
|
53
|
+
this.inputSize = Math.max(1, this.placeholderText.length);
|
54
|
+
|
55
|
+
this.$container = $('<div class="bootstrap-tagsinput"></div>');
|
56
|
+
this.$input = $('<input type="text" placeholder="' + this.placeholderText + '"/>').appendTo(this.$container);
|
57
|
+
|
58
|
+
this.$element.before(this.$container);
|
59
|
+
|
60
|
+
this.build(options);
|
61
|
+
this.isInit = false;
|
62
|
+
}
|
63
|
+
|
64
|
+
TagsInput.prototype = {
|
65
|
+
constructor: TagsInput,
|
66
|
+
|
67
|
+
/**
|
68
|
+
* Adds the given item as a new tag. Pass true to dontPushVal to prevent
|
69
|
+
* updating the elements val()
|
70
|
+
*/
|
71
|
+
add: function(item, dontPushVal, options) {
|
72
|
+
var self = this;
|
73
|
+
|
74
|
+
if (self.options.maxTags && self.itemsArray.length >= self.options.maxTags)
|
75
|
+
return;
|
76
|
+
|
77
|
+
// Ignore falsey values, except false
|
78
|
+
if (item !== false && !item)
|
79
|
+
return;
|
80
|
+
|
81
|
+
// Trim value
|
82
|
+
if (typeof item === "string" && self.options.trimValue) {
|
83
|
+
item = $.trim(item);
|
84
|
+
}
|
85
|
+
|
86
|
+
// Throw an error when trying to add an object while the itemValue option was not set
|
87
|
+
if (typeof item === "object" && !self.objectItems)
|
88
|
+
throw("Can't add objects when itemValue option is not set");
|
89
|
+
|
90
|
+
// Ignore strings only containg whitespace
|
91
|
+
if (item.toString().match(/^\s*$/))
|
92
|
+
return;
|
93
|
+
|
94
|
+
// If SELECT but not multiple, remove current tag
|
95
|
+
if (self.isSelect && !self.multiple && self.itemsArray.length > 0)
|
96
|
+
self.remove(self.itemsArray[0]);
|
97
|
+
|
98
|
+
if (typeof item === "string" && this.$element[0].tagName === 'INPUT') {
|
99
|
+
var delimiter = (self.options.delimiterRegex) ? self.options.delimiterRegex : self.options.delimiter;
|
100
|
+
var items = item.split(delimiter);
|
101
|
+
if (items.length > 1) {
|
102
|
+
for (var i = 0; i < items.length; i++) {
|
103
|
+
this.add(items[i], true);
|
104
|
+
}
|
105
|
+
|
106
|
+
if (!dontPushVal)
|
107
|
+
self.pushVal(self.options.triggerChange);
|
108
|
+
return;
|
109
|
+
}
|
110
|
+
}
|
111
|
+
|
112
|
+
var itemValue = self.options.itemValue(item),
|
113
|
+
itemText = self.options.itemText(item),
|
114
|
+
tagClass = self.options.tagClass(item),
|
115
|
+
itemTitle = self.options.itemTitle(item);
|
116
|
+
|
117
|
+
// Ignore items allready added
|
118
|
+
var existing = $.grep(self.itemsArray, function(item) { return self.options.itemValue(item) === itemValue; } )[0];
|
119
|
+
if (existing && !self.options.allowDuplicates) {
|
120
|
+
// Invoke onTagExists
|
121
|
+
if (self.options.onTagExists) {
|
122
|
+
var $existingTag = $(".tag", self.$container).filter(function() { return $(this).data("item") === existing; });
|
123
|
+
self.options.onTagExists(item, $existingTag);
|
124
|
+
}
|
125
|
+
return;
|
126
|
+
}
|
127
|
+
|
128
|
+
// if length greater than limit
|
129
|
+
if (self.items().toString().length + item.length + 1 > self.options.maxInputLength)
|
130
|
+
return;
|
131
|
+
|
132
|
+
// raise beforeItemAdd arg
|
133
|
+
var beforeItemAddEvent = $.Event('beforeItemAdd', { item: item, cancel: false, options: options});
|
134
|
+
self.$element.trigger(beforeItemAddEvent);
|
135
|
+
if (beforeItemAddEvent.cancel)
|
136
|
+
return;
|
137
|
+
|
138
|
+
// register item in internal array and map
|
139
|
+
self.itemsArray.push(item);
|
140
|
+
|
141
|
+
// add a tag element
|
142
|
+
|
143
|
+
var $tag = $('<span class="tag ' + htmlEncode(tagClass) + (itemTitle !== null ? ('" title="' + itemTitle) : '') + '">' + htmlEncode(itemText) + '<span data-role="remove"></span></span>');
|
144
|
+
$tag.data('item', item);
|
145
|
+
self.findInputWrapper().before($tag);
|
146
|
+
$tag.after(' ');
|
147
|
+
|
148
|
+
// Check to see if the tag exists in its raw or uri-encoded form
|
149
|
+
var optionExists = (
|
150
|
+
$('option[value="' + encodeURIComponent(itemValue) + '"]', self.$element).length ||
|
151
|
+
$('option[value="' + htmlEncode(itemValue) + '"]', self.$element).length
|
152
|
+
);
|
153
|
+
|
154
|
+
// add <option /> if item represents a value not present in one of the <select />'s options
|
155
|
+
if (self.isSelect && !optionExists) {
|
156
|
+
var $option = $('<option selected>' + htmlEncode(itemText) + '</option>');
|
157
|
+
$option.data('item', item);
|
158
|
+
$option.attr('value', itemValue);
|
159
|
+
self.$element.append($option);
|
160
|
+
}
|
161
|
+
|
162
|
+
if (!dontPushVal)
|
163
|
+
self.pushVal(self.options.triggerChange);
|
164
|
+
|
165
|
+
// Add class when reached maxTags
|
166
|
+
if (self.options.maxTags === self.itemsArray.length || self.items().toString().length === self.options.maxInputLength)
|
167
|
+
self.$container.addClass('bootstrap-tagsinput-max');
|
168
|
+
|
169
|
+
// If using typeahead, once the tag has been added, clear the typeahead value so it does not stick around in the input.
|
170
|
+
if ($('.typeahead, .twitter-typeahead', self.$container).length) {
|
171
|
+
self.$input.typeahead('val', '');
|
172
|
+
}
|
173
|
+
|
174
|
+
if (this.isInit) {
|
175
|
+
self.$element.trigger($.Event('itemAddedOnInit', { item: item, options: options }));
|
176
|
+
} else {
|
177
|
+
self.$element.trigger($.Event('itemAdded', { item: item, options: options }));
|
178
|
+
}
|
179
|
+
},
|
180
|
+
|
181
|
+
/**
|
182
|
+
* Removes the given item. Pass true to dontPushVal to prevent updating the
|
183
|
+
* elements val()
|
184
|
+
*/
|
185
|
+
remove: function(item, dontPushVal, options) {
|
186
|
+
var self = this;
|
187
|
+
|
188
|
+
if (self.objectItems) {
|
189
|
+
if (typeof item === "object")
|
190
|
+
item = $.grep(self.itemsArray, function(other) { return self.options.itemValue(other) == self.options.itemValue(item); } );
|
191
|
+
else
|
192
|
+
item = $.grep(self.itemsArray, function(other) { return self.options.itemValue(other) == item; } );
|
193
|
+
|
194
|
+
item = item[item.length-1];
|
195
|
+
}
|
196
|
+
|
197
|
+
if (item) {
|
198
|
+
var beforeItemRemoveEvent = $.Event('beforeItemRemove', { item: item, cancel: false, options: options });
|
199
|
+
self.$element.trigger(beforeItemRemoveEvent);
|
200
|
+
if (beforeItemRemoveEvent.cancel)
|
201
|
+
return;
|
202
|
+
|
203
|
+
$('.tag', self.$container).filter(function() { return $(this).data('item') === item; }).remove();
|
204
|
+
$('option', self.$element).filter(function() { return $(this).data('item') === item; }).remove();
|
205
|
+
if($.inArray(item, self.itemsArray) !== -1)
|
206
|
+
self.itemsArray.splice($.inArray(item, self.itemsArray), 1);
|
207
|
+
}
|
208
|
+
|
209
|
+
if (!dontPushVal)
|
210
|
+
self.pushVal(self.options.triggerChange);
|
211
|
+
|
212
|
+
// Remove class when reached maxTags
|
213
|
+
if (self.options.maxTags > self.itemsArray.length)
|
214
|
+
self.$container.removeClass('bootstrap-tagsinput-max');
|
215
|
+
|
216
|
+
self.$element.trigger($.Event('itemRemoved', { item: item, options: options }));
|
217
|
+
},
|
218
|
+
|
219
|
+
/**
|
220
|
+
* Removes all items
|
221
|
+
*/
|
222
|
+
removeAll: function() {
|
223
|
+
var self = this;
|
224
|
+
|
225
|
+
$('.tag', self.$container).remove();
|
226
|
+
$('option', self.$element).remove();
|
227
|
+
|
228
|
+
while(self.itemsArray.length > 0)
|
229
|
+
self.itemsArray.pop();
|
230
|
+
|
231
|
+
self.pushVal(self.options.triggerChange);
|
232
|
+
},
|
233
|
+
|
234
|
+
/**
|
235
|
+
* Refreshes the tags so they match the text/value of their corresponding
|
236
|
+
* item.
|
237
|
+
*/
|
238
|
+
refresh: function() {
|
239
|
+
var self = this;
|
240
|
+
$('.tag', self.$container).each(function() {
|
241
|
+
var $tag = $(this),
|
242
|
+
item = $tag.data('item'),
|
243
|
+
itemValue = self.options.itemValue(item),
|
244
|
+
itemText = self.options.itemText(item),
|
245
|
+
tagClass = self.options.tagClass(item);
|
246
|
+
|
247
|
+
// Update tag's class and inner text
|
248
|
+
$tag.attr('class', null);
|
249
|
+
$tag.addClass('tag ' + htmlEncode(tagClass));
|
250
|
+
$tag.contents().filter(function() {
|
251
|
+
return this.nodeType == 3;
|
252
|
+
})[0].nodeValue = htmlEncode(itemText);
|
253
|
+
|
254
|
+
if (self.isSelect) {
|
255
|
+
var option = $('option', self.$element).filter(function() { return $(this).data('item') === item; });
|
256
|
+
option.attr('value', itemValue);
|
257
|
+
}
|
258
|
+
});
|
259
|
+
},
|
260
|
+
|
261
|
+
/**
|
262
|
+
* Returns the items added as tags
|
263
|
+
*/
|
264
|
+
items: function() {
|
265
|
+
return this.itemsArray;
|
266
|
+
},
|
267
|
+
|
268
|
+
/**
|
269
|
+
* Assembly value by retrieving the value of each item, and set it on the
|
270
|
+
* element.
|
271
|
+
*/
|
272
|
+
pushVal: function() {
|
273
|
+
var self = this,
|
274
|
+
val = $.map(self.items(), function(item) {
|
275
|
+
return self.options.itemValue(item).toString();
|
276
|
+
});
|
277
|
+
|
278
|
+
self.$element.val(val, true);
|
279
|
+
|
280
|
+
if (self.options.triggerChange)
|
281
|
+
self.$element.trigger('change');
|
282
|
+
},
|
283
|
+
|
284
|
+
/**
|
285
|
+
* Initializes the tags input behaviour on the element
|
286
|
+
*/
|
287
|
+
build: function(options) {
|
288
|
+
var self = this;
|
289
|
+
|
290
|
+
self.options = $.extend({}, defaultOptions, options);
|
291
|
+
// When itemValue is set, freeInput should always be false
|
292
|
+
if (self.objectItems)
|
293
|
+
self.options.freeInput = false;
|
294
|
+
|
295
|
+
makeOptionItemFunction(self.options, 'itemValue');
|
296
|
+
makeOptionItemFunction(self.options, 'itemText');
|
297
|
+
makeOptionFunction(self.options, 'tagClass');
|
298
|
+
|
299
|
+
// Typeahead Bootstrap version 2.3.2
|
300
|
+
if (self.options.typeahead) {
|
301
|
+
var typeahead = self.options.typeahead || {};
|
302
|
+
|
303
|
+
makeOptionFunction(typeahead, 'source');
|
304
|
+
|
305
|
+
self.$input.typeahead($.extend({}, typeahead, {
|
306
|
+
source: function (query, process) {
|
307
|
+
function processItems(items) {
|
308
|
+
var texts = [];
|
309
|
+
|
310
|
+
for (var i = 0; i < items.length; i++) {
|
311
|
+
var text = self.options.itemText(items[i]);
|
312
|
+
map[text] = items[i];
|
313
|
+
texts.push(text);
|
314
|
+
}
|
315
|
+
process(texts);
|
316
|
+
}
|
317
|
+
|
318
|
+
this.map = {};
|
319
|
+
var map = this.map,
|
320
|
+
data = typeahead.source(query);
|
321
|
+
|
322
|
+
if ($.isFunction(data.success)) {
|
323
|
+
// support for Angular callbacks
|
324
|
+
data.success(processItems);
|
325
|
+
} else if ($.isFunction(data.then)) {
|
326
|
+
// support for Angular promises
|
327
|
+
data.then(processItems);
|
328
|
+
} else {
|
329
|
+
// support for functions and jquery promises
|
330
|
+
$.when(data)
|
331
|
+
.then(processItems);
|
332
|
+
}
|
333
|
+
},
|
334
|
+
updater: function (text) {
|
335
|
+
self.add(this.map[text]);
|
336
|
+
return this.map[text];
|
337
|
+
},
|
338
|
+
matcher: function (text) {
|
339
|
+
return (text.toLowerCase().indexOf(this.query.trim().toLowerCase()) !== -1);
|
340
|
+
},
|
341
|
+
sorter: function (texts) {
|
342
|
+
return texts.sort();
|
343
|
+
},
|
344
|
+
highlighter: function (text) {
|
345
|
+
var regex = new RegExp( '(' + this.query + ')', 'gi' );
|
346
|
+
return text.replace( regex, "<strong>$1</strong>" );
|
347
|
+
}
|
348
|
+
}));
|
349
|
+
}
|
350
|
+
|
351
|
+
// typeahead.js
|
352
|
+
if (self.options.typeaheadjs) {
|
353
|
+
|
354
|
+
// Determine if main configurations were passed or simply a dataset
|
355
|
+
var typeaheadjs = self.options.typeaheadjs;
|
356
|
+
if (!$.isArray(typeaheadjs)) {
|
357
|
+
typeaheadjs = [null, typeaheadjs];
|
358
|
+
}
|
359
|
+
var valueKey = typeaheadjs[1].valueKey; // We should test typeaheadjs.size >= 1
|
360
|
+
var f_datum = valueKey ? function (datum) { return datum[valueKey]; }
|
361
|
+
: function (datum) { return datum; }
|
362
|
+
$.fn.typeahead.apply(self.$input,typeaheadjs).on('typeahead:selected', $.proxy(function (obj, datum) {
|
363
|
+
self.add( f_datum(datum) );
|
364
|
+
self.$input.typeahead('val', '');
|
365
|
+
}, self));
|
366
|
+
|
367
|
+
}
|
368
|
+
|
369
|
+
self.$container.on('click', $.proxy(function(event) {
|
370
|
+
if (! self.$element.attr('disabled')) {
|
371
|
+
self.$input.removeAttr('disabled');
|
372
|
+
}
|
373
|
+
self.$input.focus();
|
374
|
+
}, self));
|
375
|
+
|
376
|
+
if (self.options.addOnBlur && self.options.freeInput) {
|
377
|
+
self.$input.on('focusout', $.proxy(function(event) {
|
378
|
+
// HACK: only process on focusout when no typeahead opened, to
|
379
|
+
// avoid adding the typeahead text as tag
|
380
|
+
if ($('.typeahead, .twitter-typeahead', self.$container).length === 0) {
|
381
|
+
self.add(self.$input.val());
|
382
|
+
self.$input.val('');
|
383
|
+
}
|
384
|
+
}, self));
|
385
|
+
}
|
386
|
+
|
387
|
+
// Toggle the 'focus' css class on the container when it has focus
|
388
|
+
self.$container.on({
|
389
|
+
focusin: function() {
|
390
|
+
self.$container.addClass(self.options.focusClass);
|
391
|
+
},
|
392
|
+
focusout: function() {
|
393
|
+
self.$container.removeClass(self.options.focusClass);
|
394
|
+
},
|
395
|
+
});
|
396
|
+
|
397
|
+
self.$container.on('keydown', 'input', $.proxy(function(event) {
|
398
|
+
var $input = $(event.target),
|
399
|
+
$inputWrapper = self.findInputWrapper();
|
400
|
+
|
401
|
+
if (self.$element.attr('disabled')) {
|
402
|
+
self.$input.attr('disabled', 'disabled');
|
403
|
+
return;
|
404
|
+
}
|
405
|
+
|
406
|
+
switch (event.which) {
|
407
|
+
// BACKSPACE
|
408
|
+
case 8:
|
409
|
+
if (doGetCaretPosition($input[0]) === 0) {
|
410
|
+
var prev = $inputWrapper.prev();
|
411
|
+
if (prev.length) {
|
412
|
+
self.remove(prev.data('item'));
|
413
|
+
}
|
414
|
+
}
|
415
|
+
break;
|
416
|
+
|
417
|
+
// DELETE
|
418
|
+
case 46:
|
419
|
+
if (doGetCaretPosition($input[0]) === 0) {
|
420
|
+
var next = $inputWrapper.next();
|
421
|
+
if (next.length) {
|
422
|
+
self.remove(next.data('item'));
|
423
|
+
}
|
424
|
+
}
|
425
|
+
break;
|
426
|
+
|
427
|
+
// LEFT ARROW
|
428
|
+
case 37:
|
429
|
+
// Try to move the input before the previous tag
|
430
|
+
var $prevTag = $inputWrapper.prev();
|
431
|
+
if ($input.val().length === 0 && $prevTag[0]) {
|
432
|
+
$prevTag.before($inputWrapper);
|
433
|
+
$input.focus();
|
434
|
+
}
|
435
|
+
break;
|
436
|
+
// RIGHT ARROW
|
437
|
+
case 39:
|
438
|
+
// Try to move the input after the next tag
|
439
|
+
var $nextTag = $inputWrapper.next();
|
440
|
+
if ($input.val().length === 0 && $nextTag[0]) {
|
441
|
+
$nextTag.after($inputWrapper);
|
442
|
+
$input.focus();
|
443
|
+
}
|
444
|
+
break;
|
445
|
+
default:
|
446
|
+
// ignore
|
447
|
+
}
|
448
|
+
|
449
|
+
// Reset internal input's size
|
450
|
+
var textLength = $input.val().length,
|
451
|
+
wordSpace = Math.ceil(textLength / 5),
|
452
|
+
size = textLength + wordSpace + 1;
|
453
|
+
$input.attr('size', Math.max(this.inputSize, $input.val().length));
|
454
|
+
}, self));
|
455
|
+
|
456
|
+
self.$container.on('keypress', 'input', $.proxy(function(event) {
|
457
|
+
var $input = $(event.target);
|
458
|
+
|
459
|
+
if (self.$element.attr('disabled')) {
|
460
|
+
self.$input.attr('disabled', 'disabled');
|
461
|
+
return;
|
462
|
+
}
|
463
|
+
|
464
|
+
var text = $input.val(),
|
465
|
+
maxLengthReached = self.options.maxChars && text.length >= self.options.maxChars;
|
466
|
+
if (self.options.freeInput && (keyCombinationInList(event, self.options.confirmKeys) || maxLengthReached)) {
|
467
|
+
// Only attempt to add a tag if there is data in the field
|
468
|
+
if (text.length !== 0) {
|
469
|
+
self.add(maxLengthReached ? text.substr(0, self.options.maxChars) : text);
|
470
|
+
$input.val('');
|
471
|
+
}
|
472
|
+
|
473
|
+
// If the field is empty, let the event triggered fire as usual
|
474
|
+
if (self.options.cancelConfirmKeysOnEmpty === false) {
|
475
|
+
event.preventDefault();
|
476
|
+
}
|
477
|
+
}
|
478
|
+
|
479
|
+
// Reset internal input's size
|
480
|
+
var textLength = $input.val().length,
|
481
|
+
wordSpace = Math.ceil(textLength / 5),
|
482
|
+
size = textLength + wordSpace + 1;
|
483
|
+
$input.attr('size', Math.max(this.inputSize, $input.val().length));
|
484
|
+
}, self));
|
485
|
+
|
486
|
+
// Remove icon clicked
|
487
|
+
self.$container.on('click', '[data-role=remove]', $.proxy(function(event) {
|
488
|
+
if (self.$element.attr('disabled')) {
|
489
|
+
return;
|
490
|
+
}
|
491
|
+
self.remove($(event.target).closest('.tag').data('item'));
|
492
|
+
}, self));
|
493
|
+
|
494
|
+
// Only add existing value as tags when using strings as tags
|
495
|
+
if (self.options.itemValue === defaultOptions.itemValue) {
|
496
|
+
if (self.$element[0].tagName === 'INPUT') {
|
497
|
+
self.add(self.$element.val());
|
498
|
+
} else {
|
499
|
+
$('option', self.$element).each(function() {
|
500
|
+
self.add($(this).attr('value'), true);
|
501
|
+
});
|
502
|
+
}
|
503
|
+
}
|
504
|
+
},
|
505
|
+
|
506
|
+
/**
|
507
|
+
* Removes all tagsinput behaviour and unregsiter all event handlers
|
508
|
+
*/
|
509
|
+
destroy: function() {
|
510
|
+
var self = this;
|
511
|
+
|
512
|
+
// Unbind events
|
513
|
+
self.$container.off('keypress', 'input');
|
514
|
+
self.$container.off('click', '[role=remove]');
|
515
|
+
|
516
|
+
self.$container.remove();
|
517
|
+
self.$element.removeData('tagsinput');
|
518
|
+
self.$element.show();
|
519
|
+
},
|
520
|
+
|
521
|
+
/**
|
522
|
+
* Sets focus on the tagsinput
|
523
|
+
*/
|
524
|
+
focus: function() {
|
525
|
+
this.$input.focus();
|
526
|
+
},
|
527
|
+
|
528
|
+
/**
|
529
|
+
* Returns the internal input element
|
530
|
+
*/
|
531
|
+
input: function() {
|
532
|
+
return this.$input;
|
533
|
+
},
|
534
|
+
|
535
|
+
/**
|
536
|
+
* Returns the element which is wrapped around the internal input. This
|
537
|
+
* is normally the $container, but typeahead.js moves the $input element.
|
538
|
+
*/
|
539
|
+
findInputWrapper: function() {
|
540
|
+
var elt = this.$input[0],
|
541
|
+
container = this.$container[0];
|
542
|
+
while(elt && elt.parentNode !== container)
|
543
|
+
elt = elt.parentNode;
|
544
|
+
|
545
|
+
return $(elt);
|
546
|
+
}
|
547
|
+
};
|
548
|
+
|
549
|
+
/**
|
550
|
+
* Register JQuery plugin
|
551
|
+
*/
|
552
|
+
$.fn.tagsinput = function(arg1, arg2, arg3) {
|
553
|
+
var results = [];
|
554
|
+
|
555
|
+
this.each(function() {
|
556
|
+
var tagsinput = $(this).data('tagsinput');
|
557
|
+
// Initialize a new tags input
|
558
|
+
if (!tagsinput) {
|
559
|
+
tagsinput = new TagsInput(this, arg1);
|
560
|
+
$(this).data('tagsinput', tagsinput);
|
561
|
+
results.push(tagsinput);
|
562
|
+
|
563
|
+
if (this.tagName === 'SELECT') {
|
564
|
+
$('option', $(this)).attr('selected', 'selected');
|
565
|
+
}
|
566
|
+
|
567
|
+
// Init tags from $(this).val()
|
568
|
+
$(this).val($(this).val());
|
569
|
+
} else if (!arg1 && !arg2) {
|
570
|
+
// tagsinput already exists
|
571
|
+
// no function, trying to init
|
572
|
+
results.push(tagsinput);
|
573
|
+
} else if(tagsinput[arg1] !== undefined) {
|
574
|
+
// Invoke function on existing tags input
|
575
|
+
if(tagsinput[arg1].length === 3 && arg3 !== undefined){
|
576
|
+
var retVal = tagsinput[arg1](arg2, null, arg3);
|
577
|
+
}else{
|
578
|
+
var retVal = tagsinput[arg1](arg2);
|
579
|
+
}
|
580
|
+
if (retVal !== undefined)
|
581
|
+
results.push(retVal);
|
582
|
+
}
|
583
|
+
});
|
584
|
+
|
585
|
+
if ( typeof arg1 == 'string') {
|
586
|
+
// Return the results from the invoked function calls
|
587
|
+
return results.length > 1 ? results : results[0];
|
588
|
+
} else {
|
589
|
+
return results;
|
590
|
+
}
|
591
|
+
};
|
592
|
+
|
593
|
+
$.fn.tagsinput.Constructor = TagsInput;
|
594
|
+
|
595
|
+
/**
|
596
|
+
* Most options support both a string or number as well as a function as
|
597
|
+
* option value. This function makes sure that the option with the given
|
598
|
+
* key in the given options is wrapped in a function
|
599
|
+
*/
|
600
|
+
function makeOptionItemFunction(options, key) {
|
601
|
+
if (typeof options[key] !== 'function') {
|
602
|
+
var propertyName = options[key];
|
603
|
+
options[key] = function(item) { return item[propertyName]; };
|
604
|
+
}
|
605
|
+
}
|
606
|
+
function makeOptionFunction(options, key) {
|
607
|
+
if (typeof options[key] !== 'function') {
|
608
|
+
var value = options[key];
|
609
|
+
options[key] = function() { return value; };
|
610
|
+
}
|
611
|
+
}
|
612
|
+
/**
|
613
|
+
* HtmlEncodes the given value
|
614
|
+
*/
|
615
|
+
var htmlEncodeContainer = $('<div />');
|
616
|
+
function htmlEncode(value) {
|
617
|
+
if (value) {
|
618
|
+
return htmlEncodeContainer.text(value).html();
|
619
|
+
} else {
|
620
|
+
return '';
|
621
|
+
}
|
622
|
+
}
|
623
|
+
|
624
|
+
/**
|
625
|
+
* Returns the position of the caret in the given input field
|
626
|
+
* http://flightschool.acylt.com/devnotes/caret-position-woes/
|
627
|
+
*/
|
628
|
+
function doGetCaretPosition(oField) {
|
629
|
+
var iCaretPos = 0;
|
630
|
+
if (document.selection) {
|
631
|
+
oField.focus ();
|
632
|
+
var oSel = document.selection.createRange();
|
633
|
+
oSel.moveStart ('character', -oField.value.length);
|
634
|
+
iCaretPos = oSel.text.length;
|
635
|
+
} else if (oField.selectionStart || oField.selectionStart == '0') {
|
636
|
+
iCaretPos = oField.selectionStart;
|
637
|
+
}
|
638
|
+
return (iCaretPos);
|
639
|
+
}
|
640
|
+
|
641
|
+
/**
|
642
|
+
* Returns boolean indicates whether user has pressed an expected key combination.
|
643
|
+
* @param object keyPressEvent: JavaScript event object, refer
|
644
|
+
* http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
|
645
|
+
* @param object lookupList: expected key combinations, as in:
|
646
|
+
* [13, {which: 188, shiftKey: true}]
|
647
|
+
*/
|
648
|
+
function keyCombinationInList(keyPressEvent, lookupList) {
|
649
|
+
var found = false;
|
650
|
+
$.each(lookupList, function (index, keyCombination) {
|
651
|
+
if (typeof (keyCombination) === 'number' && keyPressEvent.which === keyCombination) {
|
652
|
+
found = true;
|
653
|
+
return false;
|
654
|
+
}
|
655
|
+
|
656
|
+
if (keyPressEvent.which === keyCombination.which) {
|
657
|
+
var alt = !keyCombination.hasOwnProperty('altKey') || keyPressEvent.altKey === keyCombination.altKey,
|
658
|
+
shift = !keyCombination.hasOwnProperty('shiftKey') || keyPressEvent.shiftKey === keyCombination.shiftKey,
|
659
|
+
ctrl = !keyCombination.hasOwnProperty('ctrlKey') || keyPressEvent.ctrlKey === keyCombination.ctrlKey;
|
660
|
+
if (alt && shift && ctrl) {
|
661
|
+
found = true;
|
662
|
+
return false;
|
663
|
+
}
|
664
|
+
}
|
665
|
+
});
|
666
|
+
|
667
|
+
return found;
|
668
|
+
}
|
669
|
+
|
670
|
+
/**
|
671
|
+
* Initialize tagsinput behaviour on inputs and selects which have
|
672
|
+
* data-role=tagsinput
|
673
|
+
*/
|
674
|
+
$(function() {
|
675
|
+
$("input[data-role=tagsinput], select[multiple][data-role=tagsinput]").tagsinput();
|
676
|
+
});
|
677
|
+
})(window.jQuery);
|
@@ -0,0 +1,7 @@
|
|
1
|
+
/*
|
2
|
+
* bootstrap-tagsinput v0.8.0
|
3
|
+
*
|
4
|
+
*/
|
5
|
+
|
6
|
+
!function(a){"use strict";function b(b,c){this.isInit=!0,this.itemsArray=[],this.$element=a(b),this.$element.hide(),this.isSelect="SELECT"===b.tagName,this.multiple=this.isSelect&&b.hasAttribute("multiple"),this.objectItems=c&&c.itemValue,this.placeholderText=b.hasAttribute("placeholder")?this.$element.attr("placeholder"):"",this.inputSize=Math.max(1,this.placeholderText.length),this.$container=a('<div class="bootstrap-tagsinput"></div>'),this.$input=a('<input type="text" placeholder="'+this.placeholderText+'"/>').appendTo(this.$container),this.$element.before(this.$container),this.build(c),this.isInit=!1}function c(a,b){if("function"!=typeof a[b]){var c=a[b];a[b]=function(a){return a[c]}}}function d(a,b){if("function"!=typeof a[b]){var c=a[b];a[b]=function(){return c}}}function e(a){return a?i.text(a).html():""}function f(a){var b=0;if(document.selection){a.focus();var c=document.selection.createRange();c.moveStart("character",-a.value.length),b=c.text.length}else(a.selectionStart||"0"==a.selectionStart)&&(b=a.selectionStart);return b}function g(b,c){var d=!1;return a.each(c,function(a,c){if("number"==typeof c&&b.which===c)return d=!0,!1;if(b.which===c.which){var e=!c.hasOwnProperty("altKey")||b.altKey===c.altKey,f=!c.hasOwnProperty("shiftKey")||b.shiftKey===c.shiftKey,g=!c.hasOwnProperty("ctrlKey")||b.ctrlKey===c.ctrlKey;if(e&&f&&g)return d=!0,!1}}),d}var h={tagClass:function(a){return"badge bg-info"},focusClass:"focus",itemValue:function(a){return a?a.toString():a},itemText:function(a){return this.itemValue(a)},itemTitle:function(a){return null},freeInput:!0,addOnBlur:!0,maxTags:void 0,maxChars:void 0,confirmKeys:[13,44],delimiter:",",delimiterRegex:null,cancelConfirmKeysOnEmpty:!1,onTagExists:function(a,b){b.hide().fadeIn()},trimValue:!1,allowDuplicates:!1,triggerChange:!0};b.prototype={constructor:b,add:function(b,c,d){var f=this;if(!(f.options.maxTags&&f.itemsArray.length>=f.options.maxTags)&&(b===!1||b)){if("string"==typeof b&&f.options.trimValue&&(b=a.trim(b)),"object"==typeof b&&!f.objectItems)throw"Can't add objects when itemValue option is not set";if(!b.toString().match(/^\s*$/)){if(f.isSelect&&!f.multiple&&f.itemsArray.length>0&&f.remove(f.itemsArray[0]),"string"==typeof b&&"INPUT"===this.$element[0].tagName){var g=f.options.delimiterRegex?f.options.delimiterRegex:f.options.delimiter,h=b.split(g);if(h.length>1){for(var i=0;i<h.length;i++)this.add(h[i],!0);return void(c||f.pushVal(f.options.triggerChange))}}var j=f.options.itemValue(b),k=f.options.itemText(b),l=f.options.tagClass(b),m=f.options.itemTitle(b),n=a.grep(f.itemsArray,function(a){return f.options.itemValue(a)===j})[0];if(!n||f.options.allowDuplicates){if(!(f.items().toString().length+b.length+1>f.options.maxInputLength)){var o=a.Event("beforeItemAdd",{item:b,cancel:!1,options:d});if(f.$element.trigger(o),!o.cancel){f.itemsArray.push(b);var p=a('<span class="tag '+e(l)+(null!==m?'" title="'+m:"")+'">'+e(k)+'<span data-role="remove"></span></span>');p.data("item",b),f.findInputWrapper().before(p),p.after(" ");var q=a('option[value="'+encodeURIComponent(j)+'"]',f.$element).length||a('option[value="'+e(j)+'"]',f.$element).length;if(f.isSelect&&!q){var r=a("<option selected>"+e(k)+"</option>");r.data("item",b),r.attr("value",j),f.$element.append(r)}c||f.pushVal(f.options.triggerChange),f.options.maxTags!==f.itemsArray.length&&f.items().toString().length!==f.options.maxInputLength||f.$container.addClass("bootstrap-tagsinput-max"),a(".typeahead, .twitter-typeahead",f.$container).length&&f.$input.typeahead("val",""),this.isInit?f.$element.trigger(a.Event("itemAddedOnInit",{item:b,options:d})):f.$element.trigger(a.Event("itemAdded",{item:b,options:d}))}}}else if(f.options.onTagExists){var s=a(".tag",f.$container).filter(function(){return a(this).data("item")===n});f.options.onTagExists(b,s)}}}},remove:function(b,c,d){var e=this;if(e.objectItems&&(b="object"==typeof b?a.grep(e.itemsArray,function(a){return e.options.itemValue(a)==e.options.itemValue(b)}):a.grep(e.itemsArray,function(a){return e.options.itemValue(a)==b}),b=b[b.length-1]),b){var f=a.Event("beforeItemRemove",{item:b,cancel:!1,options:d});if(e.$element.trigger(f),f.cancel)return;a(".tag",e.$container).filter(function(){return a(this).data("item")===b}).remove(),a("option",e.$element).filter(function(){return a(this).data("item")===b}).remove(),a.inArray(b,e.itemsArray)!==-1&&e.itemsArray.splice(a.inArray(b,e.itemsArray),1)}c||e.pushVal(e.options.triggerChange),e.options.maxTags>e.itemsArray.length&&e.$container.removeClass("bootstrap-tagsinput-max"),e.$element.trigger(a.Event("itemRemoved",{item:b,options:d}))},removeAll:function(){var b=this;for(a(".tag",b.$container).remove(),a("option",b.$element).remove();b.itemsArray.length>0;)b.itemsArray.pop();b.pushVal(b.options.triggerChange)},refresh:function(){var b=this;a(".tag",b.$container).each(function(){var c=a(this),d=c.data("item"),f=b.options.itemValue(d),g=b.options.itemText(d),h=b.options.tagClass(d);if(c.attr("class",null),c.addClass("tag "+e(h)),c.contents().filter(function(){return 3==this.nodeType})[0].nodeValue=e(g),b.isSelect){var i=a("option",b.$element).filter(function(){return a(this).data("item")===d});i.attr("value",f)}})},items:function(){return this.itemsArray},pushVal:function(){var b=this,c=a.map(b.items(),function(a){return b.options.itemValue(a).toString()});b.$element.val(c,!0),b.options.triggerChange&&b.$element.trigger("change")},build:function(b){var e=this;if(e.options=a.extend({},h,b),e.objectItems&&(e.options.freeInput=!1),c(e.options,"itemValue"),c(e.options,"itemText"),d(e.options,"tagClass"),e.options.typeahead){var i=e.options.typeahead||{};d(i,"source"),e.$input.typeahead(a.extend({},i,{source:function(b,c){function d(a){for(var b=[],d=0;d<a.length;d++){var g=e.options.itemText(a[d]);f[g]=a[d],b.push(g)}c(b)}this.map={};var f=this.map,g=i.source(b);a.isFunction(g.success)?g.success(d):a.isFunction(g.then)?g.then(d):a.when(g).then(d)},updater:function(a){return e.add(this.map[a]),this.map[a]},matcher:function(a){return a.toLowerCase().indexOf(this.query.trim().toLowerCase())!==-1},sorter:function(a){return a.sort()},highlighter:function(a){var b=new RegExp("("+this.query+")","gi");return a.replace(b,"<strong>$1</strong>")}}))}if(e.options.typeaheadjs){var j=e.options.typeaheadjs;a.isArray(j)||(j=[null,j]);var k=j[1].valueKey,l=k?function(a){return a[k]}:function(a){return a};a.fn.typeahead.apply(e.$input,j).on("typeahead:selected",a.proxy(function(a,b){e.add(l(b)),e.$input.typeahead("val","")},e))}e.$container.on("click",a.proxy(function(a){e.$element.attr("disabled")||e.$input.removeAttr("disabled"),e.$input.focus()},e)),e.options.addOnBlur&&e.options.freeInput&&e.$input.on("focusout",a.proxy(function(b){0===a(".typeahead, .twitter-typeahead",e.$container).length&&(e.add(e.$input.val()),e.$input.val(""))},e)),e.$container.on({focusin:function(){e.$container.addClass(e.options.focusClass)},focusout:function(){e.$container.removeClass(e.options.focusClass)}}),e.$container.on("keydown","input",a.proxy(function(b){var c=a(b.target),d=e.findInputWrapper();if(e.$element.attr("disabled"))return void e.$input.attr("disabled","disabled");switch(b.which){case 8:if(0===f(c[0])){var g=d.prev();g.length&&e.remove(g.data("item"))}break;case 46:if(0===f(c[0])){var h=d.next();h.length&&e.remove(h.data("item"))}break;case 37:var i=d.prev();0===c.val().length&&i[0]&&(i.before(d),c.focus());break;case 39:var j=d.next();0===c.val().length&&j[0]&&(j.after(d),c.focus())}var k=c.val().length;Math.ceil(k/5);c.attr("size",Math.max(this.inputSize,c.val().length))},e)),e.$container.on("keypress","input",a.proxy(function(b){var c=a(b.target);if(e.$element.attr("disabled"))return void e.$input.attr("disabled","disabled");var d=c.val(),f=e.options.maxChars&&d.length>=e.options.maxChars;e.options.freeInput&&(g(b,e.options.confirmKeys)||f)&&(0!==d.length&&(e.add(f?d.substr(0,e.options.maxChars):d),c.val("")),e.options.cancelConfirmKeysOnEmpty===!1&&b.preventDefault());var h=c.val().length;Math.ceil(h/5);c.attr("size",Math.max(this.inputSize,c.val().length))},e)),e.$container.on("click","[data-role=remove]",a.proxy(function(b){e.$element.attr("disabled")||e.remove(a(b.target).closest(".tag").data("item"))},e)),e.options.itemValue===h.itemValue&&("INPUT"===e.$element[0].tagName?e.add(e.$element.val()):a("option",e.$element).each(function(){e.add(a(this).attr("value"),!0)}))},destroy:function(){var a=this;a.$container.off("keypress","input"),a.$container.off("click","[role=remove]"),a.$container.remove(),a.$element.removeData("tagsinput"),a.$element.show()},focus:function(){this.$input.focus()},input:function(){return this.$input},findInputWrapper:function(){for(var b=this.$input[0],c=this.$container[0];b&&b.parentNode!==c;)b=b.parentNode;return a(b)}},a.fn.tagsinput=function(c,d,e){var f=[];return this.each(function(){var g=a(this).data("tagsinput");if(g)if(c||d){if(void 0!==g[c]){if(3===g[c].length&&void 0!==e)var h=g[c](d,null,e);else var h=g[c](d);void 0!==h&&f.push(h)}}else f.push(g);else g=new b(this,c),a(this).data("tagsinput",g),f.push(g),"SELECT"===this.tagName&&a("option",a(this)).attr("selected","selected"),a(this).val(a(this).val())}),"string"==typeof c?f.length>1?f:f[0]:f},a.fn.tagsinput.Constructor=b;var i=a("<div />");a(function(){a("input[data-role=tagsinput], select[multiple][data-role=tagsinput]").tagsinput()})}(window.jQuery);
|
7
|
+
//# sourceMappingURL=bootstrap-tagsinput.min.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"sources":["../src/bootstrap-tagsinput.js"],"names":["$","TagsInput","element","options","this","isInit","itemsArray","$element","hide","isSelect","tagName","multiple","hasAttribute","objectItems","itemValue","placeholderText","attr","inputSize","Math","max","length","$container","$input","appendTo","before","build","makeOptionItemFunction","key","propertyName","item","makeOptionFunction","value","htmlEncode","htmlEncodeContainer","text","html","doGetCaretPosition","oField","iCaretPos","document","selection","focus","oSel","createRange","moveStart","selectionStart","keyCombinationInList","keyPressEvent","lookupList","found","each","index","keyCombination","which","alt","hasOwnProperty","altKey","shift","shiftKey","ctrl","ctrlKey","defaultOptions","tagClass","focusClass","toString","itemText","itemTitle","freeInput","addOnBlur","maxTags","undefined","maxChars","confirmKeys","delimiter","delimiterRegex","cancelConfirmKeysOnEmpty","onTagExists","$tag","fadeIn","trimValue","allowDuplicates","triggerChange","prototype","constructor","add","dontPushVal","self","trim","match","remove","items","split","i","pushVal","existing","grep","maxInputLength","beforeItemAddEvent","Event","cancel","trigger","push","data","findInputWrapper","after","optionExists","encodeURIComponent","$option","append","addClass","typeahead","$existingTag","filter","other","beforeItemRemoveEvent","inArray","splice","removeClass","removeAll","pop","refresh","contents","nodeType","nodeValue","option","val","map","extend","source","query","process","processItems","texts","isFunction","success","then","when","updater","matcher","toLowerCase","indexOf","sorter","sort","highlighter","regex","RegExp","replace","typeaheadjs","isArray","valueKey","f_datum","datum","fn","apply","on","proxy","obj","event","removeAttr","focusin","focusout","target","$inputWrapper","prev","next","$prevTag","$nextTag","textLength","ceil","maxLengthReached","substr","preventDefault","closest","destroy","off","removeData","show","input","elt","container","parentNode","tagsinput","arg1","arg2","arg3","results","retVal","Constructor","window","jQuery"],"mappings":"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","file":"bootstrap-tagsinput.min.js"}
|
@@ -0,0 +1,54 @@
|
|
1
|
+
/*
|
2
|
+
* bootstrap-tagsinput v0.8.0
|
3
|
+
*
|
4
|
+
*/
|
5
|
+
|
6
|
+
.twitter-typeahead .tt-query,
|
7
|
+
.twitter-typeahead .tt-hint {
|
8
|
+
margin-bottom: 0;
|
9
|
+
}
|
10
|
+
|
11
|
+
.twitter-typeahead .tt-hint
|
12
|
+
{
|
13
|
+
display: none;
|
14
|
+
}
|
15
|
+
|
16
|
+
.tt-menu {
|
17
|
+
position: absolute;
|
18
|
+
top: 100%;
|
19
|
+
left: 0;
|
20
|
+
z-index: 1000;
|
21
|
+
display: none;
|
22
|
+
float: left;
|
23
|
+
min-width: 160px;
|
24
|
+
padding: 5px 0;
|
25
|
+
margin: 2px 0 0;
|
26
|
+
list-style: none;
|
27
|
+
font-size: 14px;
|
28
|
+
background-color: #ffffff;
|
29
|
+
border: 1px solid #cccccc;
|
30
|
+
border: 1px solid rgba(0, 0, 0, 0.15);
|
31
|
+
border-radius: 4px;
|
32
|
+
-webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
|
33
|
+
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
|
34
|
+
background-clip: padding-box;
|
35
|
+
cursor: pointer;
|
36
|
+
}
|
37
|
+
|
38
|
+
.tt-suggestion {
|
39
|
+
display: block;
|
40
|
+
padding: 3px 20px;
|
41
|
+
clear: both;
|
42
|
+
font-weight: normal;
|
43
|
+
line-height: 1.428571429;
|
44
|
+
color: #333333;
|
45
|
+
white-space: nowrap;
|
46
|
+
}
|
47
|
+
|
48
|
+
.tt-suggestion:hover,
|
49
|
+
.tt-suggestion:focus {
|
50
|
+
color: #ffffff;
|
51
|
+
text-decoration: none;
|
52
|
+
outline: 0;
|
53
|
+
background-color: #428bca;
|
54
|
+
}
|
@@ -0,0 +1,60 @@
|
|
1
|
+
/*
|
2
|
+
* bootstrap-tagsinput v0.8.0
|
3
|
+
*
|
4
|
+
*/
|
5
|
+
|
6
|
+
.bootstrap-tagsinput {
|
7
|
+
background-color: #fff;
|
8
|
+
border: 1px solid #ccc;
|
9
|
+
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
|
10
|
+
display: inline-block;
|
11
|
+
padding: 4px 6px;
|
12
|
+
color: #555;
|
13
|
+
vertical-align: middle;
|
14
|
+
border-radius: 4px;
|
15
|
+
max-width: 100%;
|
16
|
+
line-height: 22px;
|
17
|
+
cursor: text;
|
18
|
+
}
|
19
|
+
.bootstrap-tagsinput input {
|
20
|
+
border: none;
|
21
|
+
box-shadow: none;
|
22
|
+
outline: none;
|
23
|
+
background-color: transparent;
|
24
|
+
padding: 0 6px;
|
25
|
+
margin: 0;
|
26
|
+
width: auto;
|
27
|
+
max-width: inherit;
|
28
|
+
}
|
29
|
+
.bootstrap-tagsinput.form-control input::-moz-placeholder {
|
30
|
+
color: #777;
|
31
|
+
opacity: 1;
|
32
|
+
}
|
33
|
+
.bootstrap-tagsinput.form-control input:-ms-input-placeholder {
|
34
|
+
color: #777;
|
35
|
+
}
|
36
|
+
.bootstrap-tagsinput.form-control input::-webkit-input-placeholder {
|
37
|
+
color: #777;
|
38
|
+
}
|
39
|
+
.bootstrap-tagsinput input:focus {
|
40
|
+
border: none;
|
41
|
+
box-shadow: none;
|
42
|
+
}
|
43
|
+
.bootstrap-tagsinput .tag {
|
44
|
+
margin-right: 2px;
|
45
|
+
color: white;
|
46
|
+
}
|
47
|
+
.bootstrap-tagsinput .tag [data-role="remove"] {
|
48
|
+
margin-left: 8px;
|
49
|
+
cursor: pointer;
|
50
|
+
}
|
51
|
+
.bootstrap-tagsinput .tag [data-role="remove"]:after {
|
52
|
+
content: "x";
|
53
|
+
padding: 0px 2px;
|
54
|
+
}
|
55
|
+
.bootstrap-tagsinput .tag [data-role="remove"]:hover {
|
56
|
+
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
|
57
|
+
}
|
58
|
+
.bootstrap-tagsinput .tag [data-role="remove"]:hover:active {
|
59
|
+
box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
|
60
|
+
}
|
@@ -0,0 +1,50 @@
|
|
1
|
+
.bootstrap-tagsinput {
|
2
|
+
background-color: #fff;
|
3
|
+
border: 1px solid #ccc;
|
4
|
+
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
|
5
|
+
display: inline-block;
|
6
|
+
padding: 4px 6px;
|
7
|
+
margin-bottom: 10px;
|
8
|
+
color: #555;
|
9
|
+
vertical-align: middle;
|
10
|
+
border-radius: 4px;
|
11
|
+
max-width: 100%;
|
12
|
+
line-height: 22px;
|
13
|
+
cursor: text;
|
14
|
+
|
15
|
+
input {
|
16
|
+
border: none;
|
17
|
+
box-shadow: none;
|
18
|
+
outline: none;
|
19
|
+
background-color: transparent;
|
20
|
+
padding: 0;
|
21
|
+
margin: 0;
|
22
|
+
width: auto !important;
|
23
|
+
max-width: inherit;
|
24
|
+
|
25
|
+
&:focus {
|
26
|
+
border: none;
|
27
|
+
box-shadow: none;
|
28
|
+
}
|
29
|
+
}
|
30
|
+
|
31
|
+
.tag {
|
32
|
+
margin-right: 2px;
|
33
|
+
color: white;
|
34
|
+
|
35
|
+
[data-role="remove"] {
|
36
|
+
margin-left:8px;
|
37
|
+
cursor:pointer;
|
38
|
+
&:after{
|
39
|
+
content: "x";
|
40
|
+
padding:0px 2px;
|
41
|
+
}
|
42
|
+
&:hover {
|
43
|
+
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
|
44
|
+
&:active {
|
45
|
+
box-shadow: inset 0 3px 5px rgba(0,0,0,0.125);
|
46
|
+
}
|
47
|
+
}
|
48
|
+
}
|
49
|
+
}
|
50
|
+
}
|
metadata
ADDED
@@ -0,0 +1,99 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: bootstrap5-tagsinput-rails
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Felipe Calvo
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2021-03-30 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: railties
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '3.1'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '3.1'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bundler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '2.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '2.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
description:
|
56
|
+
email:
|
57
|
+
- felipecalvo239@gmail.com
|
58
|
+
executables: []
|
59
|
+
extensions: []
|
60
|
+
extra_rdoc_files: []
|
61
|
+
files:
|
62
|
+
- LICENSE.txt
|
63
|
+
- README.md
|
64
|
+
- lib/bootstrap5/tagsinput/rails.rb
|
65
|
+
- lib/bootstrap5/tagsinput/rails/version.rb
|
66
|
+
- vendor/assets/javascripts/bootstrap-tagsinput-angular.js
|
67
|
+
- vendor/assets/javascripts/bootstrap-tagsinput-angular.min.js
|
68
|
+
- vendor/assets/javascripts/bootstrap-tagsinput-angular.min.js.map
|
69
|
+
- vendor/assets/javascripts/bootstrap-tagsinput.js
|
70
|
+
- vendor/assets/javascripts/bootstrap-tagsinput.min.js
|
71
|
+
- vendor/assets/javascripts/bootstrap-tagsinput.min.js.map
|
72
|
+
- vendor/assets/stylesheets/bootstrap-tagsinput-typeahead.css
|
73
|
+
- vendor/assets/stylesheets/bootstrap-tagsinput.css
|
74
|
+
- vendor/assets/stylesheets/bootstrap-tagsinput.less
|
75
|
+
homepage: http://github.com/felipecalvo/bootstrap5-tagsinput-rails
|
76
|
+
licenses:
|
77
|
+
- MIT
|
78
|
+
metadata: {}
|
79
|
+
post_install_message:
|
80
|
+
rdoc_options: []
|
81
|
+
require_paths:
|
82
|
+
- lib
|
83
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
84
|
+
requirements:
|
85
|
+
- - ">="
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '0'
|
88
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
89
|
+
requirements:
|
90
|
+
- - ">="
|
91
|
+
- !ruby/object:Gem::Version
|
92
|
+
version: '0'
|
93
|
+
requirements: []
|
94
|
+
rubyforge_project:
|
95
|
+
rubygems_version: 2.5.1
|
96
|
+
signing_key:
|
97
|
+
specification_version: 4
|
98
|
+
summary: Bootstrap 5 compatible bootstrap-tagsinput-rails
|
99
|
+
test_files: []
|