Skip to content

Instantly share code, notes, and snippets.

@gladson
Created November 23, 2012 06:20
Show Gist options
  • Save gladson/4134227 to your computer and use it in GitHub Desktop.
Save gladson/4134227 to your computer and use it in GitHub Desktop.
Masked Input plugin for jQuery
/// <reference path="../../../lib/jquery-1.2.6.js" />
/*
Masked Input plugin for jQuery
Copyright (c) 2007-2009 Josh Bush (digitalbush.com)
Licensed under the MIT license (http://digitalbush.com/projects/masked-input-plugin/#license)
Version: 1.2.2 (03/09/2009 22:39:06)
*/
(function($) {
var pasteEventName = ($.browser.msie ? 'paste' : 'input') + ".mask";
var iPhone = (window.orientation != undefined);
$.mask = {
//Predefined character definitions
definitions: {
'9': "[0-9]",
'a': "[A-Za-z]",
'*': "[A-Za-z0-9]",
'0': "[0-9 ]",
't': "[A-Za-z0-9_]"
}
};
/*
'f': {
"validator": "[0-9\(\)\.\+/ ]",
"cardinality": 1,
'prevalidator': null
}
'd': { //day
"validator": "0[1-9]|[12][0-9]|3[01]",
"cardinality": 2,
"prevalidator": [{ "validator": "[0-3]", "cardinality": 1}]
}
*/
$.fn.extend({
//Helper Function for Caret positioning
caret: function(begin, end) {
if (this.length == 0) return;
if (typeof begin == 'number') {
end = (typeof end == 'number') ? end : begin;
return this.each(function() {
if (this.setSelectionRange) {
this.focus();
this.setSelectionRange(begin, end);
} else if (this.createTextRange) {
var range = this.createTextRange();
range.collapse(true);
range.moveEnd('character', end);
range.moveStart('character', begin);
range.select();
}
});
} else {
if (this[0].setSelectionRange) {
begin = this[0].selectionStart;
end = this[0].selectionEnd;
} else if (document.selection && document.selection.createRange) {
var range = document.selection.createRange();
begin = 0 - range.duplicate().moveStart('character', -100000);
end = begin + range.text.length;
}
return { begin: begin, end: end };
}
},
unmask: function() { return this.trigger("unmask"); },
mask: function(mask, settings) {
if (!mask && this.length > 0) {
var input = $(this[0]);
var tests = input.data("tests");
return $.map(input.data("buffer"), function(c, i) {
return tests[i] ? c : null;
}).join('');
}
settings = $.extend({
placeholder: "",
completed: null
}, settings);
var defs = $.mask.definitions;
var tests = [];
var partialPosition = mask.length;
var firstNonMaskPos = null;
var len = mask.length;
$.each(mask.split(""), function(i, c) {
if (c == '?') {
len--;
partialPosition = i;
} else if (defs[c]) {
tests.push(new RegExp(defs[c]));
if(firstNonMaskPos==null)
firstNonMaskPos = tests.length - 1;
} else {
tests.push(null);
}
});
return this.each(function() {
var input = $(this);
var buffer = $.map(mask.split(""), function(c, i) { if (c != '?') return defs[c] ? settings.placeholder : c });
var ignore = false; //Variable for ignoring control keys
var focusText = input.val();
input.data("buffer", buffer).data("tests", tests);
function seekNext(pos) {
while (++pos <= len && !tests[pos]);
return pos;
};
function shiftL(pos) {
while (!tests[pos] && --pos >= 0);
for (var i = pos; i < len; i++) {
if (tests[i]) {
buffer[i] = settings.placeholder;
var j = seekNext(i);
if (j < len && tests[i].test(buffer[j])) {
buffer[i] = buffer[j];
} else
break;
}
}
writeBuffer();
input.caret(Math.max(firstNonMaskPos, pos));
};
function shiftR(pos) {
for (var i = pos, c = settings.placeholder; i < len; i++) {
if (tests[i]) {
var j = seekNext(i);
var t = buffer[i];
buffer[i] = c;
if (j < len && tests[j].test(t))
c = t;
else
break;
}
}
};
function keydownEvent(e) {
var pos = $(this).caret();
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, delete, and escape get special treatment
if (k == 8 || k == 46 || (iPhone && k == 127)) {//backspace/delete
shiftL(pos.begin + (k == 46 ? 0 : -1));
return false;
} else if (k == 27) {//escape
input.val(focusText);
input.caret(0, checkVal());
return false;
}
};
function keypressEvent(e) {
if (ignore) {
ignore = false;
//Fixes Mac FF bug on backspace
return (e.keyCode == 8) ? false : null;
}
e = e || window.event;
var k = e.charCode || e.keyCode || e.which;
var pos = $(this).caret();
if (e.ctrlKey || e.altKey || e.metaKey) {//Ignore
return true;
} else if ((k >= 32 && k <= 125) || k > 186) {//typeable characters
var p = seekNext(pos.begin - 1);
if (p < len) {
var c = String.fromCharCode(k);
if (tests[p].test(c)) {
shiftR(p);
buffer[p] = c;
writeBuffer();
var next = seekNext(p);
$(this).caret(next);
if (settings.completed && next == len)
settings.completed.call(input);
}
}
}
return false;
};
function clearBuffer(start, end) {
for (var i = start; i < end && i < len; i++) {
if (tests[i])
buffer[i] = settings.placeholder;
}
};
function writeBuffer() { return input.val(buffer.join('')).val(); };
function checkVal(allow) {
//try to place characters where they belong
var test = input.val();
var lastMatch = -1;
for (var i = 0, pos = 0; i < len; i++) {
if (tests[i]) {
buffer[i] = settings.placeholder;
while (pos++ < test.length) {
var c = test.charAt(pos - 1);
if (tests[i].test(c)) {
buffer[i] = c;
lastMatch = i;
break;
}
}
if (pos > test.length)
break;
} else if (buffer[i] == test[pos] && i!=partialPosition) {
pos++;
lastMatch = i;
}
}
if (!allow && lastMatch + 1 < partialPosition) {
input.val("");
clearBuffer(0, len);
} else if (allow || lastMatch + 1 >= partialPosition) {
writeBuffer();
if (!allow) input.val(input.val().substring(0, lastMatch + 1));
}
return (partialPosition ? i : firstNonMaskPos);
};
if (!input.attr("readonly"))
input
.one("unmask", function() {
input
.unbind(".mask")
.removeData("buffer")
.removeData("tests");
})
.bind("focus.mask", function() {
focusText = input.val();
var pos = checkVal();
writeBuffer();
setTimeout(function() {
if (pos == mask.length)
input.caret(0, pos);
else
input.caret(pos);
}, 0);
})
.bind("blur.mask", function() {
checkVal();
if (input.val() != focusText)
input.change();
})
.bind("keydown.mask", keydownEvent)
.bind("keypress.mask", keypressEvent)
.bind(pasteEventName, function() {
setTimeout(function() { input.caret(checkVal(true)); }, 0);
});
checkVal(); //Perform initial check for existing values
});
}
});
})(jQuery);
(function(c){var a=(c.browser.msie?"paste":"input")+".mask";var b=(window.orientation!=undefined);c.mask={definitions:{"9":"[0-9]",a:"[A-Za-z]","*":"[A-Za-z0-9]","0":"[0-9 ]",t:"[A-Za-z0-9_]"}};c.fn.extend({caret:function(f,d){if(this.length==0){return}if(typeof f=="number"){d=(typeof d=="number")?d:f;return this.each(function(){if(this.setSelectionRange){this.focus();this.setSelectionRange(f,d)}else{if(this.createTextRange){var g=this.createTextRange();g.collapse(true);g.moveEnd("character",d);g.moveStart("character",f);g.select()}}})}else{if(this[0].setSelectionRange){f=this[0].selectionStart;d=this[0].selectionEnd}else{if(document.selection&&document.selection.createRange){var e=document.selection.createRange();f=0-e.duplicate().moveStart("character",-100000);d=f+e.text.length}}return{begin:f,end:d}}},unmask:function(){return this.trigger("unmask")},mask:function(f,j){if(!f&&this.length>0){var g=c(this[0]);var i=g.data("tests");return c.map(g.data("buffer"),function(m,l){return i[l]?m:null}).join("")}j=c.extend({placeholder:"",completed:null},j);var e=c.mask.definitions;var i=[];var k=f.length;var h=null;var d=f.length;c.each(f.split(""),function(l,m){if(m=="?"){d--;k=l}else{if(e[m]){i.push(new RegExp(e[m]));if(h==null){h=i.length-1}}else{i.push(null)}}});return this.each(function(){var u=c(this);var p=c.map(f.split(""),function(y,x){if(y!="?"){return e[y]?j.placeholder:y}});var s=false;var w=u.val();u.data("buffer",p).data("tests",i);function t(x){while(++x<=d&&!i[x]){}return x}function o(z){while(!i[z]&&--z>=0){}for(var y=z;y<d;y++){if(i[y]){p[y]=j.placeholder;var x=t(y);if(x<d&&i[y].test(p[x])){p[y]=p[x]}else{break}}}r();u.caret(Math.max(h,z))}function l(B){for(var z=B,A=j.placeholder;z<d;z++){if(i[z]){var x=t(z);var y=p[z];p[z]=A;if(x<d&&i[x].test(y)){A=y}else{break}}}}function q(y){var z=c(this).caret();var x=y.keyCode;s=(x<16||(x>16&&x<32)||(x>32&&x<41));if((z.begin-z.end)!=0&&(!s||x==8||x==46)){m(z.begin,z.end)}if(x==8||x==46||(b&&x==127)){o(z.begin+(x==46?0:-1));return false}else{if(x==27){u.val(w);u.caret(0,n());return false}}}function v(A){if(s){s=false;return(A.keyCode==8)?false:null}A=A||window.event;var x=A.charCode||A.keyCode||A.which;var C=c(this).caret();if(A.ctrlKey||A.altKey||A.metaKey){return true}else{if((x>=32&&x<=125)||x>186){var z=t(C.begin-1);if(z<d){var B=String.fromCharCode(x);if(i[z].test(B)){l(z);p[z]=B;r();var y=t(z);c(this).caret(y);if(j.completed&&y==d){j.completed.call(u)}}}}}return false}function m(z,x){for(var y=z;y<x&&y<d;y++){if(i[y]){p[y]=j.placeholder}}}function r(){return u.val(p.join("")).val()}function n(y){var C=u.val();var B=-1;for(var x=0,A=0;x<d;x++){if(i[x]){p[x]=j.placeholder;while(A++<C.length){var z=C.charAt(A-1);if(i[x].test(z)){p[x]=z;B=x;break}}if(A>C.length){break}}else{if(p[x]==C[A]&&x!=k){A++;B=x}}}if(!y&&B+1<k){u.val("");m(0,d)}else{if(y||B+1>=k){r();if(!y){u.val(u.val().substring(0,B+1))}}}return(k?x:h)}if(!u.attr("readonly")){u.one("unmask",function(){u.unbind(".mask").removeData("buffer").removeData("tests")}).bind("focus.mask",function(){w=u.val();var x=n();r();setTimeout(function(){if(x==f.length){u.caret(0,x)}else{u.caret(x)}},0)}).bind("blur.mask",function(){n();if(u.val()!=w){u.change()}}).bind("keydown.mask",q).bind("keypress.mask",v).bind(a,function(){setTimeout(function(){u.caret(n(true))},0)})}n()})}})})(jQuery);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment