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 class="tagsinput-remove-link">', { 102 href : '#', 103 title : 'Remove tag', 104 text : '' 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 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:'', 181 minChars:0, 182 width:'', 183 height:'', 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 this.each(function() { 196 if (settings.hide) { 197 $(this).hide(); 198 } 199 var id = $(this).attr('id'); 200 if (!id || delimiter[$(this).attr('id')]) { 201 id = $(this).attr('id', 'tags' + new Date().getTime()).attr('id'); 202 } 203 204 var data = jQuery.extend({ 205 pid:id, 206 real_input: '#'+id, 207 holder: '#'+id+'_tagsinput', 208 input_wrapper: '#'+id+'_addTag', 209 fake_input: '#'+id+'_tag' 210 },settings); 211 212 delimiter[id] = data.delimiter; 213 214 if (settings.onAddTag || settings.onRemoveTag || settings.onChange) { 215 tags_callbacks[id] = new Array(); 216 tags_callbacks[id]['onAddTag'] = settings.onAddTag; 217 tags_callbacks[id]['onRemoveTag'] = settings.onRemoveTag; 218 tags_callbacks[id]['onChange'] = settings.onChange; 219 } 220 221 var containerClass = $('#'+id).attr('class').replace('tagsinput', ''); 222 var markup = '<div id="'+id+'_tagsinput" class="tagsinput '+containerClass+'"><div class="tagsinput-add-container" id="'+id+'_addTag"><div class="tagsinput-add"></div>'; 223 224 if (settings.interactive) { 225 markup = markup + '<input id="'+id+'_tag" value="" data-default="'+settings.defaultText+'" />'; 226 } 227 228 markup = markup + '</div></div>'; 229 230 $(markup).insertAfter(this); 231 232 $(data.holder).css('width',settings.width); 233 $(data.holder).css('min-height',settings.height); 234 $(data.holder).css('height','100%'); 235 236 if ($(data.real_input).val()!='') { 237 $.fn.tagsInput.importTags($(data.real_input),$(data.real_input).val()); 238 } 239 if (settings.interactive) { 240 $(data.fake_input).val($(data.fake_input).attr('data-default')); 241 $(data.fake_input).css('color',settings.placeholderColor); 242 $(data.fake_input).resetAutosize(settings); 243 244 $(data.holder).bind('click',data,function(event) { 245 $(event.data.fake_input).focus(); 246 }); 247 248 $(data.fake_input).bind('focus',data,function(event) { 249 if ($(event.data.fake_input).val()==$(event.data.fake_input).attr('data-default')) { 250 $(event.data.fake_input).val(''); 251 } 252 $(event.data.fake_input).css('color','#000000'); 253 }); 254 255 if (settings.autocomplete_url != undefined) { 256 autocomplete_options = {source: settings.autocomplete_url}; 257 for (attrname in settings.autocomplete) { 258 autocomplete_options[attrname] = settings.autocomplete[attrname]; 259 } 260 261 if (jQuery.Autocompleter !== undefined) { 262 $(data.fake_input).autocomplete(settings.autocomplete_url, settings.autocomplete); 263 $(data.fake_input).bind('result',data,function(event,data,formatted) { 264 if (data) { 265 $('#'+id).addTag(data[0] + "",{focus:true,unique:(settings.unique)}); 266 } 267 }); 268 } else if (jQuery.ui.autocomplete !== undefined) { 269 $(data.fake_input).autocomplete(autocomplete_options); 270 $(data.fake_input).bind('autocompleteselect',data,function(event,ui) { 271 $(event.data.real_input).addTag(ui.item.value,{focus:true,unique:(settings.unique)}); 272 return false;
273 }); 274 } 275 276 277 } else { 278 // if a user tabs out of the field, create a new tag 279 // this is only available if autocomplete is not used. 280 $(data.fake_input).bind('blur',data,function(event) { 281 var d = $(this).attr('data-default'); 282 if ($(event.data.fake_input).val()!='' && $(event.data.fake_input).val()!=d) { 283 if( (event.data.minChars <= $(event.data.fake_input).val().length) && (!event.data.maxChars || (event.data.maxChars >= $(event.data.fake_input).val().length)) ) 284 $(event.data.real_input).addTag($(event.data.fake_input).val(),{focus:true,unique:(settings.unique)}); 285 } else { 286 $(event.data.fake_input).val($(event.data.fake_input).attr('data-default')); 287 $(event.data.fake_input).css('color',settings.placeholderColor); 288 } 289 return false; 290 }); 291 292 } 293 // if user types a comma, create a new tag 294 $(data.fake_input).bind('keypress',data,function(event) { 295 if (event.which==event.data.delimiter.charCodeAt(0) || event.which==13 ) { 296 event.preventDefault(); 297 if( (event.data.minChars <= $(event.data.fake_input).val().length) && (!event.data.maxChars || (event.data.maxChars >= $(event.data.fake_input).val().length)) ) 298 $(event.data.real_input).addTag($(event.data.fake_input).val(),{focus:true,unique:(settings.unique)}); 299 $(event.data.fake_input).resetAutosize(settings); 300 return false; 301 } else if (event.data.autosize) { 302 $(event.data.fake_input).doAutosize(settings); 303 304 } 305 }); 306 //Delete last tag on backspace 307 data.removeWithBackspace && $(data.fake_input).bind('keydown', function(event) 308 { 309 if(event.keyCode == 8 && $(this).val() == '') 310 { 311 event.preventDefault(); 312 var last_tag = $(this).closest('.tagsinput').find('.tag:last').text(); 313 var id = $(this).attr('id').replace(/_tag$/, ''); 314 last_tag = last_tag.replace(/[\s\u00a0]+x$/, ''); 315 $('#' + id).removeTag(escape(last_tag)); 316 $(this).trigger('focus'); 317 } 318 }); 319 $(data.fake_input).blur(); 320 321 //Removes the not_valid class when user changes the value of the fake input 322 if(data.unique) { 323 $(data.fake_input).keydown(function(event){ 324 if(event.keyCode == 8 || String.fromCharCode(event.which).match(/\w+|[áéÃóúÃÃÃÃÃñÃ,/]+/)) { 325 $(this).removeClass('not_valid'); 326 } 327 }); 328 } 329 } // if settings.interactive 330 }); 331 332 return this; 333 334 }; 335 336 $.fn.tagsInput.updateTagsField = function(obj,tagslist) { 337 var id = $(obj).attr('id'); 338 $(obj).val(tagslist.join(delimiter[id])); 339 }; 340 341 $.fn.tagsInput.importTags = function(obj,val) { 342 $(obj).val(''); 343 var id = $(obj).attr('id'); 344 var tags = val.split(delimiter[id]); 345 for (i=0; i<tags.length; i++) { 346 $(obj).addTag(tags[i],{focus:false,callback:false}); 347 } 348 if(tags_callbacks[id] && tags_callbacks[id]['onChange']) 349 { 350 var f = tags_callbacks[id]['onChange']; 351 f.call(obj, obj, tags[i]); 352 } 353 }; 354 355})(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.