File indexing completed on 2024-05-19 06:00:29
0001 /* 0002 0003 jQuery Tags Input Plugin 1.3.3 0004 0005 Copyright (c) 2011 XOXCO, Inc 0006 0007 Documentation for this plugin lives here: 0008 http://xoxco.com/clickable/jquery-tags-input 0009 0010 Licensed under the MIT license: 0011 http://www.opensource.org/licenses/mit-license.php 0012 0013 ben@xoxco.com 0014 0015 */ 0016 0017 (function($) { 0018 0019 var delimiter = new Array(); 0020 var tags_callbacks = new Array(); 0021 $.fn.doAutosize = function(o){ 0022 var minWidth = $(this).data('minwidth'), 0023 maxWidth = $(this).data('maxwidth'), 0024 val = '', 0025 input = $(this), 0026 testSubject = $('#'+$(this).data('tester_id')); 0027 0028 if (val === (val = input.val())) {return;} 0029 0030 // Enter new content into testSubject 0031 var escaped = val.replace(/&/g, '&').replace(/\s/g,' ').replace(/</g, '<').replace(/>/g, '>'); 0032 testSubject.html(escaped); 0033 // Calculate new width + whether to change 0034 var testerWidth = testSubject.width(), 0035 newWidth = (testerWidth + o.comfortZone) >= minWidth ? testerWidth + o.comfortZone : minWidth, 0036 currentWidth = input.width(), 0037 isValidWidthChange = (newWidth < currentWidth && newWidth >= minWidth) 0038 || (newWidth > minWidth && newWidth < maxWidth); 0039 0040 // Animate width 0041 if (isValidWidthChange) { 0042 input.width(newWidth); 0043 } 0044 0045 0046 }; 0047 $.fn.resetAutosize = function(options){ 0048 // alert(JSON.stringify(options)); 0049 var minWidth = $(this).data('minwidth') || options.minInputWidth || $(this).width(), 0050 maxWidth = $(this).data('maxwidth') || options.maxInputWidth || ($(this).closest('.tagsinput').width() - options.inputPadding), 0051 val = '', 0052 input = $(this), 0053 testSubject = $('<tester/>').css({ 0054 position: 'absolute', 0055 top: -9999, 0056 left: -9999, 0057 width: 'auto', 0058 fontSize: input.css('fontSize'), 0059 fontFamily: input.css('fontFamily'), 0060 fontWeight: input.css('fontWeight'), 0061 letterSpacing: input.css('letterSpacing'), 0062 whiteSpace: 'nowrap' 0063 }), 0064 testerId = $(this).attr('id')+'_autosize_tester'; 0065 if(! $('#'+testerId).length > 0){ 0066 testSubject.attr('id', testerId); 0067 testSubject.appendTo('body'); 0068 } 0069 0070 input.data('minwidth', minWidth); 0071 input.data('maxwidth', maxWidth); 0072 input.data('tester_id', testerId); 0073 input.css('width', minWidth); 0074 }; 0075 0076 $.fn.addTag = function(value,options) { 0077 options = jQuery.extend({focus:false,callback:true},options); 0078 this.each(function() { 0079 var id = $(this).attr('id'); 0080 0081 var tagslist = $(this).val().split(delimiter[id]); 0082 if (tagslist[0] == '') { 0083 tagslist = new Array(); 0084 } 0085 0086 value = jQuery.trim(value); 0087 0088 if (options.unique) { 0089 var skipTag = $(this).tagExist(value); 0090 if(skipTag == true) { 0091 //Marks fake input as not_valid to let styling it 0092 $('#'+id+'_tag').addClass('not_valid'); 0093 } 0094 } else { 0095 var skipTag = false; 0096 } 0097 0098 if (value !='' && skipTag != true) { 0099 $('<span>').addClass('tag').append( 0100 $('<span>').text(value).append(' '), 0101 $('<a class="tagsinput-remove-link">', { 0102 href : '#', 0103 title : 'Remove tag', 0104 text : '' 0105 }).click(function () { 0106 return $('#' + id).removeTag(escape(value)); 0107 }) 0108 ).insertBefore('#' + id + '_addTag'); 0109 0110 tagslist.push(value); 0111 0112 $('#'+id+'_tag').val(''); 0113 if (options.focus) { 0114 $('#'+id+'_tag').focus(); 0115 } else { 0116 $('#'+id+'_tag').blur(); 0117 } 0118 0119 $.fn.tagsInput.updateTagsField(this,tagslist); 0120 0121 if (options.callback && tags_callbacks[id] && tags_callbacks[id]['onAddTag']) { 0122 var f = tags_callbacks[id]['onAddTag']; 0123 f.call(this, value); 0124 } 0125 if(tags_callbacks[id] && tags_callbacks[id]['onChange']) 0126 { 0127 var i = tagslist.length; 0128 var f = tags_callbacks[id]['onChange']; 0129 f.call(this, $(this), tagslist[i-1]); 0130 } 0131 } 0132 0133 }); 0134 0135 return false; 0136 }; 0137 0138 $.fn.removeTag = function(value) { 0139 value = unescape(value); 0140 this.each(function() { 0141 var id = $(this).attr('id'); 0142 0143 var old = $(this).val().split(delimiter[id]); 0144 0145 $('#'+id+'_tagsinput .tag').remove(); 0146 str = ''; 0147 for (i=0; i< old.length; i++) { 0148 if (old[i]!=value) { 0149 str = str + delimiter[id] +old[i]; 0150 } 0151 } 0152 0153 $.fn.tagsInput.importTags(this,str); 0154 0155 if (tags_callbacks[id] && tags_callbacks[id]['onRemoveTag']) { 0156 var f = tags_callbacks[id]['onRemoveTag']; 0157 f.call(this, value); 0158 } 0159 }); 0160 0161 return false; 0162 }; 0163 0164 $.fn.tagExist = function(val) { 0165 var id = $(this).attr('id'); 0166 var tagslist = $(this).val().split(delimiter[id]); 0167 return (jQuery.inArray(val, tagslist) >= 0); //true when tag exists, false when not 0168 }; 0169 0170 // clear all existing tags and import new ones from a string 0171 $.fn.importTags = function(str) { 0172 id = $(this).attr('id'); 0173 $('#'+id+'_tagsinput .tag').remove(); 0174 $.fn.tagsInput.importTags(this,str); 0175 } 0176 0177 $.fn.tagsInput = function(options) { 0178 var settings = jQuery.extend({ 0179 interactive:true, 0180 defaultText:'', 0181 minChars:0, 0182 width:'', 0183 height:'', 0184 autocomplete: {selectFirst: false }, 0185 'hide':true, 0186 'delimiter':',', 0187 'unique':true, 0188 removeWithBackspace:true, 0189 placeholderColor:'#666666', 0190 autosize: true, 0191 comfortZone: 20, 0192 inputPadding: 6*2 0193 },options); 0194 0195 this.each(function() { 0196 if (settings.hide) { 0197 $(this).hide(); 0198 } 0199 var id = $(this).attr('id'); 0200 if (!id || delimiter[$(this).attr('id')]) { 0201 id = $(this).attr('id', 'tags' + new Date().getTime()).attr('id'); 0202 } 0203 0204 var data = jQuery.extend({ 0205 pid:id, 0206 real_input: '#'+id, 0207 holder: '#'+id+'_tagsinput', 0208 input_wrapper: '#'+id+'_addTag', 0209 fake_input: '#'+id+'_tag' 0210 },settings); 0211 0212 delimiter[id] = data.delimiter; 0213 0214 if (settings.onAddTag || settings.onRemoveTag || settings.onChange) { 0215 tags_callbacks[id] = new Array(); 0216 tags_callbacks[id]['onAddTag'] = settings.onAddTag; 0217 tags_callbacks[id]['onRemoveTag'] = settings.onRemoveTag; 0218 tags_callbacks[id]['onChange'] = settings.onChange; 0219 } 0220 0221 var containerClass = $('#'+id).attr('class').replace('tagsinput', ''); 0222 var markup = '<div id="'+id+'_tagsinput" class="tagsinput '+containerClass+'"><div class="tagsinput-add-container" id="'+id+'_addTag"><div class="tagsinput-add"></div>'; 0223 0224 if (settings.interactive) { 0225 markup = markup + '<input id="'+id+'_tag" value="" data-default="'+settings.defaultText+'" />'; 0226 } 0227 0228 markup = markup + '</div></div>'; 0229 0230 $(markup).insertAfter(this); 0231 0232 $(data.holder).css('width',settings.width); 0233 $(data.holder).css('min-height',settings.height); 0234 $(data.holder).css('height','100%'); 0235 0236 if ($(data.real_input).val()!='') { 0237 $.fn.tagsInput.importTags($(data.real_input),$(data.real_input).val()); 0238 } 0239 if (settings.interactive) { 0240 $(data.fake_input).val($(data.fake_input).attr('data-default')); 0241 $(data.fake_input).css('color',settings.placeholderColor); 0242 $(data.fake_input).resetAutosize(settings); 0243 0244 $(data.holder).bind('click',data,function(event) { 0245 $(event.data.fake_input).focus(); 0246 }); 0247 0248 $(data.fake_input).bind('focus',data,function(event) { 0249 if ($(event.data.fake_input).val()==$(event.data.fake_input).attr('data-default')) { 0250 $(event.data.fake_input).val(''); 0251 } 0252 $(event.data.fake_input).css('color','#000000'); 0253 }); 0254 0255 if (settings.autocomplete_url != undefined) { 0256 autocomplete_options = {source: settings.autocomplete_url}; 0257 for (attrname in settings.autocomplete) { 0258 autocomplete_options[attrname] = settings.autocomplete[attrname]; 0259 } 0260 0261 if (jQuery.Autocompleter !== undefined) { 0262 $(data.fake_input).autocomplete(settings.autocomplete_url, settings.autocomplete); 0263 $(data.fake_input).bind('result',data,function(event,data,formatted) { 0264 if (data) { 0265 $('#'+id).addTag(data[0] + "",{focus:true,unique:(settings.unique)}); 0266 } 0267 }); 0268 } else if (jQuery.ui.autocomplete !== undefined) { 0269 $(data.fake_input).autocomplete(autocomplete_options); 0270 $(data.fake_input).bind('autocompleteselect',data,function(event,ui) { 0271 $(event.data.real_input).addTag(ui.item.value,{focus:true,unique:(settings.unique)}); 0272 return false; 0273 }); 0274 } 0275 0276 0277 } else { 0278 // if a user tabs out of the field, create a new tag 0279 // this is only available if autocomplete is not used. 0280 $(data.fake_input).bind('blur',data,function(event) { 0281 var d = $(this).attr('data-default'); 0282 if ($(event.data.fake_input).val()!='' && $(event.data.fake_input).val()!=d) { 0283 if( (event.data.minChars <= $(event.data.fake_input).val().length) && (!event.data.maxChars || (event.data.maxChars >= $(event.data.fake_input).val().length)) ) 0284 $(event.data.real_input).addTag($(event.data.fake_input).val(),{focus:true,unique:(settings.unique)}); 0285 } else { 0286 $(event.data.fake_input).val($(event.data.fake_input).attr('data-default')); 0287 $(event.data.fake_input).css('color',settings.placeholderColor); 0288 } 0289 return false; 0290 }); 0291 0292 } 0293 // if user types a comma, create a new tag 0294 $(data.fake_input).bind('keypress',data,function(event) { 0295 if (event.which==event.data.delimiter.charCodeAt(0) || event.which==13 ) { 0296 event.preventDefault(); 0297 if( (event.data.minChars <= $(event.data.fake_input).val().length) && (!event.data.maxChars || (event.data.maxChars >= $(event.data.fake_input).val().length)) ) 0298 $(event.data.real_input).addTag($(event.data.fake_input).val(),{focus:true,unique:(settings.unique)}); 0299 $(event.data.fake_input).resetAutosize(settings); 0300 return false; 0301 } else if (event.data.autosize) { 0302 $(event.data.fake_input).doAutosize(settings); 0303 0304 } 0305 }); 0306 //Delete last tag on backspace 0307 data.removeWithBackspace && $(data.fake_input).bind('keydown', function(event) 0308 { 0309 if(event.keyCode == 8 && $(this).val() == '') 0310 { 0311 event.preventDefault(); 0312 var last_tag = $(this).closest('.tagsinput').find('.tag:last').text(); 0313 var id = $(this).attr('id').replace(/_tag$/, ''); 0314 last_tag = last_tag.replace(/[\s\u00a0]+x$/, ''); 0315 $('#' + id).removeTag(escape(last_tag)); 0316 $(this).trigger('focus'); 0317 } 0318 }); 0319 $(data.fake_input).blur(); 0320 0321 //Removes the not_valid class when user changes the value of the fake input 0322 if(data.unique) { 0323 $(data.fake_input).keydown(function(event){ 0324 if(event.keyCode == 8 || String.fromCharCode(event.which).match(/\w+|[áéíóúÁÉÍÓÚñÑ,/]+/)) { 0325 $(this).removeClass('not_valid'); 0326 } 0327 }); 0328 } 0329 } // if settings.interactive 0330 }); 0331 0332 return this; 0333 0334 }; 0335 0336 $.fn.tagsInput.updateTagsField = function(obj,tagslist) { 0337 var id = $(obj).attr('id'); 0338 $(obj).val(tagslist.join(delimiter[id])); 0339 }; 0340 0341 $.fn.tagsInput.importTags = function(obj,val) { 0342 $(obj).val(''); 0343 var id = $(obj).attr('id'); 0344 var tags = val.split(delimiter[id]); 0345 for (i=0; i<tags.length; i++) { 0346 $(obj).addTag(tags[i],{focus:false,callback:false}); 0347 } 0348 if(tags_callbacks[id] && tags_callbacks[id]['onChange']) 0349 { 0350 var f = tags_callbacks[id]['onChange']; 0351 f.call(obj, obj, tags[i]); 0352 } 0353 }; 0354 0355 })(jQuery);