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