diff --git a/demo/index.html b/demo/index.html
index d297b1e..c57914e 100644
--- a/demo/index.html
+++ b/demo/index.html
@@ -6,7 +6,10 @@
$(function() {
$.mask.definitions['~'] = "[+-]";
- $("#date").mask("99/99/9999",{completed:function(){alert("completed!");}});
+ $("#date").mask("99/99/9999")
+ .on("completed.mask",function(){
+ alert("completed with value: "+this.value);
+ });
$("#phone").mask("(999) 999-9999");
$("#phoneExt").mask("(999) 999-9999? x99999");
$("#iphone").mask("+33 999 999 999");
diff --git a/gruntfile.js b/gruntfile.js
index 5896f86..aa76f29 100644
--- a/gruntfile.js
+++ b/gruntfile.js
@@ -1,54 +1,75 @@
-"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
+module.exports = function(grunt) {
+ "use strict";
+ grunt.initConfig({
+ pkg: grunt.file.readJSON('package.json'),
+ 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\n',
+ concat: {
+ options: {
+ banner: '<%= banner %>',
+ stripBanners: false
+ },
+ dist: {
+ src: ['src/jquery.maskedinput.js','src/masks/*.js'],
+ dest: 'dist/<%= pkg.name %>.js'
+ }
},
-
- 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"
- ]
+ uglify: {
+ options: {
+ banner: '<%= banner %>'
+ },
+ dist: {
+ files: {
+ 'dist/<%= pkg.name %>.min.js': ['<%= concat.dist.dest %>']
+ }
+ }
+ },
+ jasmine: {
+ full: {
+ src: '<%= concat.dist.src %>',
+ options: {
+ specs: 'spec/*[S|s]pec.js',
+ vendor: [
+ 'lib/jquery-1.9.0.min.js',
+ 'spec/lib/matchers.js',
+ 'spec/lib/jasmine-species/jasmine-grammar.js',
+ 'spec/lib/setup.js',
+ 'spec/lib/jquery.keymasher.js'
+ ]
+ }
+ }
+ },
+ jshint: {
+ src: {
+ options: {
+ jshintrc: 'src/.jshintrc'
+ },
+ src: '<%= concat.dist.src %>'
+ },
+ specs: {
+ options: {
+ jshintrc: 'spec/.jshintrc'
+ },
+ src: ['<%= jasmine.full.options.specs %>']
+ }
+ },
+ watch: {
+ files: ['<%= jshint.files %>'],
+ tasks: ['jshint', 'jasmine']
}
- }
- }
- });
+ });
- grunt.loadNpmTasks("grunt-contrib-jasmine");
- grunt.loadNpmTasks("grunt-contrib-uglify");
+ grunt.loadNpmTasks('grunt-contrib-uglify');
+ grunt.loadNpmTasks('grunt-contrib-jshint');
+ grunt.loadNpmTasks('grunt-contrib-jasmine');
+ grunt.loadNpmTasks('grunt-contrib-watch');
+ grunt.loadNpmTasks('grunt-contrib-concat');
- grunt.registerTask('test', ['jasmine']);
- grunt.registerTask('default', ['test', 'uglify']);
+ grunt.registerTask('test', ['jshint', 'jasmine']);
+ grunt.registerTask('default', ['jshint', 'jasmine', 'concat', 'uglify']);
};
diff --git a/package.json b/package.json
index 2f8f240..7d80b3f 100644
--- a/package.json
+++ b/package.json
@@ -3,12 +3,13 @@
"version": "1.3.1",
"author": "Josh Bush (digitalbush.com)",
"description": "jQuery Masked Input Plugin",
-
"devDependencies": {
- "grunt": "0.4.x",
+ "grunt": "~0.4.4",
"grunt-contrib-jasmine": "0.5.x",
- "grunt-contrib-watch": "0.5.x",
- "grunt-contrib-uglify": "0.2.x"
+ "grunt-contrib-watch": "~0.6.1",
+ "grunt-contrib-uglify": "0.2.x",
+ "grunt-contrib-jshint": "~0.9.2",
+ "grunt-contrib-concat": "~0.3.0"
},
"scripts": {
"test": "grunt test"
diff --git a/plugin.json b/plugin.json
deleted file mode 100644
index e2aa63d..0000000
--- a/plugin.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "name" : "jquery.maskedinput",
- "author" : "Josh Bush (digitalbush.com)",
- "version" : "1.3.1"
-}
diff --git a/spec/.jshintrc b/spec/.jshintrc
new file mode 100644
index 0000000..a6649b9
--- /dev/null
+++ b/spec/.jshintrc
@@ -0,0 +1,3 @@
+{
+ "asi" : true
+}
diff --git a/spec/Enter.Spec.js b/spec/Enter.Spec.js
index 025e21e..636aa09 100644
--- a/spec/Enter.Spec.js
+++ b/spec/Enter.Spec.js
@@ -37,7 +37,7 @@ feature("Enter Key", function() {
input.trigger(enterKeyEvent);
});
then("value should remain visible with placeholders",function(){
- expect(input).toHaveValue("1_");
+ expect(input).toHaveValue("1");
});
});
});
@@ -63,7 +63,7 @@ feature("Enter Key", function() {
input.mashKeys("1").trigger(enterKeyEvent);
});
then("value should be empty",function(){
- expect(input).toHaveValue("1___");
+ expect(input).toHaveValue("1");
});
});
diff --git a/spec/Focus.Spec.js b/spec/Focus.Spec.js
index 9964893..91c6c25 100644
--- a/spec/Focus.Spec.js
+++ b/spec/Focus.Spec.js
@@ -123,7 +123,7 @@ feature("Leaving A Masked Input",function(){
input.blur();
});
then("value should remain visible with placeholders",function(){
- expect(input).toHaveValue("1_");
+ expect(input).toHaveValue("1");
});
});
});
@@ -149,7 +149,7 @@ feature("Optional marker",function(){
input.mashKeys("1").blur();
});
then("value should be empty",function(){
- expect(input).toHaveValue("1___");
+ expect(input).toHaveValue("1");
});
});
diff --git a/spec/Paste.Spec.js b/spec/Paste.Spec.js
index a9ae291..0997f33 100644
--- a/spec/Paste.Spec.js
+++ b/spec/Paste.Spec.js
@@ -1,8 +1,8 @@
-feature("Pasting", function() {
+feature("Pasting", function() {
scenario('When pasting a value',function(){
var completed=false;
given("an input with a completed callback", function(){
- input.mask("99",{completed:function(){completed=true;}});
+ input.mask("99").on("completed.mask",function(){completed=true;});
});
when("pasting",function(){
@@ -13,4 +13,4 @@ feature("Pasting", function() {
expect(completed).toBeTruthy();
});
});
-});
\ No newline at end of file
+});
diff --git a/spec/lib/setup.js b/spec/lib/setup.js
index 9539215..14d79fb 100644
--- a/spec/lib/setup.js
+++ b/spec/lib/setup.js
@@ -9,6 +9,39 @@ function importGrammar(g){
importGrammar(jasmine.grammar.FeatureStory);
importGrammar(jasmine.grammar.GWT);
+
+$.fn.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 };
+ }
+ };
var input;
beforeEach(function(){ input = $("").appendTo("body").focus(); });
afterEach(function(){ input.remove();});
diff --git a/src/.jshintrc b/src/.jshintrc
new file mode 100644
index 0000000..a26251b
--- /dev/null
+++ b/src/.jshintrc
@@ -0,0 +1,12 @@
+{
+ "browser" : true,
+ "jquery" : true,
+ "eqnull" : true,
+ "newcap" : true,
+ "indent" : 4,
+ "undef" : true,
+ "unused" : true,
+ "trailing" : true,
+ "curly" : true,
+ "strict" : true
+}
diff --git a/src/jquery.maskedinput.js b/src/jquery.maskedinput.js
index cd226c8..d291665 100644
--- a/src/jquery.maskedinput.js
+++ b/src/jquery.maskedinput.js
@@ -1,375 +1,220 @@
(function($) {
-
-function getPasteEvent() {
- var el = document.createElement('input'),
+ "use strict";
+ function setCaret(elm,begin,end){
+ end = (typeof end === 'number') ? end : begin;
+
+ if (elm.setSelectionRange) {
+ elm.setSelectionRange(begin, end);
+ } else if (elm.createTextRange) {
+ var range = elm.createTextRange();
+ range.collapse(true);
+ range.moveEnd('character', end);
+ range.moveStart('character', begin);
+ range.select();
+ }
+ }
+
+ function getCaret(elm){
+ var begin,end;
+ if (elm.setSelectionRange) {
+ begin = elm.selectionStart;
+ end = elm.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 };
+ }
+
+ //TODO: alias as maskedinput?
+ $.mask = {
+ masks:{},
+ //Predefined character definitions
+ //TODO: Move these to the mask def itself.
+ definitions: {
+ '9': "[0-9]",
+ 'a': "[A-Za-z]",
+ '*': "[A-Za-z0-9]"
+ },
+ autoclear: true,
+ dataName: "maskedinput",
+ placeholder: '_'
+ };
+
+ 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),
- chrome = /chrome/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]"
- },
- autoclear: true,
- 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({
- autoclear: $.mask.autoclear,
- 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;
- }
- }),
- defaultBuffer = buffer.join(''),
- 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 blurEvent(e) {
- checkVal();
-
- if (input.val() != focusText)
- input.change();
- }
-
- 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 === 13 ) { // enter
- blurEvent.call(this, e);
- } 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 (k == 0) {
- // unable to detect key pressed. Grab it from pos and adjust
- // this is a failsafe for mobile chrome
- // which can't detect keypress events
- // reliably
- if (pos.begin >= len) {
- input.val(input.val().substr(0, len));
- e.preventDefault();
- return false;
- }
- if (pos.begin == pos.end) {
- k = input.val().charCodeAt(pos.begin - 1);
- pos.begin--;
- pos.end--;
- }
+ el.setAttribute(name, '');
+ return (typeof el[name] === 'function')?'paste':'input';
+ }
+
+ var pasteEventName = getPasteEvent() + ".mask";
+
+ $.fn.extend({
+ //TODO: Be a good citizen and get this down to only .mask()
+ unmask: function() {
+ return this.trigger("unmask");
+ },
+ //TODO: we need a conflict thing here, maybe only use maskedinput(or alias?)
+ mask: function(format, settings) {
+ var input;
+
+ //TODO: make these more in line with newer plugin interaction guidelines.
+ if (!format && this.length > 0) {
+ input = $(this[0]);
+ return input.data($.mask.dataName).apply(input.val()).raw;
+ }
+
+ settings = $.extend({
+ definitions: $.mask.definitions,
+ autoclear: $.mask.autoclear,
+ placeholder: $.mask.placeholder,
+ completed: null
+ }, settings);
+
+ //Hardcoded as fixed for now.
+ var mask=new $.mask.masks.fixed(format, settings);
+
+ return this.trigger("unmask").each(function() {
+ var elm = this,
+ input = $(this),
+ focusText = elm.value;
+
+ function blurEvent() {
+ var result = mask.apply(elm.value);
+ elm.value = result.trimmed;
+ if(settings.autoclear && !result.isComplete){
+ elm.value = "";
}
- if (e.ctrlKey || e.altKey || e.metaKey || k < 32) {//Ignore
- return;
- } else if ( k && k !== 13 ) {
- 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){
- //Path for CSP Violation on FireFox OS 1.1
- var proxy = function()
- {
- $.proxy($.fn.caret,input,next);
- }
-
- setTimeout(proxy,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('')); }
+ if (elm.value != focusText){
+ input.change();
+ }
+ }
- function checkVal(allow) {
- //try to place characters where they belong
- var test = input.val(),
- lastMatch = -1,
- i,
- c,
- pos;
+ function keydownEvent(e) {
+ var k = e.which;
+
+ //backspace, delete, enter, and escape get special treatment
+ if (k === 8 || k === 46) {
+ var pos = getCaret(elm);
+ var result;
+
+ if (pos.begin != pos.end) {
+ var buffer = elm.value.split('');
+ buffer.splice(pos.begin,pos.end - pos.begin);
+ result = mask.apply(buffer.join(''), pos.begin+1);
+ result.pos = pos.begin;
+ } else if( k == 8 ) {
+ result = mask.applyBackspace(elm.value, pos.begin);
+ } else {
+ result = mask.applyDelete(elm.value, pos.begin);
+ }
- 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) {
- if (settings.autoclear || buffer.join('') === defaultBuffer) {
- // Invalid value. Remove it and replace it with the
- // mask, which is the default behavior.
- input.val("");
- clearBuffer(0, len);
- } else {
- // Invalid value, but we opt to show the value to the
- // user and allow them to correct their mistake.
- writeBuffer();
- }
- } else {
- writeBuffer();
- input.val(input.val().substring(0, lastMatch + 1));
- }
- return (partialPosition ? i : firstNonMaskPos);
- }
+ elm.value = result.value;
+ setCaret(elm, result.pos);
+ e.preventDefault();
+ } else if(k === 13) { // enter
+ blurEvent.call(elm, e);
+ } else if (k === 27) { // escape
+ elm.value = focusText;
+ setCaret(elm, 0, focusText.length);
+ e.preventDefault();
+ }
+ }
- input.data($.mask.dataName,function(){
- return $.map(buffer, function(c, i) {
- return tests[i]&&c!=settings.placeholder ? c : null;
- }).join('');
- });
+ function keypressEvent(e) {
+ var k = e.which,
+ pos = getCaret(elm);
+
+ if (e.ctrlKey || e.altKey || e.metaKey || k < 32) {//Ignore
+ return;
+ } else if (k && k !== 13) {
+ var buffer = elm.value.split('');
+ buffer.splice(pos.begin, pos.end - pos.begin, String.fromCharCode(k));
+ var result = mask.apply(buffer.join(''), pos.begin+1);
+
+ elm.value = result.value;
+ setCaret(elm, result.pos);
+ if(result.isComplete){
+ input.trigger("completed.mask");
+ }
- if (!input.attr("readonly"))
- input
- .one("unmask", function() {
- input
- .off(".mask")
- .removeData($.mask.dataName);
- })
- .on("focus.mask", function() {
- clearTimeout(caretTimeoutId);
- var pos;
+ e.preventDefault();
+
+ // if(android){
+ // //Path for CSP Violation on FireFox OS 1.1
+ // var proxy = function()
+ // {
+ //
+ // $.proxy(setCaret,elm,next);
+ // }
+ //
+ // setTimeout(proxy,0);
+ // }else{
+ // setCaret(elm,next);
+ // }
+ }
+ }
- focusText = input.val();
+ var caretTimeoutId;
+ function focusEvent(){
+ clearTimeout(caretTimeoutId);
+ var result = mask.apply(elm.value);
+ focusText = elm.value;
+
+ caretTimeoutId = setTimeout(function(){
+ elm.value = result.value;
+ if (result.isComplete) {
+ setCaret(elm, 0, result.pos);
+ } else {
+ setCaret(elm, result.pos);
+ }
+ }, 10);
+ }
- pos = checkVal();
+ function pasteEvent(){
+ setTimeout(function() {
+ var pos = getCaret(elm);
+ var result = mask.apply(elm.value, pos.end);
+ elm.value = result.value;
+ setCaret(elm, result.pos);
+ if(result.isComplete){
+ input.trigger("completed.mask");
+ }
+ }, 0);
+ }
+ input.data($.mask.dataName,mask);
+
+ if (!input.attr("readonly")){
+ input
+ .one("unmask", function() {
+ input
+ .off(".mask")
+ .removeData($.mask.dataName);
+ })
+ .on("focus.mask",focusEvent)
+ .on("blur.mask", blurEvent)
+ .on("keydown.mask", keydownEvent)
+ .on("keypress.mask", keypressEvent)
+ .on(pasteEventName, pasteEvent);
+ }
- caretTimeoutId = setTimeout(function(){
- writeBuffer();
- if (pos == mask.replace("?","").length) {
- input.caret(0, pos);
- } else {
- input.caret(pos);
- }
- }, 10);
- })
- .on("blur.mask", blurEvent)
- .on("keydown.mask", keydownEvent)
- .on("keypress.mask", keypressEvent)
- .on(pasteEventName, function() {
- setTimeout(function() {
- var pos=checkVal(true);
- input.caret(pos);
- if (settings.completed && pos == input.val().length)
- settings.completed.call(input);
- }, 0);
- });
- if (chrome && android) {
- input.on("keyup.mask", keypressEvent);
+ // if (chrome && android) {
+ // input.on("keyup.mask", keypressEvent);
+ // }
+
+ //Apply initital mask
+ if(elm.value.length){
+ var result=mask.apply(elm.value);
+ if(!settings.autoclear || result.isComplete){
+ elm.value = result.value;
+ }else{
+ elm.value="";
+ }
}
- checkVal(); //Perform initial check for existing values
- });
- }
-});
+ });
+ }
+ });
})(jQuery);
diff --git a/src/masks/FixedWidthMask.js b/src/masks/FixedWidthMask.js
new file mode 100644
index 0000000..e7ad0a1
--- /dev/null
+++ b/src/masks/FixedWidthMask.js
@@ -0,0 +1,157 @@
+(function(){
+ "use strict";
+ function FixedWidthMask (mask, settings){
+ var self=this;
+ //Build up structures necessary to quickly apply masking
+ this.settings = settings;
+
+ this.tests = [];
+ this.partialPosition = mask.length;
+ this.length = mask.length;
+
+ var firstNonMaskPos = null;
+
+ $.each(mask.split(""), function(i, c) {
+ if (c == '?') {
+ self.length--;
+ self.partialPosition = i;
+ } else if (settings.definitions[c]) {
+ self.tests.push(new RegExp(settings.definitions[c]));
+ if (firstNonMaskPos === null) {
+ firstNonMaskPos = self.tests.length - 1;
+ }
+ } else {
+ self.tests.push(c);
+ }
+ });
+ }
+
+ FixedWidthMask.prototype.applyBackspace = function(input, pos){
+ var i, buffer = input.split('');
+ for(i = pos - 1; i >= 0; i--){
+ if(this.tests[i].test){
+ break;
+ }
+ }
+ buffer.splice(i, 1);
+ var result= this.apply(buffer.join(''), i, true);
+ result.pos=i;
+ return result;
+ };
+
+ FixedWidthMask.prototype.applyDelete = function(input, pos){
+ var i, buffer = input.split('');
+ for(i = pos; i < buffer.length; i++){
+ if(this.tests[i].test){
+ break;
+ }
+ }
+ buffer.splice(i, 1);
+ var result=this.apply(buffer.join(''), i, true);
+ result.pos=i;
+ return result;
+ };
+
+ FixedWidthMask.prototype.apply = function(inputString, caretPosition, doShift){
+ if(caretPosition == null){
+ caretPosition = this.length;
+ }
+
+ var input=inputString.split(''),
+ buffer=[],
+ raw=[],
+ lastMatch = -1,
+ i,
+ action,
+ pos;
+
+ for (i = 0, pos = 0; i < this.length; i++) {
+ action=this.tests[i];
+
+ if (action.test) {
+ buffer.push(this.settings.placeholder);
+
+ while (pos++ < input.length) {
+ var c = input[pos - 1];
+ if (action.test(c)) {
+ buffer[i] = c;
+ raw.push(c);
+ lastMatch = i;
+ break;
+ }else if(doShift){
+ //TODO: The following is awful and needs to be refactored.
+ var tests;
+ /* jshint ignore:start */
+ tests=$.map(this.tests.slice(i + 1), function(test, offset){
+ var index = pos - 1 + offset;
+ if(test.test && input[index] != null){
+ return {regex:test,char:input[index]};
+ }
+ });
+ /* jshint ignore:end */
+
+ var newInput = [];
+ var canShift = tests.length > 0;
+
+ if(tests.length){
+ tests.unshift({regex: action});
+ for(var j = 1; j < tests.length; j++){
+ if(!tests[j-1].regex.test(tests[j].char)){
+ canShift = false;
+ break;
+ }
+ newInput.push(tests[j].char);
+ }
+ }
+
+ if(canShift){
+ //Everything to the right can shift left and still match.
+ input = newInput;
+ buffer[i] = input[0];
+ pos = 1;
+ }else{
+ //Retry current char at next position leaving a blank.
+ pos--;
+ }
+ //Only allow shift attempt to happen once.
+ doShift = false;
+ break;
+ }
+ }
+ } else {
+ buffer.push(action);
+ if(action === input[pos] && i !== this.partialPosition) {
+ pos++;
+ }
+ }
+ }
+
+ //Find the next spot waiting for input
+ var maxCaret=Math.min(caretPosition,this.length);
+ for(i=Math.min(lastMatch+1,maxCaret);i