weaver 0.6.0 → 0.6.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (106) hide show
  1. checksums.yaml +4 -4
  2. data/data/weaver/css/animate.css +36 -4
  3. data/data/weaver/css/bootstrap.css +31 -74
  4. data/data/weaver/css/bootstrap.css.map +1 -1
  5. data/data/weaver/css/bootstrap.min.css +4 -3
  6. data/data/weaver/css/bootstrap.min.css.map +1 -0
  7. data/data/weaver/css/plugins/bootstrap-markdown/bootstrap-markdown.min.css +1 -0
  8. data/data/weaver/css/plugins/bootstrap-tagsinput/bootstrap-tagsinput.css +55 -0
  9. data/data/weaver/css/plugins/bootstrapSocial/bootstrap-social.css +147 -0
  10. data/data/weaver/css/plugins/bootstrapTour/bootstrap-tour.min.css +22 -0
  11. data/data/weaver/css/plugins/c3/c3.min.css +1 -0
  12. data/data/weaver/css/plugins/chosen/bootstrap-chosen.css +332 -0
  13. data/data/weaver/css/plugins/codemirror/codemirror.css +1 -0
  14. data/data/weaver/css/plugins/dataTables/datatables.min.css +17 -0
  15. data/data/weaver/css/plugins/dropzone/basic.css +32 -148
  16. data/data/weaver/css/plugins/dropzone/dropzone.css +363 -385
  17. data/data/weaver/css/plugins/dualListbox/bootstrap-duallistbox.min.css +10 -0
  18. data/data/weaver/css/plugins/fullcalendar/fullcalendar.css +663 -379
  19. data/data/weaver/css/plugins/fullcalendar/fullcalendar.print.css +11 -5
  20. data/data/weaver/css/plugins/jQueryUI/jquery-ui.css +1177 -0
  21. data/data/weaver/css/plugins/ladda/ladda-themeless.min.css +7 -0
  22. data/data/weaver/css/plugins/ladda/ladda.min.css +9 -0
  23. data/data/weaver/css/plugins/summernote/font/summernote.eot +0 -0
  24. data/data/weaver/css/plugins/summernote/font/summernote.ttf +0 -0
  25. data/data/weaver/css/plugins/summernote/font/summernote.woff +0 -0
  26. data/data/weaver/css/plugins/summernote/summernote.css +1 -446
  27. data/data/weaver/css/plugins/textSpinners/spinners.css +204 -0
  28. data/data/weaver/css/plugins/touchspin/jquery.bootstrap-touchspin.min.css +10 -0
  29. data/data/weaver/css/style.css +687 -220
  30. data/data/weaver/font-awesome/css/font-awesome.css +547 -11
  31. data/data/weaver/font-awesome/css/font-awesome.min.css +2 -2
  32. data/data/weaver/font-awesome/fonts/FontAwesome.otf +0 -0
  33. data/data/weaver/font-awesome/fonts/fontawesome-webfont.eot +0 -0
  34. data/data/weaver/font-awesome/fonts/fontawesome-webfont.svg +2668 -562
  35. data/data/weaver/font-awesome/fonts/fontawesome-webfont.ttf +0 -0
  36. data/data/weaver/font-awesome/fonts/fontawesome-webfont.woff +0 -0
  37. data/data/weaver/font-awesome/fonts/fontawesome-webfont.woff2 +0 -0
  38. data/data/weaver/font-awesome/less/bordered-pulled.less +9 -0
  39. data/data/weaver/font-awesome/less/core.less +1 -2
  40. data/data/weaver/font-awesome/less/font-awesome.less +2 -1
  41. data/data/weaver/font-awesome/less/icons.less +195 -2
  42. data/data/weaver/font-awesome/less/mixins.less +37 -4
  43. data/data/weaver/font-awesome/less/path.less +1 -1
  44. data/data/weaver/font-awesome/less/screen-reader.less +5 -0
  45. data/data/weaver/font-awesome/less/variables.less +198 -4
  46. data/data/weaver/font-awesome/scss/_bordered-pulled.scss +9 -0
  47. data/data/weaver/font-awesome/scss/_core.scss +1 -2
  48. data/data/weaver/font-awesome/scss/_icons.scss +195 -2
  49. data/data/weaver/font-awesome/scss/_mixins.scss +37 -4
  50. data/data/weaver/font-awesome/scss/_screen-reader.scss +5 -0
  51. data/data/weaver/font-awesome/scss/_variables.scss +198 -4
  52. data/data/weaver/font-awesome/scss/font-awesome.scss +2 -1
  53. data/data/weaver/js/api/typehead_collection.json +3 -0
  54. data/data/weaver/js/bootstrap.js +66 -52
  55. data/data/weaver/js/bootstrap.min.js +4 -4
  56. data/data/weaver/js/demo/chartjs-demo.js +68 -157
  57. data/data/weaver/js/jquery-3.1.1.min.js +4 -0
  58. data/data/weaver/js/plugins/bootstrap-markdown/bootstrap-markdown.js +1386 -0
  59. data/data/weaver/js/plugins/bootstrap-markdown/markdown.js +1616 -0
  60. data/data/weaver/js/plugins/bootstrap-tagsinput/bootstrap-tagsinput.js +646 -0
  61. data/data/weaver/js/plugins/bootstrapTour/bootstrap-tour.min.js +22 -0
  62. data/data/weaver/js/plugins/c3/c3.min.js +5 -0
  63. data/data/weaver/js/plugins/chartJs/Chart.min.js +8 -5
  64. data/data/weaver/js/plugins/clipboard/clipboard.min.js +7 -0
  65. data/data/weaver/js/plugins/d3/LICENSE +27 -0
  66. data/data/weaver/js/plugins/d3/d3.min.js +5 -0
  67. data/data/weaver/js/plugins/dataTables/datatables.min.js +308 -0
  68. data/data/weaver/js/plugins/datamaps/datamaps.all.min.js +3 -0
  69. data/data/weaver/js/plugins/dotdotdot/jquery.dotdotdot.min.js +13 -0
  70. data/data/weaver/js/plugins/dropzone/dropzone.js +1575 -1649
  71. data/data/weaver/js/plugins/dualListbox/jquery.bootstrap-duallistbox.js +761 -0
  72. data/data/weaver/js/plugins/fullcalendar/fullcalendar.min.js +7 -6
  73. data/data/weaver/js/plugins/i18next/i18next.min.js +7 -0
  74. data/data/weaver/js/plugins/jquery-ui/LICENSE.txt +43 -0
  75. data/data/weaver/js/plugins/jquery-ui/images/ui-icons_444444_256x240.png +0 -0
  76. data/data/weaver/js/plugins/jquery-ui/images/ui-icons_555555_256x240.png +0 -0
  77. data/data/weaver/js/plugins/jquery-ui/images/ui-icons_777620_256x240.png +0 -0
  78. data/data/weaver/js/plugins/jquery-ui/images/ui-icons_777777_256x240.png +0 -0
  79. data/data/weaver/js/plugins/jquery-ui/images/ui-icons_cc0000_256x240.png +0 -0
  80. data/data/weaver/js/plugins/jquery-ui/images/ui-icons_ffffff_256x240.png +0 -0
  81. data/data/weaver/js/plugins/jquery-ui/jquery-ui.min.css +6 -3
  82. data/data/weaver/js/plugins/jquery-ui/jquery-ui.min.js +12 -11
  83. data/data/weaver/js/plugins/jvectormap/jquery-jvectormap-world-mill-en.js +481 -1
  84. data/data/weaver/js/plugins/ladda/ladda.jquery.min.js +8 -0
  85. data/data/weaver/js/plugins/ladda/ladda.min.js +8 -0
  86. data/data/weaver/js/plugins/ladda/spin.min.js +1 -0
  87. data/data/weaver/js/plugins/masonary/masonry.pkgd.min.js +2 -2
  88. data/data/weaver/js/plugins/nouslider/jquery.nouislider.min.js +2 -33
  89. data/data/weaver/js/plugins/pace/pace.min.js +2 -2
  90. data/data/weaver/js/plugins/pdfjs/pdf.js +10905 -0
  91. data/data/weaver/js/plugins/pdfjs/pdf.worker.js +43194 -0
  92. data/data/weaver/js/plugins/pwstrength/pwstrength-bootstrap.min.js +4 -0
  93. data/data/weaver/js/plugins/pwstrength/zxcvbn.js +28 -0
  94. data/data/weaver/js/plugins/steps/jquery.steps.min.js +6 -0
  95. data/data/weaver/js/plugins/summernote/summernote.min.js +4 -2
  96. data/data/weaver/js/plugins/switchery/switchery.js +1 -1
  97. data/data/weaver/js/plugins/topojson/LICENSE +26 -0
  98. data/data/weaver/js/plugins/topojson/topojson.js +534 -0
  99. data/data/weaver/js/plugins/touchpunch/jquery.ui.touch-punch.min.js +11 -0
  100. data/data/weaver/js/plugins/touchspin/jquery.bootstrap-touchspin.min.js +9 -0
  101. data/data/weaver/js/plugins/typehead/bootstrap3-typeahead.min.js +1 -0
  102. data/data/weaver/js/plugins/validate/jquery.validate.min.js +3 -3
  103. data/data/weaver/js/{inspinia.js → weaver.js} +34 -38
  104. data/lib/weaver.rb +1 -1
  105. data/lib/weaver/version.rb +1 -1
  106. metadata +58 -4
@@ -0,0 +1,646 @@
1
+ (function ($) {
2
+ "use strict";
3
+
4
+ var defaultOptions = {
5
+ tagClass: function(item) {
6
+ return 'label label-info';
7
+ },
8
+ itemValue: function(item) {
9
+ return item ? item.toString() : item;
10
+ },
11
+ itemText: function(item) {
12
+ return this.itemValue(item);
13
+ },
14
+ itemTitle: function(item) {
15
+ return null;
16
+ },
17
+ freeInput: true,
18
+ addOnBlur: true,
19
+ maxTags: undefined,
20
+ maxChars: undefined,
21
+ confirmKeys: [13, 44],
22
+ delimiter: ',',
23
+ delimiterRegex: null,
24
+ cancelConfirmKeysOnEmpty: true,
25
+ onTagExists: function(item, $tag) {
26
+ $tag.hide().fadeIn();
27
+ },
28
+ trimValue: false,
29
+ allowDuplicates: false
30
+ };
31
+
32
+ /**
33
+ * Constructor function
34
+ */
35
+ function TagsInput(element, options) {
36
+ this.itemsArray = [];
37
+
38
+ this.$element = $(element);
39
+ this.$element.hide();
40
+
41
+ this.isSelect = (element.tagName === 'SELECT');
42
+ this.multiple = (this.isSelect && element.hasAttribute('multiple'));
43
+ this.objectItems = options && options.itemValue;
44
+ this.placeholderText = element.hasAttribute('placeholder') ? this.$element.attr('placeholder') : '';
45
+ this.inputSize = Math.max(1, this.placeholderText.length);
46
+
47
+ this.$container = $('<div class="bootstrap-tagsinput"></div>');
48
+ this.$input = $('<input type="text" placeholder="' + this.placeholderText + '"/>').appendTo(this.$container);
49
+
50
+ this.$element.before(this.$container);
51
+
52
+ this.build(options);
53
+ }
54
+
55
+ TagsInput.prototype = {
56
+ constructor: TagsInput,
57
+
58
+ /**
59
+ * Adds the given item as a new tag. Pass true to dontPushVal to prevent
60
+ * updating the elements val()
61
+ */
62
+ add: function(item, dontPushVal, options) {
63
+ var self = this;
64
+
65
+ if (self.options.maxTags && self.itemsArray.length >= self.options.maxTags)
66
+ return;
67
+
68
+ // Ignore falsey values, except false
69
+ if (item !== false && !item)
70
+ return;
71
+
72
+ // Trim value
73
+ if (typeof item === "string" && self.options.trimValue) {
74
+ item = $.trim(item);
75
+ }
76
+
77
+ // Throw an error when trying to add an object while the itemValue option was not set
78
+ if (typeof item === "object" && !self.objectItems)
79
+ throw("Can't add objects when itemValue option is not set");
80
+
81
+ // Ignore strings only containg whitespace
82
+ if (item.toString().match(/^\s*$/))
83
+ return;
84
+
85
+ // If SELECT but not multiple, remove current tag
86
+ if (self.isSelect && !self.multiple && self.itemsArray.length > 0)
87
+ self.remove(self.itemsArray[0]);
88
+
89
+ if (typeof item === "string" && this.$element[0].tagName === 'INPUT') {
90
+ var delimiter = (self.options.delimiterRegex) ? self.options.delimiterRegex : self.options.delimiter;
91
+ var items = item.split(delimiter);
92
+ if (items.length > 1) {
93
+ for (var i = 0; i < items.length; i++) {
94
+ this.add(items[i], true);
95
+ }
96
+
97
+ if (!dontPushVal)
98
+ self.pushVal();
99
+ return;
100
+ }
101
+ }
102
+
103
+ var itemValue = self.options.itemValue(item),
104
+ itemText = self.options.itemText(item),
105
+ tagClass = self.options.tagClass(item),
106
+ itemTitle = self.options.itemTitle(item);
107
+
108
+ // Ignore items allready added
109
+ var existing = $.grep(self.itemsArray, function(item) { return self.options.itemValue(item) === itemValue; } )[0];
110
+ if (existing && !self.options.allowDuplicates) {
111
+ // Invoke onTagExists
112
+ if (self.options.onTagExists) {
113
+ var $existingTag = $(".tag", self.$container).filter(function() { return $(this).data("item") === existing; });
114
+ self.options.onTagExists(item, $existingTag);
115
+ }
116
+ return;
117
+ }
118
+
119
+ // if length greater than limit
120
+ if (self.items().toString().length + item.length + 1 > self.options.maxInputLength)
121
+ return;
122
+
123
+ // raise beforeItemAdd arg
124
+ var beforeItemAddEvent = $.Event('beforeItemAdd', { item: item, cancel: false, options: options});
125
+ self.$element.trigger(beforeItemAddEvent);
126
+ if (beforeItemAddEvent.cancel)
127
+ return;
128
+
129
+ // register item in internal array and map
130
+ self.itemsArray.push(item);
131
+
132
+ // add a tag element
133
+
134
+ var $tag = $('<span class="tag ' + htmlEncode(tagClass) + (itemTitle !== null ? ('" title="' + itemTitle) : '') + '">' + htmlEncode(itemText) + '<span data-role="remove"></span></span>');
135
+ $tag.data('item', item);
136
+ self.findInputWrapper().before($tag);
137
+ $tag.after(' ');
138
+
139
+ // add <option /> if item represents a value not present in one of the <select />'s options
140
+ if (self.isSelect && !$('option[value="' + encodeURIComponent(itemValue) + '"]',self.$element)[0]) {
141
+ var $option = $('<option selected>' + htmlEncode(itemText) + '</option>');
142
+ $option.data('item', item);
143
+ $option.attr('value', itemValue);
144
+ self.$element.append($option);
145
+ }
146
+
147
+ if (!dontPushVal)
148
+ self.pushVal();
149
+
150
+ // Add class when reached maxTags
151
+ if (self.options.maxTags === self.itemsArray.length || self.items().toString().length === self.options.maxInputLength)
152
+ self.$container.addClass('bootstrap-tagsinput-max');
153
+
154
+ self.$element.trigger($.Event('itemAdded', { item: item, options: options }));
155
+ },
156
+
157
+ /**
158
+ * Removes the given item. Pass true to dontPushVal to prevent updating the
159
+ * elements val()
160
+ */
161
+ remove: function(item, dontPushVal, options) {
162
+ var self = this;
163
+
164
+ if (self.objectItems) {
165
+ if (typeof item === "object")
166
+ item = $.grep(self.itemsArray, function(other) { return self.options.itemValue(other) == self.options.itemValue(item); } );
167
+ else
168
+ item = $.grep(self.itemsArray, function(other) { return self.options.itemValue(other) == item; } );
169
+
170
+ item = item[item.length-1];
171
+ }
172
+
173
+ if (item) {
174
+ var beforeItemRemoveEvent = $.Event('beforeItemRemove', { item: item, cancel: false, options: options });
175
+ self.$element.trigger(beforeItemRemoveEvent);
176
+ if (beforeItemRemoveEvent.cancel)
177
+ return;
178
+
179
+ $('.tag', self.$container).filter(function() { return $(this).data('item') === item; }).remove();
180
+ $('option', self.$element).filter(function() { return $(this).data('item') === item; }).remove();
181
+ if($.inArray(item, self.itemsArray) !== -1)
182
+ self.itemsArray.splice($.inArray(item, self.itemsArray), 1);
183
+ }
184
+
185
+ if (!dontPushVal)
186
+ self.pushVal();
187
+
188
+ // Remove class when reached maxTags
189
+ if (self.options.maxTags > self.itemsArray.length)
190
+ self.$container.removeClass('bootstrap-tagsinput-max');
191
+
192
+ self.$element.trigger($.Event('itemRemoved', { item: item, options: options }));
193
+ },
194
+
195
+ /**
196
+ * Removes all items
197
+ */
198
+ removeAll: function() {
199
+ var self = this;
200
+
201
+ $('.tag', self.$container).remove();
202
+ $('option', self.$element).remove();
203
+
204
+ while(self.itemsArray.length > 0)
205
+ self.itemsArray.pop();
206
+
207
+ self.pushVal();
208
+ },
209
+
210
+ /**
211
+ * Refreshes the tags so they match the text/value of their corresponding
212
+ * item.
213
+ */
214
+ refresh: function() {
215
+ var self = this;
216
+ $('.tag', self.$container).each(function() {
217
+ var $tag = $(this),
218
+ item = $tag.data('item'),
219
+ itemValue = self.options.itemValue(item),
220
+ itemText = self.options.itemText(item),
221
+ tagClass = self.options.tagClass(item);
222
+
223
+ // Update tag's class and inner text
224
+ $tag.attr('class', null);
225
+ $tag.addClass('tag ' + htmlEncode(tagClass));
226
+ $tag.contents().filter(function() {
227
+ return this.nodeType == 3;
228
+ })[0].nodeValue = htmlEncode(itemText);
229
+
230
+ if (self.isSelect) {
231
+ var option = $('option', self.$element).filter(function() { return $(this).data('item') === item; });
232
+ option.attr('value', itemValue);
233
+ }
234
+ });
235
+ },
236
+
237
+ /**
238
+ * Returns the items added as tags
239
+ */
240
+ items: function() {
241
+ return this.itemsArray;
242
+ },
243
+
244
+ /**
245
+ * Assembly value by retrieving the value of each item, and set it on the
246
+ * element.
247
+ */
248
+ pushVal: function() {
249
+ var self = this,
250
+ val = $.map(self.items(), function(item) {
251
+ return self.options.itemValue(item).toString();
252
+ });
253
+
254
+ self.$element.val(val, true).trigger('change');
255
+ },
256
+
257
+ /**
258
+ * Initializes the tags input behaviour on the element
259
+ */
260
+ build: function(options) {
261
+ var self = this;
262
+
263
+ self.options = $.extend({}, defaultOptions, options);
264
+ // When itemValue is set, freeInput should always be false
265
+ if (self.objectItems)
266
+ self.options.freeInput = false;
267
+
268
+ makeOptionItemFunction(self.options, 'itemValue');
269
+ makeOptionItemFunction(self.options, 'itemText');
270
+ makeOptionFunction(self.options, 'tagClass');
271
+
272
+ // Typeahead Bootstrap version 2.3.2
273
+ if (self.options.typeahead) {
274
+ var typeahead = self.options.typeahead || {};
275
+
276
+ makeOptionFunction(typeahead, 'source');
277
+
278
+ self.$input.typeahead($.extend({}, typeahead, {
279
+ source: function (query, process) {
280
+ function processItems(items) {
281
+ var texts = [];
282
+
283
+ for (var i = 0; i < items.length; i++) {
284
+ var text = self.options.itemText(items[i]);
285
+ map[text] = items[i];
286
+ texts.push(text);
287
+ }
288
+ process(texts);
289
+ }
290
+
291
+ this.map = {};
292
+ var map = this.map,
293
+ data = typeahead.source(query);
294
+
295
+ if ($.isFunction(data.success)) {
296
+ // support for Angular callbacks
297
+ data.success(processItems);
298
+ } else if ($.isFunction(data.then)) {
299
+ // support for Angular promises
300
+ data.then(processItems);
301
+ } else {
302
+ // support for functions and jquery promises
303
+ $.when(data)
304
+ .then(processItems);
305
+ }
306
+ },
307
+ updater: function (text) {
308
+ self.add(this.map[text]);
309
+ return this.map[text];
310
+ },
311
+ matcher: function (text) {
312
+ return (text.toLowerCase().indexOf(this.query.trim().toLowerCase()) !== -1);
313
+ },
314
+ sorter: function (texts) {
315
+ return texts.sort();
316
+ },
317
+ highlighter: function (text) {
318
+ var regex = new RegExp( '(' + this.query + ')', 'gi' );
319
+ return text.replace( regex, "<strong>$1</strong>" );
320
+ }
321
+ }));
322
+ }
323
+
324
+ // typeahead.js
325
+ if (self.options.typeaheadjs) {
326
+ var typeaheadConfig = null;
327
+ var typeaheadDatasets = {};
328
+
329
+ // Determine if main configurations were passed or simply a dataset
330
+ var typeaheadjs = self.options.typeaheadjs;
331
+ if ($.isArray(typeaheadjs)) {
332
+ typeaheadConfig = typeaheadjs[0];
333
+ typeaheadDatasets = typeaheadjs[1];
334
+ } else {
335
+ typeaheadDatasets = typeaheadjs;
336
+ }
337
+
338
+ self.$input.typeahead(typeaheadConfig, typeaheadDatasets).on('typeahead:selected', $.proxy(function (obj, datum) {
339
+ if (typeaheadDatasets.valueKey)
340
+ self.add(datum[typeaheadDatasets.valueKey]);
341
+ else
342
+ self.add(datum);
343
+ self.$input.typeahead('val', '');
344
+ }, self));
345
+ }
346
+
347
+ self.$container.on('click', $.proxy(function(event) {
348
+ if (! self.$element.attr('disabled')) {
349
+ self.$input.removeAttr('disabled');
350
+ }
351
+ self.$input.focus();
352
+ }, self));
353
+
354
+ if (self.options.addOnBlur && self.options.freeInput) {
355
+ self.$input.on('focusout', $.proxy(function(event) {
356
+ // HACK: only process on focusout when no typeahead opened, to
357
+ // avoid adding the typeahead text as tag
358
+ if ($('.typeahead, .twitter-typeahead', self.$container).length === 0) {
359
+ self.add(self.$input.val());
360
+ self.$input.val('');
361
+ }
362
+ }, self));
363
+ }
364
+
365
+
366
+ self.$container.on('keydown', 'input', $.proxy(function(event) {
367
+ var $input = $(event.target),
368
+ $inputWrapper = self.findInputWrapper();
369
+
370
+ if (self.$element.attr('disabled')) {
371
+ self.$input.attr('disabled', 'disabled');
372
+ return;
373
+ }
374
+
375
+ switch (event.which) {
376
+ // BACKSPACE
377
+ case 8:
378
+ if (doGetCaretPosition($input[0]) === 0) {
379
+ var prev = $inputWrapper.prev();
380
+ if (prev.length) {
381
+ self.remove(prev.data('item'));
382
+ }
383
+ }
384
+ break;
385
+
386
+ // DELETE
387
+ case 46:
388
+ if (doGetCaretPosition($input[0]) === 0) {
389
+ var next = $inputWrapper.next();
390
+ if (next.length) {
391
+ self.remove(next.data('item'));
392
+ }
393
+ }
394
+ break;
395
+
396
+ // LEFT ARROW
397
+ case 37:
398
+ // Try to move the input before the previous tag
399
+ var $prevTag = $inputWrapper.prev();
400
+ if ($input.val().length === 0 && $prevTag[0]) {
401
+ $prevTag.before($inputWrapper);
402
+ $input.focus();
403
+ }
404
+ break;
405
+ // RIGHT ARROW
406
+ case 39:
407
+ // Try to move the input after the next tag
408
+ var $nextTag = $inputWrapper.next();
409
+ if ($input.val().length === 0 && $nextTag[0]) {
410
+ $nextTag.after($inputWrapper);
411
+ $input.focus();
412
+ }
413
+ break;
414
+ default:
415
+ // ignore
416
+ }
417
+
418
+ // Reset internal input's size
419
+ var textLength = $input.val().length,
420
+ wordSpace = Math.ceil(textLength / 5),
421
+ size = textLength + wordSpace + 1;
422
+ $input.attr('size', Math.max(this.inputSize, $input.val().length));
423
+ }, self));
424
+
425
+ self.$container.on('keypress', 'input', $.proxy(function(event) {
426
+ var $input = $(event.target);
427
+
428
+ if (self.$element.attr('disabled')) {
429
+ self.$input.attr('disabled', 'disabled');
430
+ return;
431
+ }
432
+
433
+ var text = $input.val(),
434
+ maxLengthReached = self.options.maxChars && text.length >= self.options.maxChars;
435
+ if (self.options.freeInput && (keyCombinationInList(event, self.options.confirmKeys) || maxLengthReached)) {
436
+ // Only attempt to add a tag if there is data in the field
437
+ if (text.length !== 0) {
438
+ self.add(maxLengthReached ? text.substr(0, self.options.maxChars) : text);
439
+ $input.val('');
440
+ }
441
+
442
+ // If the field is empty, let the event triggered fire as usual
443
+ if (self.options.cancelConfirmKeysOnEmpty === false) {
444
+ event.preventDefault();
445
+ }
446
+ }
447
+
448
+ // Reset internal input's size
449
+ var textLength = $input.val().length,
450
+ wordSpace = Math.ceil(textLength / 5),
451
+ size = textLength + wordSpace + 1;
452
+ $input.attr('size', Math.max(this.inputSize, $input.val().length));
453
+ }, self));
454
+
455
+ // Remove icon clicked
456
+ self.$container.on('click', '[data-role=remove]', $.proxy(function(event) {
457
+ if (self.$element.attr('disabled')) {
458
+ return;
459
+ }
460
+ self.remove($(event.target).closest('.tag').data('item'));
461
+ }, self));
462
+
463
+ // Only add existing value as tags when using strings as tags
464
+ if (self.options.itemValue === defaultOptions.itemValue) {
465
+ if (self.$element[0].tagName === 'INPUT') {
466
+ self.add(self.$element.val());
467
+ } else {
468
+ $('option', self.$element).each(function() {
469
+ self.add($(this).attr('value'), true);
470
+ });
471
+ }
472
+ }
473
+ },
474
+
475
+ /**
476
+ * Removes all tagsinput behaviour and unregsiter all event handlers
477
+ */
478
+ destroy: function() {
479
+ var self = this;
480
+
481
+ // Unbind events
482
+ self.$container.off('keypress', 'input');
483
+ self.$container.off('click', '[role=remove]');
484
+
485
+ self.$container.remove();
486
+ self.$element.removeData('tagsinput');
487
+ self.$element.show();
488
+ },
489
+
490
+ /**
491
+ * Sets focus on the tagsinput
492
+ */
493
+ focus: function() {
494
+ this.$input.focus();
495
+ },
496
+
497
+ /**
498
+ * Returns the internal input element
499
+ */
500
+ input: function() {
501
+ return this.$input;
502
+ },
503
+
504
+ /**
505
+ * Returns the element which is wrapped around the internal input. This
506
+ * is normally the $container, but typeahead.js moves the $input element.
507
+ */
508
+ findInputWrapper: function() {
509
+ var elt = this.$input[0],
510
+ container = this.$container[0];
511
+ while(elt && elt.parentNode !== container)
512
+ elt = elt.parentNode;
513
+
514
+ return $(elt);
515
+ }
516
+ };
517
+
518
+ /**
519
+ * Register JQuery plugin
520
+ */
521
+ $.fn.tagsinput = function(arg1, arg2, arg3) {
522
+ var results = [];
523
+
524
+ this.each(function() {
525
+ var tagsinput = $(this).data('tagsinput');
526
+ // Initialize a new tags input
527
+ if (!tagsinput) {
528
+ tagsinput = new TagsInput(this, arg1);
529
+ $(this).data('tagsinput', tagsinput);
530
+ results.push(tagsinput);
531
+
532
+ if (this.tagName === 'SELECT') {
533
+ $('option', $(this)).attr('selected', 'selected');
534
+ }
535
+
536
+ // Init tags from $(this).val()
537
+ $(this).val($(this).val());
538
+ } else if (!arg1 && !arg2) {
539
+ // tagsinput already exists
540
+ // no function, trying to init
541
+ results.push(tagsinput);
542
+ } else if(tagsinput[arg1] !== undefined) {
543
+ // Invoke function on existing tags input
544
+ if(tagsinput[arg1].length === 3 && arg3 !== undefined){
545
+ var retVal = tagsinput[arg1](arg2, null, arg3);
546
+ }else{
547
+ var retVal = tagsinput[arg1](arg2);
548
+ }
549
+ if (retVal !== undefined)
550
+ results.push(retVal);
551
+ }
552
+ });
553
+
554
+ if ( typeof arg1 == 'string') {
555
+ // Return the results from the invoked function calls
556
+ return results.length > 1 ? results : results[0];
557
+ } else {
558
+ return results;
559
+ }
560
+ };
561
+
562
+ $.fn.tagsinput.Constructor = TagsInput;
563
+
564
+ /**
565
+ * Most options support both a string or number as well as a function as
566
+ * option value. This function makes sure that the option with the given
567
+ * key in the given options is wrapped in a function
568
+ */
569
+ function makeOptionItemFunction(options, key) {
570
+ if (typeof options[key] !== 'function') {
571
+ var propertyName = options[key];
572
+ options[key] = function(item) { return item[propertyName]; };
573
+ }
574
+ }
575
+ function makeOptionFunction(options, key) {
576
+ if (typeof options[key] !== 'function') {
577
+ var value = options[key];
578
+ options[key] = function() { return value; };
579
+ }
580
+ }
581
+ /**
582
+ * HtmlEncodes the given value
583
+ */
584
+ var htmlEncodeContainer = $('<div />');
585
+ function htmlEncode(value) {
586
+ if (value) {
587
+ return htmlEncodeContainer.text(value).html();
588
+ } else {
589
+ return '';
590
+ }
591
+ }
592
+
593
+ /**
594
+ * Returns the position of the caret in the given input field
595
+ * http://flightschool.acylt.com/devnotes/caret-position-woes/
596
+ */
597
+ function doGetCaretPosition(oField) {
598
+ var iCaretPos = 0;
599
+ if (document.selection) {
600
+ oField.focus ();
601
+ var oSel = document.selection.createRange();
602
+ oSel.moveStart ('character', -oField.value.length);
603
+ iCaretPos = oSel.text.length;
604
+ } else if (oField.selectionStart || oField.selectionStart == '0') {
605
+ iCaretPos = oField.selectionStart;
606
+ }
607
+ return (iCaretPos);
608
+ }
609
+
610
+ /**
611
+ * Returns boolean indicates whether user has pressed an expected key combination.
612
+ * @param object keyPressEvent: JavaScript event object, refer
613
+ * http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
614
+ * @param object lookupList: expected key combinations, as in:
615
+ * [13, {which: 188, shiftKey: true}]
616
+ */
617
+ function keyCombinationInList(keyPressEvent, lookupList) {
618
+ var found = false;
619
+ $.each(lookupList, function (index, keyCombination) {
620
+ if (typeof (keyCombination) === 'number' && keyPressEvent.which === keyCombination) {
621
+ found = true;
622
+ return false;
623
+ }
624
+
625
+ if (keyPressEvent.which === keyCombination.which) {
626
+ var alt = !keyCombination.hasOwnProperty('altKey') || keyPressEvent.altKey === keyCombination.altKey,
627
+ shift = !keyCombination.hasOwnProperty('shiftKey') || keyPressEvent.shiftKey === keyCombination.shiftKey,
628
+ ctrl = !keyCombination.hasOwnProperty('ctrlKey') || keyPressEvent.ctrlKey === keyCombination.ctrlKey;
629
+ if (alt && shift && ctrl) {
630
+ found = true;
631
+ return false;
632
+ }
633
+ }
634
+ });
635
+
636
+ return found;
637
+ }
638
+
639
+ /**
640
+ * Initialize tagsinput behaviour on inputs and selects which have
641
+ * data-role=tagsinput
642
+ */
643
+ $(function() {
644
+ $("input[data-role=tagsinput], select[multiple][data-role=tagsinput]").tagsinput();
645
+ });
646
+ })(window.jQuery);