1/* 2 3 jQuery Tags Input Plugin 1.3.3 4 5 Copyright (c) 2011 XOXCO, Inc 6 7 Documentation for this plugin lives here: 8 http://xoxco.com/clickable/jquery-tags-input 9 10 Licensed under the MIT license: 11 http://www.opensource.org/licenses/mit-license.php 12 13 [email protected] 14 15*/ 16 17(function ($) { 18 19 var delimiter = new Array(); 20 var tags_callbacks = new Array(); 21 $.fn.doAutosize = function (o) { 22 var minWidth = $(this).data('minwidth'), 23 maxWidth = $(this).data('maxwidth'), 24 val = '', 25 input = $(this), 26 testSubject = $('#' + $(this).data('tester_id')); 27 28 if (val === (val = input.val())) { return; } 29 30 // Enter new content into testSubject 31 var escaped = val.replace(/&/g, '&').replace(/\s/g, ' ').replace(/</g, '<').replace(/>/g, '>'); 32 testSubject.html(escaped); 33 // Calculate new width + whether to change 34 var testerWidth = testSubject.width(), 35 newWidth = (testerWidth + o.comfortZone) >= minWidth ? testerWidth + o.comfortZone : minWidth, 36 currentWidth = input.width(), 37 isValidWidthChange = (newWidth < currentWidth && newWidth >= minWidth) 38 || (newWidth > minWidth && newWidth < maxWidth); 39 40 // Animate width 41 if (isValidWidthChange) { 42 input.width(newWidth); 43 } 44 45 46 }; 47 $.fn.resetAutosize = function (options) { 48 // alert(JSON.stringify(options)); 49 var minWidth = $(this).data('minwidth') || options.minInputWidth || $(this).width(), 50 maxWidth = $(this).data('maxwidth') || options.maxInputWidth || ($(this).closest('.tagsinput').width() - options.inputPadding), 51 val = '', 52 input = $(this), 53 testSubject = $('<tester/>').css({ 54 position: 'absolute', 55 top: -9999, 56 left: -9999, 57 width: 'auto', 58 fontSize: input.css('fontSize'), 59 fontFamily: input.css('fontFamily'), 60 fontWeight: input.css('fontWeight'), 61 letterSpacing: input.css('letterSpacing'), 62 whiteSpace: 'nowrap' 63 }), 64 testerId = $(this).attr('id') + '_autosize_tester'; 65 if (!$('#' + testerId).length > 0) { 66 testSubject.attr('id', testerId); 67 testSubject.appendTo('body'); 68 } 69 70 input.data('minwidth', minWidth); 71 input.data('maxwidth', maxWidth); 72 input.data('tester_id', testerId); 73 input.css('width', minWidth); 74 }; 75 76 $.fn.addTag = function (value, options) { 77 options = jQuery.extend({ focus: false, callback: true }, options); 78 this.each(function () { 79 var id = $(this).attr('id'); 80 81 var tagslist = $(this).val().split(delimiter[id]); 82 if (tagslist[0] == '') { 83 tagslist = new Array(); 84 } 85 86 value = jQuery.trim(value); 87 88 if (options.unique) { 89 var skipTag = $(this).tagExist(value); 90 if (skipTag == true) { 91 //Marks fake input as not_valid to let styling it 92 $('#' + id + '_tag').addClass('not_valid'); 93 } 94 } else { 95 var skipTag = false; 96 } 97 98 if (value != '' && skipTag != true) { 99 $('<span>').addClass('tag').append( 100 $('<span>').text(value).append(' '), 101 $('<a>', { 102 href: '#', 103 title: 'Removing tag', 104 text: 'x' 105 }).click(function () { 106 return $('#' + id).removeTag(escape(value)); 107 }) 108 ).insertBefore('#' + id + '_addTag'); 109 110 tagslist.push(value); 111 112 $('#' + id + '_tag').val(''); 113 if (options.focus) { 114 $('#' + id + '_tag').focus(); 115 } else { 116 $('#' + id + '_tag').blur(); 117 } 118 119 $.fn.tagsInput.updateTagsField(this, tagslist); 120 121 if (options.callback && tags_callbacks[id] && tags_callbacks[id]['onAddTag']) { 122 var f = tags_callbacks[id]['onAddTag']; 123 f.call(this, value); 124 } 125 if (tags_callbacks[id] && tags_callbacks[id]['onChange']) { 126 var i = tagslist.length; 127 var f = tags_callbacks[id]['onChange']; 128 f.call(this, $(this), tagslist[i - 1]); 129 } 130 } 131 132 }); 133 134 return false; 135 }; 136 137 $.fn.removeTag = function (value) { 138 value = unescape(value); 139 this.each(function () { 140 var id = $(this).attr('id'); 141 142 var old = $(this).val().split(delimiter[id]); 143 144 $('#' + id + '_tagsinput .tag').remove(); 145 str = ''; 146 for (i = 0; i < old.length; i++) { 147 if (old[i] != value) { 148 str = str + delimiter[id] + old[i]; 149 } 150 } 151 152 $.fn.tagsInput.importTags(this, str); 153 154 if (tags_callbacks[id] && tags_callbacks[id]['onRemoveTag']) { 155 var f = tags_callbacks[id]['onRemoveTag']; 156 f.call(this, value); 157 } 158 }); 159 160 return false;
161 }; 162 163 $.fn.tagExist = function (val) { 164 var id = $(this).attr('id'); 165 var tagslist = $(this).val().split(delimiter[id]); 166 return (jQuery.inArray(val, tagslist) >= 0); //true when tag exists, false when not 167 }; 168 169 // clear all existing tags and import new ones from a string 170 $.fn.importTags = function (str) { 171 var id = $(this).attr('id'); 172 $('#' + id + '_tagsinput .tag').remove(); 173 $.fn.tagsInput.importTags(this, str); 174 } 175 176 $.fn.tagsInput = function (options) { 177 var settings = jQuery.extend({ 178 interactive: true, 179 defaultText: 'Tags', 180 minChars: 0, 181 width: '99%', 182 height: '50px', 183 autocomplete: { selectFirst: false }, 184 hide: true, 185 delimiter: ',', 186 unique: true, 187 removeWithBackspace: true, 188 placeholderColor: '#666666', 189 autosize: true, 190 comfortZone: 20, 191 inputPadding: 6 * 2 192 }, options); 193 194 var uniqueIdCounter = 0; 195 196 this.each(function () { 197 // If we have already initialized the field, do not do it again 198 if (typeof $(this).attr('data-tagsinput-init') !== 'undefined') { 199 return; 200 } 201 202 // Mark the field as having been initialized 203 $(this).attr('data-tagsinput-init', true); 204 205 if (settings.hide) { 206 $(this).hide(); 207 } 208 var id = $(this).attr('id'); 209 if (!id || delimiter[$(this).attr('id')]) { 210 id = $(this).attr('id', 'tags' + new Date().getTime() + (uniqueIdCounter++)).attr('id'); 211 } 212 213 var data = jQuery.extend({ 214 pid: id, 215 real_input: '#' + id, 216 holder: '#' + id + '_tagsinput', 217 input_wrapper: '#' + id + '_addTag', 218 fake_input: '#' + id + '_tag' 219 }, settings); 220 221 delimiter[id] = data.delimiter; 222 223 if (settings.onAddTag || settings.onRemoveTag || settings.onChange) { 224 tags_callbacks[id] = new Array(); 225 tags_callbacks[id]['onAddTag'] = settings.onAddTag; 226 tags_callbacks[id]['onRemoveTag'] = settings.onRemoveTag; 227 tags_callbacks[id]['onChange'] = settings.onChange; 228 } 229 230 var markup = '<div id="' + id + '_tagsinput" class="tagsinput"><div id="' + id + '_addTag">'; 231 232 if (settings.interactive) { 233 markup = markup + '<input id="' + id + '_tag" value="" data-default="' + settings.defaultText + '" />'; 234 } 235 236 markup = markup + '</div><div class="tags_clear"></div></div>'; 237 238 $(markup).insertAfter(this); 239 240 $(data.holder).css('width', settings.width); 241 $(data.holder).css('min-height', settings.height); 242 $(data.holder).css('height', settings.height); 243 244 if ($(data.real_input).val() != '') { 245 $.fn.tagsInput.importTags($(data.real_input), $(data.real_input).val()); 246 } 247 if (settings.interactive) { 248 $(data.fake_input).val($(data.fake_input).attr('data-default')); 249 $(data.fake_input).css('color', settings.placeholderColor); 250 $(data.fake_input).resetAutosize(settings); 251 252 $(data.holder).bind('click', data, function (event) { 253 $(event.data.fake_input).focus(); 254 }); 255 256 $(data.fake_input).bind('focus', data, function (event) { 257 if ($(event.data.fake_input).val() == $(event.data.fake_input).attr('data-default')) { 258 $(event.data.fake_input).val(''); 259 } 260 $(event.data.fake_input).css('color', '#000000'); 261 }); 262 263 if (settings.autocomplete_url != undefined) { 264 autocomplete_options = { source: settings.autocomplete_url }; 265 for (attrname in settings.autocomplete) { 266 autocomplete_options[attrname] = settings.autocomplete[attrname]; 267 } 268 269 if (jQuery.Autocompleter !== undefined) { 270 $(data.fake_input).autocomplete(settings.autocomplete_url, settings.autocomplete); 271 $(data.fake_input).bind('result', data, function (event, data, formatted) { 272 if (data) { 273 $('#' + id).addTag(data[0] + "", { focus: true, unique: (settings.unique) }); 274 } 275 }); 276 } else if (jQuery.ui.autocomplete !== undefined) { 277 $(data.fake_input).autocomplete(autocomplete_options); 278 $(data.fake_input).bind('autocompleteselect', data, function (event, ui) { 279 $(event.data.real_input).addTag(ui.item.value, { focus: true, unique: (settings.unique) }); 280 return false; 281 }); 282 } 283 284 285 } else { 286 // if a user tabs out of the field, create a new tag 287 // this is only available if autocomplete is not used. 288 $(data.fake_input).bind('blur', data, function (event) { 289 var d = $(this).attr('data-default'); 290 if ($(event.data.fake_input).val() != '' && $(event.data.fake_input).val() != d) { 291 if ((event.data.minChars <= $(event.data.fake_input).val().length) && (!event.data.maxChars || (event.data.maxChars >= $(event.data.fake_input).val().length))) 292 $(event.data.real_input).addTag($(event.data.fake_input).val(), { focus: true, unique: (settings.unique) }); 293 } else { 294 $(event.data.fake_input).val($(event.data.fake_input).attr('data-default')); 295 $(event.data.fake_input).css('color', settings.placeholderColor); 296 } 297 return false;
298 }); 299 300 } 301 // if user types a default delimiter like comma,semicolon and then create a new tag 302 $(data.fake_input).bind('keypress', data, function (event) { 303 if (_checkDelimiter(event)) { 304 event.preventDefault(); 305 if ((event.data.minChars <= $(event.data.fake_input).val().length) && (!event.data.maxChars || (event.data.maxChars >= $(event.data.fake_input).val().length))) 306 $(event.data.real_input).addTag($(event.data.fake_input).val(), { focus: true, unique: (settings.unique) }); 307 $(event.data.fake_input).resetAutosize(settings); 308 return false; 309 } else if (event.data.autosize) { 310 $(event.data.fake_input).doAutosize(settings); 311 312 } 313 }); 314 //Delete last tag on backspace 315 data.removeWithBackspace && $(data.fake_input).bind('keydown', function (event) { 316 if (event.keyCode == 8 && $(this).val() == '') { 317 event.preventDefault(); 318 var last_tag = $(this).closest('.tagsinput').find('.tag:last').text(); 319 var id = $(this).attr('id').replace(/_tag$/, ''); 320 last_tag = last_tag.replace(/[\s]+x$/, ''); 321 $('#' + id).removeTag(escape(last_tag)); 322 $(this).trigger('focus'); 323 } 324 }); 325 $(data.fake_input).blur(); 326 327 //Removes the not_valid class when user changes the value of the fake input 328 if (data.unique) { 329 $(data.fake_input).keydown(function (event) { 330 if (event.keyCode == 8 || String.fromCharCode(event.which).match(/\w+|[áéÃóúÃÃÃÃÃñÃ,/]+/)) { 331 $(this).removeClass('not_valid'); 332 } 333 }); 334 } 335 } // if settings.interactive 336 }); 337 338 return this; 339 340 }; 341 342 $.fn.tagsInput.updateTagsField = function (obj, tagslist) { 343 var id = $(obj).attr('id'); 344 $(obj).val(tagslist.join(delimiter[id])); 345 }; 346 347 $.fn.tagsInput.importTags = function (obj, val) { 348 $(obj).val(''); 349 var id = $(obj).attr('id'); 350 var tags = val.split(delimiter[id]); 351 for (i = 0; i < tags.length; i++) { 352 $(obj).addTag(tags[i], { focus: false, callback: false }); 353 } 354 if (tags_callbacks[id] && tags_callbacks[id]['onChange']) { 355 var f = tags_callbacks[id]['onChange']; 356 f.call(obj, obj, tags[i]); 357 } 358 }; 359 360 /** 361 * check delimiter Array 362 * @param event 363 * @returns {boolean} 364 * @private 365 */ 366 var _checkDelimiter = function (event) { 367 var found = false; 368 if (event.which == 13) { 369 return true; 370 } 371 372 if (typeof event.data.delimiter === 'string') { 373 if (event.which == event.data.delimiter.charCodeAt(0)) { 374 found = true; 375 } 376 } else { 377 $.each(event.data.delimiter, function (index, delimiter) { 378 if (event.which == delimiter.charCodeAt(0)) { 379 found = true; 380 } 381 }); 382 } 383 384 return found; 385 } 386})(jQuery);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.