www.pudn.com > ProjectSend_feeywt.rar > TextboxList.js, change:2012-03-02,size:13825b


/* 
Script: TextboxList.js 
	Displays a textbox as a combination of boxes an inputs (eg: facebook tokenizer) 
 
	Authors: 
		Guillermo Rauch 
		 
	Note: 
		TextboxList is not priceless for commercial use. See <http://devthought.com/projects/jquery/textboxlist/>.  
		Purchase to remove this message. 
*/ 
 
(function($){ 
	 
$.TextboxList = function(element, _options){ 
	 
	var original, container, list, current, focused = false, index = [], blurtimer, events = {}; 
	var options = $.extend(true, { 
    prefix: 'textboxlist', 
    max: null, 
		unique: false, 
		uniqueInsensitive: true, 
    endEditableBit: true, 
		startEditableBit: true, 
		hideEditableBits: true, 
    inBetweenEditableBits: true, 
		keys: {previous: 37, next: 39}, 
		bitsOptions: {editable: {}, box: {}}, 
    plugins: {}, 
		// tip: you can change encode/decode with JSON.stringify and JSON.parse 
		encode: function(o){  
			return $.grep($.map(o, function(v){		 
				v = (chk(v[0]) ? v[0] : v[1]); 
				return chk(v) ? v.toString().replace(/,/, '') : null; 
			}), function(o){ return o != undefined; }).join(',');  
		}, 
		decode: function(o){ return o.split(','); } 
  }, _options); 
	 
	element = $(element); 
	 
	var self = this; 
	var init = function(){		 
		original = element.css('display', 'none').attr('autocomplete', 'off').focus(focusLast); 
		container = $('<div class="'+options.prefix+'" />') 
			.insertAfter(element) 
			.click(function(e){  
				if ((e.target == list.get(0) || e.target == container.get(0)) && (!focused || (current && current.toElement().get(0) != list.find(':last-child').get(0)))) focusLast(); 			 
			});			 
		list = $('<ul class="'+ options.prefix +'-bits" />').appendTo(container); 
		for (var name in options.plugins) enablePlugin(name, options.plugins[name]);		 
		afterInit(); 
	}; 
	 
	var enablePlugin = function(name, options){ 
		self.plugins[name] = new $.TextboxList[camelCase(capitalize(name))](self, options); 
	}; 
	 
	var afterInit = function(){ 
		if (options.endEditableBit) create('editable', null, {tabIndex: original.tabIndex}).inject(list); 
		addEvent('bitAdd', update, true); 
		addEvent('bitRemove', update, true); 
		$(document).click(function(e){ 
			if (!focused) return; 
			if (e.target.className.indexOf(options.prefix) != -1){				 
				if (e.target == $(container).get(0)) return;				 
				var parent = $(e.target).parents('div.' + options.prefix); 
				if (parent.get(0) == container.get(0)) return; 
			} 
			blur(); 
		}).keydown(function(ev){ 
			if (!focused || !current) return; 
			var caret = current.is('editable') ? current.getCaret() : null; 
			var value = current.getValue()[1]; 
			var special = !!$.map(['shift', 'alt', 'meta', 'ctrl'], function(e){ return ev[e]; }).length; 
			var custom = special || (current.is('editable') && current.isSelected()); 
			var evStop = function(){ ev.stopPropagation(); ev.preventDefault(); }; 
			switch (ev.which){ 
				case 8: 
					if (current.is('box')){  
						evStop(); 
						return current.remove();  
					} 
				case options.keys.previous: 
					if (current.is('box') || ((caret == 0 || !value.length) && !custom)){ 
						evStop(); 
						focusRelative('prev'); 
					} 
					break; 
				case 46: 
					if (current.is('box')){  
						evStop(); 
						return current.remove();  
					} 
				case options.keys.next:  
					if (current.is('box') || (caret == value.length && !custom)){ 
						evStop(); 
						focusRelative('next'); 
					} 
			} 
		}); 
		setValues(options.decode(original.val())); 
	}; 
	 
	var create = function(klass, value, opt){ 
		if (klass == 'box'){ 
			if (chk(options.max) && list.children('.' + options.prefix + '-bit-box').length + 1 > options.max) return false; 
			if (options.unique && $.inArray(uniqueValue(value), index) != -1) return false;		 
		}		 
		return new $.TextboxListBit(klass, value, self, $.extend(true, options.bitsOptions[klass], opt)); 
	}; 
	 
	var uniqueValue = function(value){ 
		return chk(value[0]) ? value[0] : (options.uniqueInsensitive ? value[1].toLowerCase() : value[1]); 
	} 
	 
	var add = function(plain, id, html, afterEl){ 
		var b = create('box', [id, plain, html]); 
		if (b){ 
			if (!afterEl || !afterEl.length) afterEl = list.find('.' + options.prefix + '-bit-box').filter(':last'); 
			b.inject(afterEl.length ? afterEl : list, afterEl.length ? 'after' : 'top'); 
		}  
		return self; 
	}; 
	 
	var focusRelative = function(dir, to){ 
		var el = getBit(to && $(to).length ? to : current).toElement(); 
		var b = getBit(el[dir]()); 
		if (b) b.focus(); 
		return self; 
	}; 
	 
	var focusLast = function(){ 
		var lastElement = list.children().filter(':last'); 
		if (lastElement) getBit(lastElement).focus(); 
		return self; 
	}; 
	 
	var blur = function(){	 
		if (! focused) return self; 
		if (current) current.blur(); 
		focused = false; 
		return fireEvent('blur'); 
	}; 
	 
	var getBit = function(obj){				 
		return (obj.type && (obj.type == 'editable' || obj.type == 'box')) ? obj : $(obj).data('textboxlist:bit'); 
	}; 
	 
	var getValues = function(){ 
		var values = []; 
		list.children().each(function(){ 
			var bit = getBit(this); 
			if (!bit.is('editable')) values.push(bit.getValue()); 
		}); 
		return values; 
	}; 
	 
	var setValues = function(values){ 
		if (!values) return; 
		$.each(values, function(i, v){ 
			if (v) add.apply(self, $.isArray(v) ? [v[1], v[0], v[2]] : [v]); 
		});		 
	}; 
	 
	var update = function(){ 
		original.val(options.encode(getValues())); 
	}; 
	 
	var addEvent = function(type, fn){ 
		if (events[type] == undefined) events[type] = []; 
		var exists = false; 
		$.each(events[type], function(f){ 
			if (f === fn){ 
				exists = true; 
				return; 
			}; 
		}); 
		if (!exists) events[type].push(fn); 
		return self; 
	}; 
	 
	var fireEvent = function(type, args, delay){ 
		if (!events || !events[type]) return self; 
		$.each(events[type], function(i, fn){		 
			(function(){ 
				args = (args != undefined) ? splat(args) : Array.prototype.slice.call(arguments); 
				var returns = function(){ 
					return fn.apply(self || null, args); 
				}; 
				if (delay) return setTimeout(returns, delay); 
				return returns(); 
			})(); 
		}); 
		return self; 
	}; 
	 
	var removeEvent = function(type, fn){ 
		if (events[type]){ 
			for (var i = events[type].length; i--; i){ 
				if (events[type][i] === fn) events[type].splice(i, 1); 
			} 
		}  
		return self; 
	}; 
	 
	var isDuplicate = function(v){ 
		return $.inArray(uniqueValue(v), index); 
	}; 
	 
	this.onFocus = function(bit){ 
		if (current) current.blur(); 
		clearTimeout(blurtimer); 
		current = bit; 
		container.addClass(options.prefix + '-focus');		 
		if (!focused){ 
			focused = true; 
			fireEvent('focus', bit); 
		} 
	}; 
	 
	this.onAdd = function(bit){ 
		if (options.unique && bit.is('box')) index.push(uniqueValue(bit.getValue())); 
		if (bit.is('box')){ 
			var prior = getBit(bit.toElement().prev()); 
			if ((prior && prior.is('box') && options.inBetweenEditableBits) || (!prior && options.startEditableBit)){				 
				var priorEl = prior && prior.toElement().length ? prior.toElement() : false; 
				var b = create('editable').inject(priorEl || list, priorEl ? 'after' : 'top'); 
				if (options.hideEditableBits) b.hide(); 
			} 
		} 
	}; 
	 
	this.onRemove = function(bit){ 
		if (!focused) return; 
		if (options.unique && bit.is('box')){ 
			var i = isDuplicate(bit.getValue()); 
			if (i != -1) index = index.splice(i + 1, 1); 
		}  
		var prior = getBit(bit.toElement().prev()); 
		if (prior && prior.is('editable')) prior.remove(); 
		focusRelative('next', bit); 
	}; 
	 
	this.onBlur = function(bit, all){ 
		current = null; 
		container.removeClass(options.prefix + '-focus');		 
		blurtimer = setTimeout(blur, all ? 0 : 200); 
	}; 
	 
	this.setOptions = function(opt){ 
		options = $.extend(true, options, opt); 
	}; 
	 
	this.getOptions = function(){ 
		return options; 
	}; 
	 
	this.getContainer = function(){ 
		return container; 
	}; 
	 
	this.isDuplicate = isDuplicate; 
	this.addEvent = addEvent; 
	this.removeEvent = removeEvent; 
	this.fireEvent = fireEvent; 
	this.create = create; 
	this.add = add; 
	this.getValues = getValues; 
	this.plugins = []; 
	init(); 
 
}; 
 
$.TextboxListBit = function(type, value, textboxlist, _options){ 
	 
	var element, bit, prefix, typeprefix, close, hidden, focused = false, name = capitalize(type);  
	var options = $.extend(true, type == 'box' ? { 
		deleteButton: true 
  } : { 
		tabIndex: null, 
		growing: true, 
		growingOptions: {}, 
		stopEnter: true, 
		addOnBlur: false, 
		addKeys: [13] 
	}, _options); 
	 
	this.type = type; 
	this.value = value; 
	 
	var self = this; 
	var init = function(){ 
		prefix = textboxlist.getOptions().prefix + '-bit'; 
		typeprefix = prefix + '-' + type; 
		bit = $('<li />').addClass(prefix).addClass(typeprefix) 
			.data('textboxlist:bit', self) 
			.hover(function(){  
				bit.addClass(prefix + '-hover').addClass(typeprefix + '-hover');  
			}, function(){ 
				bit.removeClass(prefix + '-hover').removeClass(typeprefix + '-hover');  
			}); 
		if (type == 'box'){ 
			bit.html(chk(self.value[2]) ? self.value[2] : self.value[1]).click(focus); 
			if (options.deleteButton){ 
				bit.addClass(typeprefix + '-deletable'); 
				close = $('<a href="#" class="'+ typeprefix +'-deletebutton" />').click(remove).appendTo(bit); 
			} 
			bit.children().click(function(e){ e.stopPropagation(); e.preventDefault(); }); 
		} else { 
			element = $('<input type="text" class="'+ typeprefix +'-input" autocomplete="off" />').val(self.value ? self.value[1] : '').appendTo(bit); 
			if (chk(options.tabIndex)) element.tabIndex = options.tabIndex; 
			if (options.growing) new $.GrowingInput(element, options.growingOptions);		 
			element.focus(function(){ focus(true); }).blur(function(){ 
				blur(true); 
				if (options.addOnBlur) toBox();  
			});				 
			if (options.addKeys || options.stopEnter){ 
				element.keydown(function(ev){ 
					if (!focused) return; 
					var evStop = function(){ ev.stopPropagation(); ev.preventDefault(); }; 
					if (options.stopEnter && ev.which === 13) evStop(); 
					if ($.inArray(ev.which, splat(options.addKeys)) != -1){ 
						evStop(); 
						toBox(); 
					} 
				}); 
			} 
		} 
	}; 
	 
	var inject = function(el, where){ 
		switch(where || 'bottom'){ 
			case 'top': bit.prependTo(el); break; 
			case 'bottom': bit.appendTo(el); break; 
			case 'before': bit.insertBefore(el); break;			 
			case 'after': bit.insertAfter(el); break;						 
		} 
		textboxlist.onAdd(self);	 
		return fireBitEvent('add'); 
	}; 
	 
	var focus = function(noReal){ 
		if (focused) return self; 
		show(); 
		focused = true; 
		textboxlist.onFocus(self); 
		bit.addClass(prefix + '-focus').addClass(prefix + '-' + type + '-focus'); 
		fireBitEvent('focus');		 
		if (type == 'editable' && !noReal) element.focus(); 
		return self; 
	}; 
	 
	var blur = function(noReal){ 
		if (!focused) return self; 
		focused = false; 
		textboxlist.onBlur(self); 
		bit.removeClass(prefix + '-focus').removeClass(prefix + '-' + type + '-focus'); 
		fireBitEvent('blur'); 
		if (type == 'editable'){ 
			if (!noReal) element.blur(); 
			if (hidden && !element.val().length) hide(); 
		} 
		return self; 
	}; 
	 
	var remove = function(){ 
		blur();		 
		textboxlist.onRemove(self); 
		bit.remove(); 
		return fireBitEvent('remove'); 
	}; 
	 
	var show = function(){ 
		bit.css('display', 'block'); 
		return self; 
	}; 
	 
	var hide = function(){ 
		bit.css('display', 'none');		 
		hidden = true; 
		return self; 
	}; 
	 
	var fireBitEvent = function(type){ 
		type = capitalize(type); 
		textboxlist.fireEvent('bit' + type, self).fireEvent('bit' + name + type, self); 
		return self; 
	}; 
	 
  this.is = function(t){ 
    return type == t; 
  }; 
 
	this.setValue = function(v){ 
		if (type == 'editable'){ 
			element.val(chk(v[0]) ? v[0] : v[1]); 
			if (options.growing) element.data('growing').resize(); 
		} else value = v; 
		return self; 
	}; 
 
 	this.getValue = function(){ 
		return type == 'editable' ? [null, element.val(), null] : value; 
	}; 
	 
	if (type == 'editable'){ 
		this.getCaret = function(){ 
 			var el = element.get(0); 
			if (el.createTextRange){ 
		    var r = document.selection.createRange().duplicate();		 
		  	r.moveEnd('character', el.value.length); 
		  	if (r.text === '') return el.value.length; 
		  	return el.value.lastIndexOf(r.text); 
		  } else return el.selectionStart; 
		}; 
 
		this.getCaretEnd = function(){ 
 			var el = element.get(0);			 
			if (el.createTextRange){ 
				var r = document.selection.createRange().duplicate(); 
				r.moveStart('character', -el.value.length); 
				return r.text.length; 
			} else return el.selectionEnd; 
		}; 
		 
		this.isSelected = function(){ 
			return focused && (self.getCaret() !== self.getCaretEnd()); 
		}; 
		 
		var toBox = function(){ 
			var value = self.getValue();				 
			var b = textboxlist.create('box', value); 
			if (b){ 
				b.inject(bit, 'before'); 
				self.setValue([null, '', null]); 
				return b; 
			} 
			return null; 
		}; 
		 
		this.toBox = toBox; 
	} 
	 
	this.toElement = function(){ 
		return bit; 
	}; 
	 
	this.focus = focus; 
	this.blur = blur; 
	this.remove = remove; 
	this.inject = inject; 
	this.show = show; 
	this.hide = hide; 
	this.fireBitEvent = fireBitEvent; 
	init(); 
}; 
 
var chk = function(v){ return !!(v || v === 0); }; 
var splat = function(a){ return $.isArray(a) ? a : [a]; }; 
var camelCase = function(str){ return str.replace(/-\D/g, function(match){ return match.charAt(1).toUpperCase(); }); }; 
var capitalize = function(str){ return str.replace(/\b[a-z]/g, function(A){ return A.toUpperCase(); }); }; 
 
$.fn.extend({ 
	 
	textboxlist: function(options){ 
		return this.each(function(){ 
			new $.TextboxList(this, options); 
		}); 
	} 
	 
}); 
 
})(jQuery);