diff --git a/.gitignore b/.gitignore index bfa0621..3175dd7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ .idea/* + +node_modules/ diff --git a/Jakefile b/Jakefile deleted file mode 100644 index 5001cb7..0000000 --- a/Jakefile +++ /dev/null @@ -1,31 +0,0 @@ -var Handlebars=require("handlebars"), - fs = require("fs"), - path = require ("path"), - UglifyJS = require("uglify-js"), - distPath='dist/'; - -Handlebars.registerHelper('include', function(context) { - return fs.readFileSync(context,'utf8'); -}); - -function keepComment(node,comment){ - return comment.type === "comment2"; -} - -task('clean',function(){ - fs.rmdir(distPath) -}); - -task('default',['clean'], function (params) { - fs.mkdir(distPath,0755); - - var options = JSON.parse(fs.readFileSync('plugin.json','utf8')) - options.Year=new Date().getFullYear() - - var template = Handlebars.compile(fs.readFileSync('templates/jquery.maskedinput.template','utf8')); - var debugFile = path.join(distPath,'jquery.maskedinput.js'); - fs.writeFileSync(debugFile,template(options)); - - compressed = UglifyJS.minify(debugFile,{output:{comments:keepComment}}); - fs.writeFileSync(path.join(distPath,'jquery.maskedinput.min.js'), compressed.code); -}); \ No newline at end of file diff --git a/README.md b/README.md index ef6f39b..c95df69 100644 --- a/README.md +++ b/README.md @@ -13,3 +13,17 @@ If your requirements aren't met by the predefined placeholders, you can always a By design, this plugin will reject input which doesn't complete the mask. You can bypass this by using a '?' character at the position where you would like to consider input optional. For example, a mask of "(999) 999-9999? x99999" would require only the first 10 digits of a phone number with extension being optional. +Setting up your Developer Environment +------------------------------------- +jQuery Masked Input uses [NodeJS](http://www.nodejs.org) and [GruntJS](http://www.gruntjs.com) as it's developer platform and build automation tool. + +To get your environment setup correctly, you'll need nodejs version 0.8.25 or greater installed. You'll also need to install the grunt command line tool: + + $ sudo npm install -g grunt-cli + +Once node is installed on your system all that you need to do is install the developer dependencies and run the grunt build: + + $ npm install + $ grunt + +All of the tests for jQuery Masked Input are run using the [jasmine](http://pivotal.github.io/jasmine/) test runner. diff --git a/dist/jquery.maskedinput.js b/dist/jquery.maskedinput.js index 89ce020..74e2a41 100644 --- a/dist/jquery.maskedinput.js +++ b/dist/jquery.maskedinput.js @@ -1,338 +1,143 @@ /* - Masked Input plugin for jQuery - Copyright (c) 2007-2013 Josh Bush (digitalbush.com) - Licensed under the MIT license (http://digitalbush.com/projects/masked-input-plugin/#license) - Version: 1.3.1 + jQuery Masked Input Plugin + Copyright (c) 2007 - 2013 Josh Bush (digitalbush.com) + Licensed under the MIT license (http://digitalbush.com/projects/masked-input-plugin/#license) + Version: 1.3.1 */ -(function($) { - function getPasteEvent() { - var el = document.createElement('input'), - name = 'onpaste'; - el.setAttribute(name, ''); - return (typeof el[name] === 'function')?'paste':'input'; -} - -var pasteEventName = getPasteEvent() + ".mask", - ua = navigator.userAgent, - iPhone = /iphone/i.test(ua), - android=/android/i.test(ua), - caretTimeoutId; - -$.mask = { - //Predefined character definitions - definitions: { - '9': "[0-9]", - 'a': "[A-Za-z]", - '*': "[A-Za-z0-9]" - }, - dataName: "rawMaskFn", - placeholder: '_' -}; - -$.fn.extend({ - //Helper Function for Caret positioning - caret: function(begin, end) { - var range; - - if (this.length === 0 || this.is(":hidden")) { - return; - } - - if (typeof begin == 'number') { - end = (typeof end === 'number') ? end : begin; - return this.each(function() { - if (this.setSelectionRange) { - this.setSelectionRange(begin, end); - } else if (this.createTextRange) { - 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) { - 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) { - var input, - defs, - tests, - partialPosition, - firstNonMaskPos, - len; - - if (!mask && this.length > 0) { - input = $(this[0]); - return input.data($.mask.dataName)(); - } - settings = $.extend({ - placeholder: $.mask.placeholder, // Load default placeholder - completed: null - }, settings); - - - defs = $.mask.definitions; - tests = []; - partialPosition = len = mask.length; - firstNonMaskPos = null; - - $.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.trigger("unmask").each(function() { - var input = $(this), - buffer = $.map( - mask.split(""), - function(c, i) { - if (c != '?') { - return defs[c] ? settings.placeholder : c; - } - }), - focusText = input.val(); - - function seekNext(pos) { - while (++pos < len && !tests[pos]); - return pos; - } - - function seekPrev(pos) { - while (--pos >= 0 && !tests[pos]); - return pos; - } - - function shiftL(begin,end) { - var i, - j; - - if (begin<0) { - return; - } - - for (i = begin, j = seekNext(end); i < len; i++) { - if (tests[i]) { - if (j < len && tests[i].test(buffer[j])) { - buffer[i] = buffer[j]; - buffer[j] = settings.placeholder; - } else { - break; - } - - j = seekNext(j); - } - } - writeBuffer(); - input.caret(Math.max(firstNonMaskPos, begin)); - } - - function shiftR(pos) { - var i, - c, - j, - t; - - for (i = pos, c = settings.placeholder; i < len; i++) { - if (tests[i]) { - j = seekNext(i); - t = buffer[i]; - buffer[i] = c; - if (j < len && tests[j].test(t)) { - c = t; - } else { - break; - } - } - } - } - - function keydownEvent(e) { - var k = e.which, - pos, - begin, - end; - - //backspace, delete, and escape get special treatment - if (k === 8 || k === 46 || (iPhone && k === 127)) { - pos = input.caret(); - begin = pos.begin; - end = pos.end; - - if (end - begin === 0) { - begin=k!==46?seekPrev(begin):(end=seekNext(begin-1)); - end=k===46?seekNext(end):end; - } - clearBuffer(begin, end); - shiftL(begin, end - 1); - - e.preventDefault(); - } else if (k == 27) {//escape - input.val(focusText); - input.caret(0, checkVal()); - e.preventDefault(); - } - } - - function keypressEvent(e) { - var k = e.which, - pos = input.caret(), - p, - c, - next; - - if (e.ctrlKey || e.altKey || e.metaKey || k < 32) {//Ignore - return; - } else if (k) { - if (pos.end - pos.begin !== 0){ - clearBuffer(pos.begin, pos.end); - shiftL(pos.begin, pos.end-1); - } - - p = seekNext(pos.begin - 1); - if (p < len) { - c = String.fromCharCode(k); - if (tests[p].test(c)) { - shiftR(p); - - buffer[p] = c; - writeBuffer(); - next = seekNext(p); - - if(android){ - setTimeout($.proxy($.fn.caret,input,next),0); - }else{ - input.caret(next); - } - - if (settings.completed && next >= len) { - settings.completed.call(input); - } - } - } - e.preventDefault(); - } - } - - function clearBuffer(start, end) { - var i; - for (i = start; i < end && i < len; i++) { - if (tests[i]) { - buffer[i] = settings.placeholder; - } - } - } - - function writeBuffer() { input.val(buffer.join('')); } - - function checkVal(allow) { - //try to place characters where they belong - var test = input.val(), - lastMatch = -1, - i, - c; - - for (i = 0, pos = 0; i < len; i++) { - if (tests[i]) { - buffer[i] = settings.placeholder; - while (pos++ < test.length) { - 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.charAt(pos) && i !== partialPosition) { - pos++; - lastMatch = i; - } - } - if (allow) { - writeBuffer(); - } else if (lastMatch + 1 < partialPosition) { - input.val(""); - clearBuffer(0, len); - } else { - writeBuffer(); - input.val(input.val().substring(0, lastMatch + 1)); - } - return (partialPosition ? i : firstNonMaskPos); - } - - input.data($.mask.dataName,function(){ - return $.map(buffer, function(c, i) { - return tests[i]&&c!=settings.placeholder ? c : null; - }).join(''); - }); - - if (!input.attr("readonly")) - input - .one("unmask", function() { - input - .unbind(".mask") - .removeData($.mask.dataName); - }) - .bind("focus.mask", function() { - clearTimeout(caretTimeoutId); - var pos, - moveCaret; - - focusText = input.val(); - pos = checkVal(); - - caretTimeoutId = setTimeout(function(){ - writeBuffer(); - if (pos == mask.length) { - input.caret(0, pos); - } else { - input.caret(pos); - } - }, 10); - }) - .bind("blur.mask", function() { - checkVal(); - if (input.val() != focusText) - input.change(); - }) - .bind("keydown.mask", keydownEvent) - .bind("keypress.mask", keypressEvent) - .bind(pasteEventName, function() { - setTimeout(function() { - var pos=checkVal(true); - input.caret(pos); - if (settings.completed && pos == input.val().length) - settings.completed.call(input); - }, 0); - }); - checkVal(); //Perform initial check for existing values - }); - } -}); - - -})(jQuery); +!function($) { + function getPasteEvent() { + var el = document.createElement("input"), name = "onpaste"; + return el.setAttribute(name, ""), "function" == typeof el[name] ? "paste" : "input"; + } + var caretTimeoutId, pasteEventName = getPasteEvent() + ".mask", ua = navigator.userAgent, iPhone = /iphone/i.test(ua), chrome = /chrome/i.test(ua), android = /android/i.test(ua); + $.mask = { + definitions: { + "9": "[0-9]", + a: "[A-Za-z]", + "*": "[A-Za-z0-9]" + }, + dataName: "rawMaskFn", + placeholder: "_" + }, $.fn.extend({ + caret: function(begin, end) { + var range; + if (0 !== this.length && !this.is(":hidden")) return "number" == typeof begin ? (end = "number" == typeof end ? end : begin, + this.each(function() { + this.setSelectionRange ? this.setSelectionRange(begin, end) : this.createTextRange && (range = this.createTextRange(), + range.collapse(!0), range.moveEnd("character", end), range.moveStart("character", begin), + range.select()); + })) : (this[0].setSelectionRange ? (begin = this[0].selectionStart, end = this[0].selectionEnd) : document.selection && document.selection.createRange && (range = document.selection.createRange(), + begin = 0 - range.duplicate().moveStart("character", -1e5), end = begin + range.text.length), + { + begin: begin, + end: end + }); + }, + unmask: function() { + return this.trigger("unmask"); + }, + mask: function(mask, settings) { + var input, defs, tests, partialPosition, firstNonMaskPos, len; + return !mask && this.length > 0 ? (input = $(this[0]), input.data($.mask.dataName)()) : (settings = $.extend({ + placeholder: $.mask.placeholder, + completed: null + }, settings), defs = $.mask.definitions, tests = [], partialPosition = len = mask.length, + firstNonMaskPos = null, $.each(mask.split(""), function(i, c) { + "?" == c ? (len--, partialPosition = i) : defs[c] ? (tests.push(new RegExp(defs[c])), + null === firstNonMaskPos && (firstNonMaskPos = tests.length - 1)) : tests.push(null); + }), this.trigger("unmask").each(function() { + function seekNext(pos) { + for (;++pos < len && !tests[pos]; ) ; + return pos; + } + function seekPrev(pos) { + for (;--pos >= 0 && !tests[pos]; ) ; + return pos; + } + function shiftL(begin, end) { + var i, j; + if (!(0 > begin)) { + for (i = begin, j = seekNext(end); len > i; i++) if (tests[i]) { + if (!(len > j && tests[i].test(buffer[j]))) break; + buffer[i] = buffer[j], buffer[j] = settings.placeholder, j = seekNext(j); + } + writeBuffer(), input.caret(Math.max(firstNonMaskPos, begin)); + } + } + function shiftR(pos) { + var i, c, j, t; + for (i = pos, c = settings.placeholder; len > i; i++) if (tests[i]) { + if (j = seekNext(i), t = buffer[i], buffer[i] = c, !(len > j && tests[j].test(t))) break; + c = t; + } + } + function keydownEvent(e) { + var pos, begin, end, k = e.which; + 8 === k || 46 === k || iPhone && 127 === k ? (pos = input.caret(), begin = pos.begin, + end = pos.end, 0 === end - begin && (begin = 46 !== k ? seekPrev(begin) : end = seekNext(begin - 1), + end = 46 === k ? seekNext(end) : end), clearBuffer(begin, end), shiftL(begin, end - 1), + e.preventDefault()) : 27 == k && (input.val(focusText), input.caret(0, checkVal()), + e.preventDefault()); + } + function keypressEvent(e) { + var p, c, next, k = e.which, pos = input.caret(); + if (0 == k) { + if (pos.begin >= len) return input.val(input.val().substr(0, len)), e.preventDefault(), + !1; + pos.begin == pos.end && (k = input.val().charCodeAt(pos.begin - 1), pos.begin--, + pos.end--); + } + e.ctrlKey || e.altKey || e.metaKey || 32 > k || k && (0 !== pos.end - pos.begin && (clearBuffer(pos.begin, pos.end), + shiftL(pos.begin, pos.end - 1)), p = seekNext(pos.begin - 1), len > p && (c = String.fromCharCode(k), + tests[p].test(c) && (shiftR(p), buffer[p] = c, writeBuffer(), next = seekNext(p), + android ? setTimeout($.proxy($.fn.caret, input, next), 0) : input.caret(next), settings.completed && next >= len && settings.completed.call(input))), + e.preventDefault()); + } + function clearBuffer(start, end) { + var i; + for (i = start; end > i && len > i; i++) tests[i] && (buffer[i] = settings.placeholder); + } + function writeBuffer() { + input.val(buffer.join("")); + } + function checkVal(allow) { + var i, c, pos, test = input.val(), lastMatch = -1; + for (i = 0, pos = 0; len > i; i++) if (tests[i]) { + for (buffer[i] = settings.placeholder; pos++ < test.length; ) if (c = test.charAt(pos - 1), + tests[i].test(c)) { + buffer[i] = c, lastMatch = i; + break; + } + if (pos > test.length) break; + } else buffer[i] === test.charAt(pos) && i !== partialPosition && (pos++, lastMatch = i); + return allow ? writeBuffer() : partialPosition > lastMatch + 1 ? (input.val(""), + clearBuffer(0, len)) : (writeBuffer(), input.val(input.val().substring(0, lastMatch + 1))), + partialPosition ? i : firstNonMaskPos; + } + var input = $(this), buffer = $.map(mask.split(""), function(c) { + return "?" != c ? defs[c] ? settings.placeholder : c : void 0; + }), focusText = input.val(); + input.data($.mask.dataName, function() { + return $.map(buffer, function(c, i) { + return tests[i] && c != settings.placeholder ? c : null; + }).join(""); + }), input.attr("readonly") || input.one("unmask", function() { + input.unbind(".mask").removeData($.mask.dataName); + }).bind("focus.mask", function() { + clearTimeout(caretTimeoutId); + var pos; + focusText = input.val(), pos = checkVal(), caretTimeoutId = setTimeout(function() { + writeBuffer(), pos == mask.length ? input.caret(0, pos) : input.caret(pos); + }, 10); + }).bind("blur.mask", function() { + checkVal(), input.val() != focusText && input.change(); + }).bind("keydown.mask", keydownEvent).bind("keypress.mask", keypressEvent).bind(pasteEventName, function() { + setTimeout(function() { + var pos = checkVal(!0); + input.caret(pos), settings.completed && pos == input.val().length && settings.completed.call(input); + }, 0); + }), chrome && android && input.bind("keyup.mask", keypressEvent), checkVal(); + })); + } + }); +}(jQuery); \ No newline at end of file diff --git a/dist/jquery.maskedinput.min.js b/dist/jquery.maskedinput.min.js index 0d9ce6e..683f0e1 100644 --- a/dist/jquery.maskedinput.min.js +++ b/dist/jquery.maskedinput.min.js @@ -1,7 +1,7 @@ /* - Masked Input plugin for jQuery - Copyright (c) 2007-2013 Josh Bush (digitalbush.com) - Licensed under the MIT license (http://digitalbush.com/projects/masked-input-plugin/#license) - Version: 1.3.1 + jQuery Masked Input Plugin + Copyright (c) 2007 - 2013 Josh Bush (digitalbush.com) + Licensed under the MIT license (http://digitalbush.com/projects/masked-input-plugin/#license) + Version: 1.3.1 */ -(function(e){function t(){var e=document.createElement("input"),t="onpaste";return e.setAttribute(t,""),"function"==typeof e[t]?"paste":"input"}var n,a=t()+".mask",r=navigator.userAgent,i=/iphone/i.test(r),o=/android/i.test(r);e.mask={definitions:{9:"[0-9]",a:"[A-Za-z]","*":"[A-Za-z0-9]"},dataName:"rawMaskFn",placeholder:"_"},e.fn.extend({caret:function(e,t){var n;if(0!==this.length&&!this.is(":hidden"))return"number"==typeof e?(t="number"==typeof t?t:e,this.each(function(){this.setSelectionRange?this.setSelectionRange(e,t):this.createTextRange&&(n=this.createTextRange(),n.collapse(!0),n.moveEnd("character",t),n.moveStart("character",e),n.select())})):(this[0].setSelectionRange?(e=this[0].selectionStart,t=this[0].selectionEnd):document.selection&&document.selection.createRange&&(n=document.selection.createRange(),e=0-n.duplicate().moveStart("character",-1e5),t=e+n.text.length),{begin:e,end:t})},unmask:function(){return this.trigger("unmask")},mask:function(t,r){var c,l,s,u,f,h;return!t&&this.length>0?(c=e(this[0]),c.data(e.mask.dataName)()):(r=e.extend({placeholder:e.mask.placeholder,completed:null},r),l=e.mask.definitions,s=[],u=h=t.length,f=null,e.each(t.split(""),function(e,t){"?"==t?(h--,u=e):l[t]?(s.push(RegExp(l[t])),null===f&&(f=s.length-1)):s.push(null)}),this.trigger("unmask").each(function(){function c(e){for(;h>++e&&!s[e];);return e}function d(e){for(;--e>=0&&!s[e];);return e}function m(e,t){var n,a;if(!(0>e)){for(n=e,a=c(t);h>n;n++)if(s[n]){if(!(h>a&&s[n].test(R[a])))break;R[n]=R[a],R[a]=r.placeholder,a=c(a)}b(),x.caret(Math.max(f,e))}}function p(e){var t,n,a,i;for(t=e,n=r.placeholder;h>t;t++)if(s[t]){if(a=c(t),i=R[t],R[t]=n,!(h>a&&s[a].test(i)))break;n=i}}function g(e){var t,n,a,r=e.which;8===r||46===r||i&&127===r?(t=x.caret(),n=t.begin,a=t.end,0===a-n&&(n=46!==r?d(n):a=c(n-1),a=46===r?c(a):a),k(n,a),m(n,a-1),e.preventDefault()):27==r&&(x.val(S),x.caret(0,y()),e.preventDefault())}function v(t){var n,a,i,l=t.which,u=x.caret();t.ctrlKey||t.altKey||t.metaKey||32>l||l&&(0!==u.end-u.begin&&(k(u.begin,u.end),m(u.begin,u.end-1)),n=c(u.begin-1),h>n&&(a=String.fromCharCode(l),s[n].test(a)&&(p(n),R[n]=a,b(),i=c(n),o?setTimeout(e.proxy(e.fn.caret,x,i),0):x.caret(i),r.completed&&i>=h&&r.completed.call(x))),t.preventDefault())}function k(e,t){var n;for(n=e;t>n&&h>n;n++)s[n]&&(R[n]=r.placeholder)}function b(){x.val(R.join(""))}function y(e){var t,n,a=x.val(),i=-1;for(t=0,pos=0;h>t;t++)if(s[t]){for(R[t]=r.placeholder;pos++a.length)break}else R[t]===a.charAt(pos)&&t!==u&&(pos++,i=t);return e?b():u>i+1?(x.val(""),k(0,h)):(b(),x.val(x.val().substring(0,i+1))),u?t:f}var x=e(this),R=e.map(t.split(""),function(e){return"?"!=e?l[e]?r.placeholder:e:void 0}),S=x.val();x.data(e.mask.dataName,function(){return e.map(R,function(e,t){return s[t]&&e!=r.placeholder?e:null}).join("")}),x.attr("readonly")||x.one("unmask",function(){x.unbind(".mask").removeData(e.mask.dataName)}).bind("focus.mask",function(){clearTimeout(n);var e;S=x.val(),e=y(),n=setTimeout(function(){b(),e==t.length?x.caret(0,e):x.caret(e)},10)}).bind("blur.mask",function(){y(),x.val()!=S&&x.change()}).bind("keydown.mask",g).bind("keypress.mask",v).bind(a,function(){setTimeout(function(){var e=y(!0);x.caret(e),r.completed&&e==x.val().length&&r.completed.call(x)},0)}),y()}))}})})(jQuery); \ No newline at end of file +!function(a){function b(){var a=document.createElement("input"),b="onpaste";return a.setAttribute(b,""),"function"==typeof a[b]?"paste":"input"}var c,d=b()+".mask",e=navigator.userAgent,f=/iphone/i.test(e),g=/chrome/i.test(e),h=/android/i.test(e);a.mask={definitions:{9:"[0-9]",a:"[A-Za-z]","*":"[A-Za-z0-9]"},dataName:"rawMaskFn",placeholder:"_"},a.fn.extend({caret:function(a,b){var c;if(0!==this.length&&!this.is(":hidden"))return"number"==typeof a?(b="number"==typeof b?b:a,this.each(function(){this.setSelectionRange?this.setSelectionRange(a,b):this.createTextRange&&(c=this.createTextRange(),c.collapse(!0),c.moveEnd("character",b),c.moveStart("character",a),c.select())})):(this[0].setSelectionRange?(a=this[0].selectionStart,b=this[0].selectionEnd):document.selection&&document.selection.createRange&&(c=document.selection.createRange(),a=0-c.duplicate().moveStart("character",-1e5),b=a+c.text.length),{begin:a,end:b})},unmask:function(){return this.trigger("unmask")},mask:function(b,e){var i,j,k,l,m,n;return!b&&this.length>0?(i=a(this[0]),i.data(a.mask.dataName)()):(e=a.extend({placeholder:a.mask.placeholder,completed:null},e),j=a.mask.definitions,k=[],l=n=b.length,m=null,a.each(b.split(""),function(a,b){"?"==b?(n--,l=a):j[b]?(k.push(new RegExp(j[b])),null===m&&(m=k.length-1)):k.push(null)}),this.trigger("unmask").each(function(){function i(a){for(;++a=0&&!k[a];);return a}function p(a,b){var c,d;if(!(0>a)){for(c=a,d=i(b);n>c;c++)if(k[c]){if(!(n>d&&k[c].test(x[d])))break;x[c]=x[d],x[d]=e.placeholder,d=i(d)}u(),w.caret(Math.max(m,a))}}function q(a){var b,c,d,f;for(b=a,c=e.placeholder;n>b;b++)if(k[b]){if(d=i(b),f=x[b],x[b]=c,!(n>d&&k[d].test(f)))break;c=f}}function r(a){var b,c,d,e=a.which;8===e||46===e||f&&127===e?(b=w.caret(),c=b.begin,d=b.end,0===d-c&&(c=46!==e?o(c):d=i(c-1),d=46===e?i(d):d),t(c,d),p(c,d-1),a.preventDefault()):27==e&&(w.val(y),w.caret(0,v()),a.preventDefault())}function s(b){var c,d,f,g=b.which,j=w.caret();if(0==g){if(j.begin>=n)return w.val(w.val().substr(0,n)),b.preventDefault(),!1;j.begin==j.end&&(g=w.val().charCodeAt(j.begin-1),j.begin--,j.end--)}b.ctrlKey||b.altKey||b.metaKey||32>g||g&&(0!==j.end-j.begin&&(t(j.begin,j.end),p(j.begin,j.end-1)),c=i(j.begin-1),n>c&&(d=String.fromCharCode(g),k[c].test(d)&&(q(c),x[c]=d,u(),f=i(c),h?setTimeout(a.proxy(a.fn.caret,w,f),0):w.caret(f),e.completed&&f>=n&&e.completed.call(w))),b.preventDefault())}function t(a,b){var c;for(c=a;b>c&&n>c;c++)k[c]&&(x[c]=e.placeholder)}function u(){w.val(x.join(""))}function v(a){var b,c,d,f=w.val(),g=-1;for(b=0,d=0;n>b;b++)if(k[b]){for(x[b]=e.placeholder;d++f.length)break}else x[b]===f.charAt(d)&&b!==l&&(d++,g=b);return a?u():l>g+1?(w.val(""),t(0,n)):(u(),w.val(w.val().substring(0,g+1))),l?b:m}var w=a(this),x=a.map(b.split(""),function(a){return"?"!=a?j[a]?e.placeholder:a:void 0}),y=w.val();w.data(a.mask.dataName,function(){return a.map(x,function(a,b){return k[b]&&a!=e.placeholder?a:null}).join("")}),w.attr("readonly")||w.one("unmask",function(){w.unbind(".mask").removeData(a.mask.dataName)}).bind("focus.mask",function(){clearTimeout(c);var a;y=w.val(),a=v(),c=setTimeout(function(){u(),a==b.length?w.caret(0,a):w.caret(a)},10)}).bind("blur.mask",function(){v(),w.val()!=y&&w.change()}).bind("keydown.mask",r).bind("keypress.mask",s).bind(d,function(){setTimeout(function(){var a=v(!0);w.caret(a),e.completed&&a==w.val().length&&e.completed.call(w)},0)}),g&&h&&w.bind("keyup.mask",s),v()}))}})}(jQuery); \ No newline at end of file diff --git a/gruntfile.js b/gruntfile.js new file mode 100644 index 0000000..5896f86 --- /dev/null +++ b/gruntfile.js @@ -0,0 +1,54 @@ + +"use strict"; + +module.exports = function( grunt ) { + grunt.initConfig({ + // TODO: change to read component.json + pkg: require('./package.json'), + + uglify: { + options: { + banner: '/*\n <%= pkg.description %>\n Copyright (c) 2007 - <%= grunt.template.today("yyyy") %> <%= pkg.author %>\n Licensed under the MIT license (http://digitalbush.com/projects/masked-input-plugin/#license)\n Version: <%= pkg.version %>\n*/\n' + }, + + dev: { + options: { + beautify: true, + mangle: false + }, + + files: { + 'dist/jquery.maskedinput.js': ['src/jquery.maskedinput.js'] + } + }, + + min: { + files: { + 'dist/jquery.maskedinput.min.js': ['src/jquery.maskedinput.js'] + } + } + }, + + jasmine: { + full: { + src: "src/**/*.js", + options: { + specs: "spec/*[S|s]pec.js", + vendor: [ + "spec/lib/matchers.js", + "spec/lib/jasmine-species/jasmine-grammar.js", + "spec/lib/setup.js", + "lib/jquery-1.9.0.min.js", + "spec/lib/jquery.keymasher.js" + ] + } + } + } + }); + + grunt.loadNpmTasks("grunt-contrib-jasmine"); + grunt.loadNpmTasks("grunt-contrib-uglify"); + + grunt.registerTask('test', ['jasmine']); + grunt.registerTask('default', ['test', 'uglify']); +}; diff --git a/package.json b/package.json new file mode 100644 index 0000000..8b3a95d --- /dev/null +++ b/package.json @@ -0,0 +1,13 @@ +{ + "name": "jquery.maskedinput", + "version": "1.3.1", + "author": "Josh Bush (digitalbush.com)", + "description": "jQuery Masked Input Plugin", + + "devDependencies": { + "grunt": "0.4.x", + "grunt-contrib-jasmine": "0.5.x", + "grunt-contrib-watch": "0.5.x", + "grunt-contrib-uglify": "0.2.x" + } +} diff --git a/spec/SpecRunner.html b/spec/SpecRunner.html deleted file mode 100644 index 0339b85..0000000 --- a/spec/SpecRunner.html +++ /dev/null @@ -1,68 +0,0 @@ - - - - Masked Input Plugin Tests - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/spec/lib/setup.js b/spec/lib/setup.js new file mode 100644 index 0000000..9539215 --- /dev/null +++ b/spec/lib/setup.js @@ -0,0 +1,14 @@ +function importGrammar(g){ + for (var prop in g) { + if (g.hasOwnProperty(prop)) + window[prop] = g[prop]; + + } +} + +importGrammar(jasmine.grammar.FeatureStory); +importGrammar(jasmine.grammar.GWT); + +var input; +beforeEach(function(){ input = $("").appendTo("body").focus(); }); +afterEach(function(){ input.remove();}); diff --git a/src/jquery.maskedinput.js b/src/jquery.maskedinput.js index 9c0d392..a526da8 100644 --- a/src/jquery.maskedinput.js +++ b/src/jquery.maskedinput.js @@ -1,8 +1,10 @@ +(function($) { + function getPasteEvent() { var el = document.createElement('input'), name = 'onpaste'; el.setAttribute(name, ''); - return (typeof el[name] === 'function')?'paste':'input'; + return (typeof el[name] === 'function')?'paste':'input'; } var pasteEventName = getPasteEvent() + ".mask", @@ -314,7 +316,7 @@ $.fn.extend({ focusText = input.val(); pos = checkVal(); - + caretTimeoutId = setTimeout(function(){ writeBuffer(); if (pos == mask.length) { @@ -332,9 +334,9 @@ $.fn.extend({ .bind("keydown.mask", keydownEvent) .bind("keypress.mask", keypressEvent) .bind(pasteEventName, function() { - setTimeout(function() { + setTimeout(function() { var pos=checkVal(true); - input.caret(pos); + input.caret(pos); if (settings.completed && pos == input.val().length) settings.completed.call(input); }, 0); @@ -346,3 +348,4 @@ $.fn.extend({ }); } }); +})(jQuery); diff --git a/templates/jquery.maskedinput.template b/templates/jquery.maskedinput.template deleted file mode 100644 index 18f6d17..0000000 --- a/templates/jquery.maskedinput.template +++ /dev/null @@ -1,9 +0,0 @@ -/* - Masked Input plugin for jQuery - Copyright (c) 2007-{{Year}} Josh Bush (digitalbush.com) - Licensed under the MIT license (http://digitalbush.com/projects/masked-input-plugin/#license) - Version: {{version}} -*/ -(function($) { - {{{include "src/jquery.maskedinput.js"}}} -})(jQuery); \ No newline at end of file