﻿/*
 * Copyright (c) 2009 Fullhouse
 * Author: James Newell
 * Date Created: 08/05/09
 * Version: 1.0
 *
 * Restricts character input on textboxes and textareas to values
 * based on a given character pattern that includes single characters,
 * exclusions, and ranges.
 *
 * Pattern Syntax:
 *
 * Usage: jQuery('input[type=text]').restrict("A-Z");           // uppercase alpha
 * Usage: jQuery('input[type=text]').restrict("A-Za-z0-9");     // alpha-numeric
 * Usage: jQuery('input[type=text]').restrict("0-9A-F");        // hexidecimal
 * Usage: jQuery('input[type=text]').restrict("0-9A-F\\^");     // hexidecimal plus ^ character (must be escaped with \\)
 * Usage: jQuery('input[type=text]').restrict("0-9A-F\\\\");    // hexidecimal plus \ character (must be escaped with \\\\)
 * Usage: jQuery('input[type=text]').restrict("A-Z^OIS);        // uppercase alpha excluding O, I, and S
 * Usage: jQuery('input[type=text]').restrict("^01OISlois);     // all characters excluding 0, 1, O, I, S, l, o, i, and s
 *
 * Preset Syntax:
 *
 * Usage: jQuery('input[type=text]').restrict("alpha");         // equivalent to "A-Za-z"
 * Usage: jQuery('input[type=text]').restrict("numeric");       // equivalent to "0-9"
 * Usage: jQuery('input[type=text]').restrict("alphanumeric");  // equivalent to "A-Za-z0-9"
 * 
 * Available Presets: alpha, alphaupper, alphalower, alphanumeric, numeric, 
 *      numericinteger, numericfloat, integer, float, percentage, currency, email
 *
 * Available Settings:
 *	    - allowControlKeys (boolean, default = true): 
 *          Allows all basic control keys for interaction.
 *	    - allowSpaces (boolean, default = true): 
 *          Allows spaces in input. If false spaces can only be entered if the space character is present in the characters pattern.
 *	    - tooltip (string, default = null): 
 *          Sets the title attribute for the element to the given string to inform the user about any input restrictions.
 */

/// <reference path="jquery-1.2.6-vsdoc.js"/>
(function($){$.fn.restrict=function(characters,settings){var includes;var excludes;var presets={alpha:"A-Za-z",alphalower:"a-z",alphaupper:"A-Z",alphanumeric:"A-Za-z0-9",numeric:"0-9",numericinteger:"0-9",numericfloat:"0-9.",integer:"0-9",float:"0-9.",percentage:"0-9.%",currency:"0-9.$,",email:"A-Za-z0-9.@!#$%&'*+-/=?\\^_`{|}~"};settings=$.extend({allowControlKeys:true,allowSpaces:true,tooltip:null},settings);return this.each(function(){$(this).bind("keypress",function(e){return allowInputCharacter(this,e);}).bind("paste",function(){var me=this;});if(settings.tooltip){$(this).attr("title",settings.tooltip);}
initialize(characters);});function allowInputCharacter(element,e){var i;var allowed=false;var code=getKeyCodeForEvent(e);if(isControlKey(code)){return settings.allowControlKeys;}
if(isSpaceKey(code)){return settings.allowSpaces;}
for(i=0;i<includes.length;i++){allowed=allowed||includes[i].test(code);if(allowed){break;}}
for(i=0;i<excludes.length;i++){allowed=allowed&&!excludes[i].test(code);if(!allowed){break;}}
return allowed;};function getKeyCodeForEvent(e){var keyCode=-1;if(window.event){keyCode=window.event.keyCode;}else if(e.which&&e.which!=0){keyCode=e.which;}else{if(e.charCode==0){keyCode=e.keyCode;}else{keyCode=e.charCode;}}
return keyCode;};function getKeyCharForEvent(e){return String.fromCharCode(getKeyCodeForEvent(e));};function isControlKey(keyCode){return(keyCode>0&&keyCode<=13)||keyCode==16;};function isSpaceKey(keyCode){return keyCode==32;};function initialize(pattern){if(!pattern||pattern.length==0){return;}
pattern=presets[pattern.toLowerCase()]||pattern;var c,i,t;var chars=[];var negate=false;includes=[];excludes=[];i=0;while(i<pattern.length){c=pattern.charAt(i);t=null;switch(c){case"-":var s="A";if(chars.length>0)
{s=chars.pop();}
i++;t=new CharRange(s.charCodeAt(0),pattern.charCodeAt(i));break;case"^":chars=reconcileCharacterTestStack(chars,negate);negate=!negate;break;case"\\":i++;t=new CharSingle(pattern.charCodeAt(i));break;default:chars.push(c);break;}
if(t!=null){if(negate){excludes.push(t);}else{includes.push(t);}}
i++;};chars=reconcileCharacterTestStack(chars,negate);if(includes.length==0&&excludes.length>0){includes.push(new CharRange(0,0xFF));}}
function reconcileCharacterTestStack(chars,negate){var code;var used={};while(chars.length>0){code=chars[0].charCodeAt(0);if(!used["c"+code]){t=new CharSingle(code);if(negate){excludes.push(t);}else{includes.push(t);}
used["c"+code]=true;chars.shift();}}
return chars}
function CharSingle(code){this.test=function(c){return c==code;}}
function CharRange(scode,ecode){this.test=function(c){return scode<=c&&c<=ecode;}}};})(jQuery);