weaver 0.6.0 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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);