text: /*
   * Copyright (c) 2007 Josh Bush (digitalbush.com)
   * 
   * Permission is hereby granted, free of charge, to any person
   * obtaining a copy of this software and associated documentation
   * files (the "Software"), to deal in the Software without
   * restriction, including without limitation the rights to use,
   * copy, modify, merge, publish, distribute, sublicense, and/or sell
   * copies of the Software, and to permit persons to whom the
   * Software is furnished to do so, subject to the following
   * conditions:
  
   * The above copyright notice and this permission notice shall be
   * included in all copies or substantial portions of the Software.
   * 
   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
   * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
   * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
   * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
   * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
   * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
   * OTHER DEALINGS IN THE SOFTWARE. 
   */
  
  /*
   * Version: 1.1
   * Release: 2007-09-08
   */
  (function ($) {
      //Helper Functions for Caret positioning
      function getCaretPosition(ctl) {
          var res = {begin: 0, end: 0};
          if (ctl.setSelectionRange) {
              res.begin = ctl.selectionStart;
              res.end = ctl.selectionEnd;
          } else if (document.selection && document.selection.createRange) {
              var range = document.selection.createRange();
              res.begin = 0 - range.duplicate().moveStart('character', -100000);
              res.end = res.begin + range.text.length;
          }
          return res;
      };
  
      function setCaretPosition(ctl, pos) {
          if (ctl.setSelectionRange) {
              ctl.focus();
              ctl.setSelectionRange(pos, pos);
          } else if (ctl.createTextRange) {
              var range = ctl.createTextRange();
              range.collapse(true);
              range.moveEnd('character', pos);
              range.moveStart('character', pos);
              range.select();
          }
      };
  
      //Predefined character definitions
      var charMap = {
          '9': "[0-9]",
          'a': "[A-Za-z]",
          '*': "[A-Za-z0-9]"
      };
  
      //Helper method to inject character definitions
      $.mask = {
          addPlaceholder: function (c, r) {
              charMap[c] = r;
          }
      };
  
      $.fn.unmask = function () {
          return this.trigger("unmask");
      };
  
      //Main Method
      $.fn.mask = function (mask, settings) {
          settings = $.extend({
              placeholder: "_",
              completed: null
          }, settings);
  
          //Build Regex for format validation
          var reString = "^";
          for (var i = 0; i < mask.length; i++)
              reString += (charMap[mask.charAt(i)] || ("\\" + mask.charAt(i)));
          reString += "$";
          var re = new RegExp(reString);
  
          return this.each(function () {
              var input = $(this);
              var buffer = new Array(mask.length);
              var locked = new Array(mask.length);
  
              //Build buffer layout from mask
              for (var i = 0; i < mask.length; i++) {
                  locked[i] = charMap[mask.charAt(i)] == null;
                  buffer[i] = locked[i] ? mask.charAt(i) : settings.placeholder;
              }
  
              /*Event Bindings*/
              function focusEvent() {
                  checkVal();
                  writeBuffer();
                  setTimeout(function () {
                      setCaretPosition(input[0], 0);
                  }, 0);
              };
              input.bind("focus", focusEvent);
  
              input.bind("blur", checkVal);
  
              //Paste events for IE and Mozilla thanks to Kristinn Sigmundsson
              if ($.browser.msie)
                  this.onpaste = function () {
                      setTimeout(checkVal, 0);
                  };
              else if ($.browser.mozilla)
                  this.addEventListener('input', checkVal, false);
  
              var ignore = false;  //Variable for ignoring control keys
  
              function keydownEvent(e) {
                  var pos = getCaretPosition(this);
                  var k = e.keyCode;
                  ignore = (k < 16 || (k > 16 && k < 32 ) || (k > 32 && k < 41));
  
                  //delete selection before proceeding
                  if ((pos.begin - pos.end) != 0 && (!ignore || k == 8 || k == 46)) {
                      clearBuffer(pos.begin, pos.end);
                  }
                  //backspace and delete get special treatment
                  if (k == 8) {//backspace
                      while (pos.begin-- >= 0) {
                          if (!locked[pos.begin]) {
                              buffer[pos.begin] = settings.placeholder;
                              if ($.browser.opera) {
                                  //Opera won't let you cancel the backspace, so we'll let it backspace over a dummy character.
                                  writeBuffer(pos.begin);
                                  setCaretPosition(this, pos.begin + 1);
                              } else {
                                  writeBuffer();
                                  setCaretPosition(this, pos.begin);
                              }
                              return false;
                          }
                      }
                  } else if (k == 46) {//delete
                      clearBuffer(pos.begin, pos.begin + 1);
                      writeBuffer();
                      setCaretPosition(this, pos.begin);
                      return false;
                  } else if (k == 27) {
                      clearBuffer(0, mask.length);
                      writeBuffer();
                      setCaretPosition(this, 0);
                      return false;
                  }
  
              };
              input.bind("keydown", keydownEvent);
  
              function keypressEvent(e) {
                  if (ignore) {
                      ignore = false;
                      return;
                  }
                  e = e || window.event;
                  var k = e.charCode || e.keyCode || e.which;
  
                  var pos = getCaretPosition(this);
                  var caretPos = pos.begin;
  
                  if (e.ctrlKey || e.altKey) {//Ignore
                      return true;
                  } else if ((k >= 41 && k <= 122) || k == 32 || k > 186) {//typeable characters
                      while (pos.begin < mask.length) {
                          var reString = charMap[mask.charAt(pos.begin)];
                          var match;
                          if (reString) {
                              var reChar = new RegExp(reString);
                              match = String.fromCharCode(k).match(reChar);
                          } else {//we're on a mask char, go forward and try again
                              pos.begin += 1;
                              pos.end = pos.begin;
                              caretPos += 1;
                              continue;
                          }
  
                          if (match)
                              buffer[pos.begin] = String.fromCharCode(k);
                          else
                              return false;//reject char
  
                          while (++caretPos < mask.length) {//seek forward to next typable position
                              if (!locked[caretPos])
                                  break;
                          }
                          break;
                      }
                  } else
                      return false;
  
                  writeBuffer();
                  if (settings.completed && caretPos >= buffer.length)
                      settings.completed.call(input);
                  else
                      setCaretPosition(this, caretPos);
  
                  return false;
              };
              input.bind("keypress", keypressEvent);
  
              /*Helper Methods*/
              function clearBuffer(start, end) {
                  for (var i = start; i < end; i++) {
                      if (!locked[i])
                          buffer[i] = settings.placeholder;
                  }
              };
  
              function writeBuffer(pos) {
                  var s = "";
                  for (var i = 0; i < mask.length; i++) {
                      s += buffer[i];
                      if (i == pos)
                          s += settings.placeholder;
                  }
                  input.val(s);
                  return s;
              };
  
              function checkVal() {
                  //try to place charcters where they belong
                  var test = input.val();
                  var pos = 0;
                  for (var i = 0; i < mask.length; i++) {
                      if (!locked[i]) {
                          while (pos++ < test.length) {
                              //Regex Test each char here.
                              var reChar = new RegExp(charMap[mask.charAt(i)]);
                              if (test.charAt(pos - 1).match(reChar)) {
                                  buffer[i] = test.charAt(pos - 1);
                                  break;
                              }
                          }
                      }
                  }
                  var s = writeBuffer();
                  if (!s.match(re)) {
                      input.val("");
                      clearBuffer(0, mask.length);
                  }
              };
  
              input.one("unmask", function () {
                  input.unbind("focus", focusEvent);
                  input.unbind("blur", checkVal);
                  input.unbind("keydown", keydownEvent);
                  input.unbind("keypress", keypressEvent);
                  if ($.browser.msie)
                      this.onpaste = null;
                  else if ($.browser.mozilla)
                      this.removeEventListener('input', checkVal, false);
              });
  
          });
      };
  })(jQuery);