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 { 127 var i = tagslist.length; 128 var f = tags_callbacks[id]['onChange']; 129 f.call(this, $(this), tagslist[i-1]); 130 } 131 } 132 133 }); 134 135 return false;
136 }; 137 138 $.fn.removeTag = function(value) { 139 value = unescape(value); 140 this.each(function() { 141 var id = $(this).attr('id'); 142 143 var old = $(this).val().split(delimiter[id]); 144 145 $('#'+id+'_tagsinput .tag').remove(); 146 str = ''; 147 for (i=0; i< old.length; i++) { 148 if (old[i]!=value) { 149 str = str + delimiter[id] +old[i]; 150 } 151 } 152 153 $.fn.tagsInput.importTags(this,str); 154 155 if (tags_callbacks[id] && tags_callbacks[id]['onRemoveTag']) { 156 var f = tags_callbacks[id]['onRemoveTag']; 157 f.call(this, value); 158 } 159 }); 160 161 return false; 162 }; 163 164 $.fn.tagExist = function(val) { 165 var id = $(this).attr('id'); 166 var tagslist = $(this).val().split(delimiter[id]); 167 return (jQuery.inArray(val, tagslist) >= 0); //true when tag exists, false when not 168 }; 169 170 // clear all existing tags and import new ones from a string 171 $.fn.importTags = function(str) { 172 var id = $(this).attr('id'); 173 $('#'+id+'_tagsinput .tag').remove(); 174 $.fn.tagsInput.importTags(this,str); 175 } 176 177 $.fn.tagsInput = function(options) { 178 var settings = jQuery.extend({ 179 interactive:true, 180 defaultText:'add keyword', 181 minChars:0, 182 width:'auto', 183 height:'45px', 184 autocomplete: {selectFirst: false }, 185 hide:true, 186 delimiter: ',', 187 unique:true, 188 removeWithBackspace:true, 189 placeholderColor:'#666666', 190 autosize: true, 191 comfortZone: 20, 192 inputPadding: 6*2 193 },options); 194 195 var uniqueIdCounter = 0; 196 197 this.each(function() { 198 // If we have already initialized the field, do not do it again 199 if (typeof $(this).attr('data-tagsinput-init') !== 'undefined') { 200 return; 201 } 202 203 // Mark the field as having been initialized 204 $(this).attr('data-tagsinput-init', true); 205 206 if (settings.hide) { 207 $(this).hide(); 208 } 209 var id = $(this).attr('id'); 210 if (!id || delimiter[$(this).attr('id')]) { 211 id = $(this).attr('id', 'tags' + new Date().getTime() + (uniqueIdCounter++)).attr('id'); 212 } 213 214 var data = jQuery.extend({ 215 pid:id, 216 real_input: '#'+id, 217 holder: '#'+id+'_tagsinput', 218 input_wrapper: '#'+id+'_addTag', 219 fake_input: '#'+id+'_tag' 220 },settings); 221 222 delimiter[id] = data.delimiter; 223 224 if (settings.onAddTag || settings.onRemoveTag || settings.onChange) { 225 tags_callbacks[id] = new Array(); 226 tags_callbacks[id]['onAddTag'] = settings.onAddTag; 227 tags_callbacks[id]['onRemoveTag'] = settings.onRemoveTag; 228 tags_callbacks[id]['onChange'] = settings.onChange; 229 } 230 231 var markup = '<div id="'+id+'_tagsinput" class="tagsinput"><div id="'+id+'_addTag">'; 232 233 if (settings.interactive) { 234 markup = markup + '<input id="'+id+'_tag" value="" data-default="'+settings.defaultText+'" />'; 235 } 236 237 markup = markup + '</div><div class="tags_clear"></div></div>'; 238 239 $(markup).insertAfter(this); 240 241 $(data.holder).css('width',settings.width); 242 $(data.holder).css('min-height',settings.height); 243 $(data.holder).css('height',settings.height); 244 245 if ($(data.real_input).val()!='') { 246 $.fn.tagsInput.importTags($(data.real_input),$(data.real_input).val()); 247 } 248 if (settings.interactive) { 249 $(data.fake_input).val($(data.fake_input).attr('data-default')); 250 $(data.fake_input).css('color',settings.placeholderColor); 251 $(data.fake_input).resetAutosize(settings); 252 253 $(data.holder).bind('click',data,function(event) { 254 $(event.data.fake_input).focus(); 255 }); 256 257 $(data.fake_input).bind('focus',data,function(event) { 258 if ($(event.data.fake_input).val()==$(event.data.fake_input).attr('data-default')) { 259 $(event.data.fake_input).val(''); 260 } 261 $(event.data.fake_input).css('color','#000000'); 262 }); 263 264 if (settings.autocomplete_url != undefined) { 265 autocomplete_options = {source: settings.autocomplete_url}; 266 for (attrname in settings.autocomplete) { 267 autocomplete_options[attrname] = settings.autocomplete[attrname]; 268 } 269 270 if (jQuery.Autocompleter !== undefined) { 271 $(data.fake_input).autocomplete(settings.autocomplete_url, settings.autocomplete); 272 $(data.fake_input).bind('result',data,function(event,data,formatted) { 273 if (data) { 274 $('#'+id).addTag(data[0] + "",{focus:true,unique:(settings.unique)}); 275 } 276 }); 277 } else if (jQuery.ui.autocomplete !== undefined) { 278 $(data.fake_input).autocomplete(autocomplete_options); 279 $(data.fake_input).bind('autocompleteselect',data,function(event,ui) { 280 $(event.data.real_input).addTag(ui.item.value,{focus:true,unique:(settings.unique)}); 281 return false;
282 }); 283 } 284 285 286 } else { 287 // if a user tabs out of the field, create a new tag 288 // this is only available if autocomplete is not used. 289 $(data.fake_input).bind('blur',data,function(event) { 290 var d = $(this).attr('data-default'); 291 if ($(event.data.fake_input).val()!='' && $(event.data.fake_input).val()!=d) { 292 if( (event.data.minChars <= $(event.data.fake_input).val().length) && (!event.data.maxChars || (event.data.maxChars >= $(event.data.fake_input).val().length)) ) 293 $(event.data.real_input).addTag($(event.data.fake_input).val(),{focus:true,unique:(settings.unique)}); 294 } else { 295 $(event.data.fake_input).val($(event.data.fake_input).attr('data-default')); 296 $(event.data.fake_input).css('color',settings.placeholderColor); 297 } 298 return false; 299 }); 300 301 } 302 // if user types a default delimiter like comma,semicolon and then create a new tag 303 $(data.fake_input).bind('keypress',data,function(event) { 304 if (_checkDelimiter(event)) { 305 event.preventDefault(); 306 if( (event.data.minChars <= $(event.data.fake_input).val().length) && (!event.data.maxChars || (event.data.maxChars >= $(event.data.fake_input).val().length)) ) 307 $(event.data.real_input).addTag($(event.data.fake_input).val(),{focus:true,unique:(settings.unique)}); 308 $(event.data.fake_input).resetAutosize(settings); 309 return false; 310 } else if (event.data.autosize) { 311 $(event.data.fake_input).doAutosize(settings); 312 313 } 314 }); 315 //Delete last tag on backspace 316 data.removeWithBackspace && $(data.fake_input).bind('keydown', function(event) 317 { 318 if(event.keyCode == 8 && $(this).val() == '') 319 { 320 event.preventDefault(); 321 var last_tag = $(this).closest('.tagsinput').find('.tag:last').text(); 322 var id = $(this).attr('id').replace(/_tag$/, ''); 323 last_tag = last_tag.replace(/[\s]+x$/, ''); 324 $('#' + id).removeTag(escape(last_tag)); 325 $(this).trigger('focus'); 326 } 327 }); 328 $(data.fake_input).blur(); 329 330 //Removes the not_valid class when user changes the value of the fake input 331 if(data.unique) { 332 $(data.fake_input).keydown(function(event){ 333 if(event.keyCode == 8 || String.fromCharCode(event.which).match(/\w+|[áéÃóúÃÃÃÃÃñÃ,/]+/)) { 334 $(this).removeClass('not_valid'); 335 } 336 }); 337 } 338 } // if settings.interactive 339 }); 340 341 return this; 342 343 }; 344 345 $.fn.tagsInput.updateTagsField = function(obj,tagslist) { 346 var id = $(obj).attr('id'); 347 $(obj).val(tagslist.join(delimiter[id])); 348 }; 349 350 $.fn.tagsInput.importTags = function(obj,val) { 351 $(obj).val(''); 352 var id = $(obj).attr('id'); 353 var tags = val.split(delimiter[id]); 354 for (i=0; i<tags.length; i++) { 355 $(obj).addTag(tags[i],{focus:false,callback:false}); 356 } 357 if(tags_callbacks[id] && tags_callbacks[id]['onChange']) 358 { 359 var f = tags_callbacks[id]['onChange']; 360 f.call(obj, obj, tags[i]); 361 } 362 }; 363 364 /** 365 * check delimiter Array 366 * @param event 367 * @returns {boolean} 368 * @private 369 */ 370 var _checkDelimiter = function(event){ 371 var found = false; 372 if (event.which == 13) { 373 return true; 374 } 375 376 if (typeof event.data.delimiter === 'string') { 377 if (event.which == event.data.delimiter.charCodeAt(0)) { 378 found = true; 379 } 380 } else { 381 $.each(event.data.delimiter, function(index, delimiter) { 382 if (event.which == delimiter.charCodeAt(0)) { 383 found = true; 384 } 385 }); 386 } 387 388 return found; 389 } 390})(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.