浏览代码

Merge branch '2.x' into dev

Robin Herbots 12 年之前
父节点
当前提交
0f7768d8f4

+ 37 - 2
README.md

@@ -55,6 +55,15 @@ $(document).ready(function(){
 });
 ```
 
+#### Default masking definitions
+
+  - 9 : numeric
+  - a : alfabetic
+  - * : alfanumeric 
+
+There are more definitions defined within the extensions.  
+You can find info within the js-files or by further exploring the options.
+
 ## Options:
 
 ### change the placeholder
@@ -307,6 +316,16 @@ While the field has focus and is blank, users will see the full mask `___-___`.
 When the required part of the mask is filled and the field loses focus, the user will see `123`.
 When both the required and optional parts of the mask are filled out and the field loses focus, the user will see `123-ABC`.
 
+#### Optional masks with greedy false
+
+When defining an optional mask together with the greedy: false option, the inputmask will show the smallest possible mask as input first.
+
+```javascript
+$(selector).inputmask({ mask: "99999[-9999]", greedy: false });
+```
+
+The initial mask shown will be "_____" instead of "_____-____". 
+
 ### Multiple masks
 
 You can define multiple mask for your input.  Depending on the input the masking will switch between the defined masks.  
@@ -349,8 +368,24 @@ $(document).ready(function(){
 
 ### auto upper/lower- casing inputmask
 
-see jquery.inputmask.extensions.js for an example how to define "auto"-casing in a definition (definition A)
-casing can be null, "upper" or "lower"
+You can define whitin a definition to automatically lowercase or uppercase the entry in an input by giving the casing.  
+Casing can be null, "upper" or "lower"
+```javascript
+    $.extend($.inputmask.defaults.definitions, {
+        'A': { 
+            validator: "[A-Za-z]",
+            cardinality: 1,
+            casing: "upper" //auto uppercasing
+        },
+        '#': {
+            validator: "[A-Za-z\u0410-\u044F\u0401\u04510-9]",
+            cardinality: 1,
+            casing: "upper"
+        }
+    });`
+```
+
+Include jquery.inputmask.extensions.js for using the A and # definitions.
 
 ```javascript
 $(document).ready(function(){

+ 2 - 2
build.properties

@@ -6,8 +6,8 @@ srcdir = js
 distdir = dist
 
 build.major = 2
-build.minor = 2
-build.revision = 64
+build.minor = 3
+build.revision = 4
 
 target = jquery.inputmask.bundle.js
 target.min = jquery.inputmask.bundle.min.js

+ 1 - 1
component.json

@@ -1,6 +1,6 @@
 {
     "name": "jquery.inputmask",
-    "version": "2.2.64",
+    "version": "2.3.4",
     "main": "./dist/jquery.inputmask.bundle.js",
     "dependencies": {
         "jquery": ">=1.5"

二进制
dist/jQuery.InputMask.2.2.63.nupkg


二进制
dist/jQuery.InputMask.2.3.4.nupkg


+ 56 - 31
dist/jquery.inputmask.bundle.js

@@ -3,7 +3,7 @@
 * http://github.com/RobinHerbots/jquery.inputmask
 * Copyright (c) 2010 - 2013 Robin Herbots
 * Licensed under the MIT license (http://www.opensource.org/licenses/mit-license.php)
-* Version: 2.2.64
+* Version: 2.3.4
 */
 
 (function ($) {
@@ -21,7 +21,7 @@
                 oncomplete: $.noop, //executes when the mask is complete
                 onincomplete: $.noop, //executes when the mask is incomplete and focus is lost
                 oncleared: $.noop, //executes when the mask is cleared
-                repeat: "*", //repetitions of the mask: * ~ forever, otherwise specify an integer
+                repeat: 0, //repetitions of the mask: * ~ forever, otherwise specify an integer
                 greedy: true, //true: allocated buffer for the mask and repetitions - false: allocate only if needed
                 autoUnmask: false, //automatically unmask when retrieving the value with $.fn.val or value if the browser supports __lookupGetter__ or getOwnPropertyDescriptor
                 clearMaskOnLostFocus: true,
@@ -63,12 +63,12 @@
                 ignorables: [9, 13, 19, 27, 33, 34, 35, 36, 37, 38, 39, 40, 45, 46, 93, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123],
                 getMaskLength: function (buffer, greedy, repeat, currentBuffer, opts) {
                     var calculatedLength = buffer.length;
-                    if (!greedy) { 
-                     	if(repeat == "*") {
-                     		calculatedLength = currentBuffer.length + 1;
-                     	} else if(repeat > 1) {
-                        	calculatedLength += (buffer.length * (repeat - 1));
-                    	}
+                    if (!greedy) {
+                        if (repeat == "*") {
+                            calculatedLength = currentBuffer.length + 1;
+                        } else if (repeat > 1) {
+                            calculatedLength += (buffer.length * (repeat - 1));
+                        }
                     }
                     return calculatedLength;
                 }
@@ -232,7 +232,7 @@
             }
             function getMaskTemplate(mask) {
                 var escaped = false, outCount = 0, greedy = opts.greedy, repeat = opts.repeat;
-                if(repeat == "*") greedy = false;
+                if (repeat == "*") greedy = false;
                 if (mask.length == 1 && greedy == false) { opts.placeholder = ""; } //hide placeholder with single non-greedy mask
                 var singleMask = $.map(mask.split(""), function (element, index) {
                     var outElem = [];
@@ -404,7 +404,7 @@
                     });
                 } else generateMask("", opts.mask.toString());
 
-                return ms;
+                return opts.greedy ? ms : ms.sort(function (a, b) { return a["mask"].length - b["mask"].length; });
             }
             function getPlaceHolder(pos) {
                 return opts.placeholder.charAt(pos % opts.placeholder.length);
@@ -465,8 +465,12 @@
                                 results.push({ "activeMasksetIndex": index, "result": { "refresh": true, c: activeMaskset['_buffer'][maskPos] } }); //new command hack only rewrite buffer
                                 activeMaskset['lastValidPosition'] = maskPos;
                                 return false;
-                            } else activeMaskset['lastValidPosition'] = isRTL ? getMaskLength() + 1 : -1; //mark mask as validated and invalid
-                            //maskPos = isRTL ? seekPrevious(pos) : seekNext(pos);
+                            } else {
+                                if (masksets[currentActiveMasksetIndex]["lastValidPosition"] >= maskPos)
+                                    activeMaskset['lastValidPosition'] = isRTL ? getMaskLength() + 1 : -1; //mark mask as validated and invalid
+                                else maskPos = isRTL ? seekPrevious(pos) : seekNext(pos);
+                            }
+
                         }
                         if ((activeMaskset['lastValidPosition'] == undefined
                                 && maskPos == (isRTL ? seekPrevious(getMaskLength()) : seekNext(-1))
@@ -646,10 +650,16 @@
 
                     var ml = getMaskLength();
                     $.each(inputValue, function (ndx, charCode) {
-                        var index = isRTL ? (opts.numericInput ? ml : ml - ndx) : ndx;
+                        var index = isRTL ? (opts.numericInput ? ml : ml - ndx) : ndx,
+                            lvp = getActiveMaskSet()["lastValidPosition"],
+                            pos = getActiveMaskSet()["p"];
+
+                        pos = lvp == undefined ? index : pos;
+                        lvp = lvp == undefined ? -1 : lvp;
+
                         if ((strict && isMask(isRTL ? index - 1 : index)) ||
-                            (charCode != getBufferElement(getActiveBufferTemplate().slice(), isRTL ? index - 1 : index, true) &&
-                             $.inArray(charCode, getActiveBufferTemplate().slice(getActiveMaskSet()["lastValidPosition"] + 1, getActiveMaskSet()["p"])) == -1)
+                            ((charCode != getBufferElement(getActiveBufferTemplate().slice(), isRTL ? index - 1 : index, true) || isMask(isRTL ? index - 1 : index)) &&
+                             $.inArray(charCode, getActiveBufferTemplate().slice(lvp + 1, pos)) == -1)
                             ) {
                             $(input).trigger("keypress", [true, charCode.charCodeAt(0), writeOut, strict, index, isRTL]);
                         }
@@ -820,7 +830,7 @@
                     $input.removeClass('focus.inputmask');
                     //bind events
                     $input.closest('form').bind("submit", function () { //trigger change on submit if any
-                        if ($input[0]._valueGet() != getActiveMaskSet()["undoBuffer"]) {
+                        if ($input[0]._valueGet && $input[0]._valueGet() != getActiveMaskSet()["undoBuffer"]) {
                             $input.change();
                         }
                     });
@@ -870,6 +880,7 @@
                         }
                         $input.addClass('focus.inputmask');
                         getActiveMaskSet()["undoBuffer"] = input._valueGet();
+                        $input.click();
                     }).bind("mouseleave.inputmask", function () {
                         var $input = $(this), input = this;
                         if (opts.clearMaskOnLostFocus) {
@@ -889,7 +900,6 @@
                                 var clickPosition = selectedCaret.begin,
                                     lvp = getActiveMaskSet()["lastValidPosition"],
                                     lastPosition;
-
                                 determineInputDirection(input, selectedCaret);
                                 if (isRTL) {
                                     if (opts.numericInput) {
@@ -951,6 +961,8 @@
                         } else {
                             clearOptionalTail(el);
                         }
+                    } else {
+                        writeBuffer(el, getActiveBuffer());
                     }
 
                     installEventRuler(el);
@@ -1272,8 +1284,9 @@
                                 }, 0);
                             }
                         }
-
+                        var caretPos = caret(input);
                         opts.onKeyDown.call(this, e, getActiveBuffer(), opts); //extra stuff to execute on keydown
+                        caret(input, caretPos.begin, caretPos.end);
                         ignorable = $.inArray(k, opts.ignorables) != -1;
                     }
 
@@ -1309,9 +1322,9 @@
                                 }
 
                                 //should we clear a possible selection??
-                                var isSelection = (pos.end - pos.begin) > 1 || ((pos.end - pos.begin) == 1 && opts.insertMode);
+                                var isSelection = (pos.end - pos.begin) > 1 || ((pos.end - pos.begin) == 1 && opts.insertMode), redetermineLVP = false;
                                 if (isSelection) {
-                                    var initialIndex = activeMasksetIndex, redetermineLVP = false;
+                                    var initialIndex = activeMasksetIndex;
                                     $.each(masksets, function (ndx, lmnt) {
                                         activeMasksetIndex = ndx;
                                         getActiveMaskSet()["undoBuffer"] = getActiveBuffer().join(''); //init undobuffer for recovery when not valid
@@ -1327,7 +1340,7 @@
                                             }
                                         }
                                         if (getActiveMaskSet()["lastValidPosition"] > pos.begin && getActiveMaskSet()["lastValidPosition"] < posend) {
-                                            getActiveMaskSet()["lastValidPosition"] = isRTL ? posend : pos.begin;
+                                            getActiveMaskSet()["lastValidPosition"] = isRTL ? seekNext(posend) : seekPrevious(pos.begin);
                                         } else {
                                             redetermineLVP = true;
                                         }
@@ -1378,6 +1391,11 @@
                                                             maskL = buffer.length;
                                                         }
                                                         shiftL(firstUnmaskedPosition, p, c);
+                                                        //shift the lvp if needed
+                                                        var lvp = getActiveMaskSet()["lastValidPosition"], plvp = seekPrevious(lvp);
+                                                        if (lvp <= p && (getBufferElement(getActiveBuffer(), plvp) != getPlaceHolder(plvp))) {
+                                                            getActiveMaskSet()["lastValidPosition"] = plvp;
+                                                        }
                                                     } else getActiveMaskSet()["writeOutBuffer"] = false;
                                                 } else setBufferElement(buffer, p, c, true, isRTL);
                                             }
@@ -1406,9 +1424,14 @@
                                                     while (getBufferElement(bfrClone, lastUnmaskedPosition, true) != getPlaceHolder(lastUnmaskedPosition) && lastUnmaskedPosition >= p) {
                                                         lastUnmaskedPosition = lastUnmaskedPosition == 0 ? -1 : seekPrevious(lastUnmaskedPosition);
                                                     }
-                                                    if (lastUnmaskedPosition >= p)
+                                                    if (lastUnmaskedPosition >= p) {
                                                         shiftR(p, buffer.length, c);
-                                                    else getActiveMaskSet()["writeOutBuffer"] = false;
+                                                        //shift the lvp if needed
+                                                        var lvp = getActiveMaskSet()["lastValidPosition"], nlvp = seekNext(lvp);
+                                                        if (nlvp != getMaskLength() && lvp >= p && (getBufferElement(getActiveBuffer(), nlvp) != getPlaceHolder(nlvp))) {
+                                                            getActiveMaskSet()["lastValidPosition"] = nlvp;
+                                                        }
+                                                    } else getActiveMaskSet()["writeOutBuffer"] = false;
                                                 } else setBufferElement(buffer, p, c, true, isRTL);
                                             }
                                             getActiveMaskSet()["p"] = seekNext(p);
@@ -1429,7 +1452,7 @@
                                         setTimeout(function () { opts.onKeyValidation.call(self, result["result"], opts); }, 0);
                                         if (getActiveMaskSet()["writeOutBuffer"] && result["result"] !== false) {
                                             var buffer = getActiveBuffer();
-                                            writeBuffer(input, buffer, checkval ? undefined : (opts.numericInput ? seekNext(getActiveMaskSet()["p"]) : getActiveMaskSet()["p"]));
+                                            writeBuffer(input, buffer, checkval ? undefined : ((opts.numericInput && isRTL) ? seekNext(getActiveMaskSet()["p"]) : getActiveMaskSet()["p"]));
                                             setTimeout(function () { //timeout needed for IE
                                                 if (isComplete(buffer))
                                                     $input.trigger("complete");
@@ -1450,7 +1473,9 @@
 
                     function keyupEvent(e) {
                         var $input = $(this), input = this, k = e.keyCode, buffer = getActiveBuffer();
+                        var caretPos = caret(input);
                         opts.onKeyUp.call(this, e, buffer, opts); //extra stuff to execute on keyup
+                        caret(input, caretPos.begin, caretPos.end);
                         if (k == opts.keyCode.TAB && $input.hasClass('focus.inputmask') && input._valueGet().length == 0 && opts.showMaskOnFocus) {
                             buffer = getActiveBufferTemplate().slice();
                             writeBuffer(input, buffer);
@@ -1470,17 +1495,17 @@ Input Mask plugin extensions
 http://github.com/RobinHerbots/jquery.inputmask
 Copyright (c) 2010 - 2013 Robin Herbots
 Licensed under the MIT license (http://www.opensource.org/licenses/mit-license.php)
-Version: 2.2.64
+Version: 2.3.4
 
 Optional extensions on the jquery.inputmask base
 */
 (function ($) {
     //extra definitions
     $.extend($.inputmask.defaults.definitions, {
-        'A': { //auto uppercasing
+        'A': { 
             validator: "[A-Za-z]",
             cardinality: 1,
-            casing: "upper"
+            casing: "upper" //auto uppercasing
         },
         '#': {
             validator: "[A-Za-z\u0410-\u044F\u0401\u04510-9]",
@@ -1572,7 +1597,7 @@ Input Mask plugin extensions
 http://github.com/RobinHerbots/jquery.inputmask
 Copyright (c) 2010 - 2012 Robin Herbots
 Licensed under the MIT license (http://www.opensource.org/licenses/mit-license.php)
-Version: 2.2.64
+Version: 2.3.4
 
 Optional extensions on the jquery.inputmask base
 */
@@ -2041,7 +2066,7 @@ Input Mask plugin extensions
 http://github.com/RobinHerbots/jquery.inputmask
 Copyright (c) 2010 - 2013 Robin Herbots
 Licensed under the MIT license (http://www.opensource.org/licenses/mit-license.php)
-Version: 2.2.64
+Version: 2.3.4
 
 Optional extensions on the jquery.inputmask base
 */
@@ -2208,7 +2233,7 @@ Input Mask plugin extensions
 http://github.com/RobinHerbots/jquery.inputmask
 Copyright (c) 2010 - 2013 Robin Herbots
 Licensed under the MIT license (http://www.opensource.org/licenses/mit-license.php)
-Version: 2.2.64
+Version: 2.3.4
 
 Regex extensions on the jquery.inputmask base
 Allows for using regular expressions as a mask
@@ -2218,7 +2243,7 @@ Allows for using regular expressions as a mask
         'Regex': {
             mask: "r",
             greedy: false,
-            repeat: 10, //needs to be computed
+            repeat: "*",
             regex: null,
             regexSplit: null,
             definitions: {

文件差异内容过多而无法显示
+ 54 - 53
dist/jquery.inputmask.bundle.min.js


文件差异内容过多而无法显示
+ 46 - 45
dist/min/jquery.inputmask.js


+ 1 - 1
dist/min/jquery.inputmask.regex.extensions.js

@@ -1 +1 @@
-(function(b){b.extend(b.inputmask.defaults.aliases,{Regex:{mask:"r",greedy:!1,repeat:10,regex:null,regexSplit:null,definitions:{r:{validator:function(f,a,c,d,e){null==e.regexSplit&&(e.regexSplit=e.regex.match(RegExp("\\[.*?]\\*","g")));var b=a.slice(),a="",d=!1;b.splice(c,0,f);f=b.join("");for(c=0;c<e.regexSplit.length&&!(a+=e.regexSplit[c],d=RegExp("^"+a+"$").test(f),console.log(f+" "+d+" "+a),d);c++);return d},cardinality:1}}}})})(jQuery);
+(function(b){b.extend(b.inputmask.defaults.aliases,{Regex:{mask:"r",greedy:!1,repeat:"*",regex:null,regexSplit:null,definitions:{r:{validator:function(f,a,c,d,e){null==e.regexSplit&&(e.regexSplit=e.regex.match(RegExp("\\[.*?]\\*","g")));var b=a.slice(),a="",d=!1;b.splice(c,0,f);f=b.join("");for(c=0;c<e.regexSplit.length&&!(a+=e.regexSplit[c],d=RegExp("^"+a+"$").test(f),console.log(f+" "+d+" "+a),d);c++);return d},cardinality:1}}}})})(jQuery);

+ 1 - 1
jquery.inputmask.jquery.json

@@ -8,7 +8,7 @@
 		"inputmask",
 		"mask"
     ],
-    "version": "2.2.64",
+    "version": "2.3.4",
     "author": {
         "name": "Robin Herbots",
         "url": "http://github.com/RobinHerbots/jquery.inputmask"

+ 2 - 2
js/jquery.inputmask.extensions.js

@@ -10,10 +10,10 @@ Optional extensions on the jquery.inputmask base
 (function ($) {
     //extra definitions
     $.extend($.inputmask.defaults.definitions, {
-        'A': { //auto uppercasing
+        'A': { 
             validator: "[A-Za-z]",
             cardinality: 1,
-            casing: "upper"
+            casing: "upper" //auto uppercasing
         },
         '#': {
             validator: "[A-Za-z\u0410-\u044F\u0401\u04510-9]",

+ 48 - 23
js/jquery.inputmask.js

@@ -21,7 +21,7 @@
                 oncomplete: $.noop, //executes when the mask is complete
                 onincomplete: $.noop, //executes when the mask is incomplete and focus is lost
                 oncleared: $.noop, //executes when the mask is cleared
-                repeat: "*", //repetitions of the mask: * ~ forever, otherwise specify an integer
+                repeat: 0, //repetitions of the mask: * ~ forever, otherwise specify an integer
                 greedy: true, //true: allocated buffer for the mask and repetitions - false: allocate only if needed
                 autoUnmask: false, //automatically unmask when retrieving the value with $.fn.val or value if the browser supports __lookupGetter__ or getOwnPropertyDescriptor
                 clearMaskOnLostFocus: true,
@@ -63,12 +63,12 @@
                 ignorables: [9, 13, 19, 27, 33, 34, 35, 36, 37, 38, 39, 40, 45, 46, 93, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123],
                 getMaskLength: function (buffer, greedy, repeat, currentBuffer, opts) {
                     var calculatedLength = buffer.length;
-                    if (!greedy) { 
-                     	if(repeat == "*") {
-                     		calculatedLength = currentBuffer.length + 1;
-                     	} else if(repeat > 1) {
-                        	calculatedLength += (buffer.length * (repeat - 1));
-                    	}
+                    if (!greedy) {
+                        if (repeat == "*") {
+                            calculatedLength = currentBuffer.length + 1;
+                        } else if (repeat > 1) {
+                            calculatedLength += (buffer.length * (repeat - 1));
+                        }
                     }
                     return calculatedLength;
                 }
@@ -232,7 +232,7 @@
             }
             function getMaskTemplate(mask) {
                 var escaped = false, outCount = 0, greedy = opts.greedy, repeat = opts.repeat;
-                if(repeat == "*") greedy = false;
+                if (repeat == "*") greedy = false;
                 if (mask.length == 1 && greedy == false) { opts.placeholder = ""; } //hide placeholder with single non-greedy mask
                 var singleMask = $.map(mask.split(""), function (element, index) {
                     var outElem = [];
@@ -404,7 +404,7 @@
                     });
                 } else generateMask("", opts.mask.toString());
 
-                return ms;
+                return opts.greedy ? ms : ms.sort(function (a, b) { return a["mask"].length - b["mask"].length; });
             }
             function getPlaceHolder(pos) {
                 return opts.placeholder.charAt(pos % opts.placeholder.length);
@@ -465,8 +465,12 @@
                                 results.push({ "activeMasksetIndex": index, "result": { "refresh": true, c: activeMaskset['_buffer'][maskPos] } }); //new command hack only rewrite buffer
                                 activeMaskset['lastValidPosition'] = maskPos;
                                 return false;
-                            } else activeMaskset['lastValidPosition'] = isRTL ? getMaskLength() + 1 : -1; //mark mask as validated and invalid
-                            //maskPos = isRTL ? seekPrevious(pos) : seekNext(pos);
+                            } else {
+                                if (masksets[currentActiveMasksetIndex]["lastValidPosition"] >= maskPos)
+                                    activeMaskset['lastValidPosition'] = isRTL ? getMaskLength() + 1 : -1; //mark mask as validated and invalid
+                                else maskPos = isRTL ? seekPrevious(pos) : seekNext(pos);
+                            }
+
                         }
                         if ((activeMaskset['lastValidPosition'] == undefined
                                 && maskPos == (isRTL ? seekPrevious(getMaskLength()) : seekNext(-1))
@@ -646,10 +650,16 @@
 
                     var ml = getMaskLength();
                     $.each(inputValue, function (ndx, charCode) {
-                        var index = isRTL ? (opts.numericInput ? ml : ml - ndx) : ndx;
+                        var index = isRTL ? (opts.numericInput ? ml : ml - ndx) : ndx,
+                            lvp = getActiveMaskSet()["lastValidPosition"],
+                            pos = getActiveMaskSet()["p"];
+
+                        pos = lvp == undefined ? index : pos;
+                        lvp = lvp == undefined ? -1 : lvp;
+
                         if ((strict && isMask(isRTL ? index - 1 : index)) ||
-                            (charCode != getBufferElement(getActiveBufferTemplate().slice(), isRTL ? index - 1 : index, true) &&
-                             $.inArray(charCode, getActiveBufferTemplate().slice(getActiveMaskSet()["lastValidPosition"] + 1, getActiveMaskSet()["p"])) == -1)
+                            ((charCode != getBufferElement(getActiveBufferTemplate().slice(), isRTL ? index - 1 : index, true) || isMask(isRTL ? index - 1 : index)) &&
+                             $.inArray(charCode, getActiveBufferTemplate().slice(lvp + 1, pos)) == -1)
                             ) {
                             $(input).trigger("keypress", [true, charCode.charCodeAt(0), writeOut, strict, index, isRTL]);
                         }
@@ -820,7 +830,7 @@
                     $input.removeClass('focus.inputmask');
                     //bind events
                     $input.closest('form').bind("submit", function () { //trigger change on submit if any
-                        if ($input[0]._valueGet() != getActiveMaskSet()["undoBuffer"]) {
+                        if ($input[0]._valueGet && $input[0]._valueGet() != getActiveMaskSet()["undoBuffer"]) {
                             $input.change();
                         }
                     });
@@ -870,6 +880,7 @@
                         }
                         $input.addClass('focus.inputmask');
                         getActiveMaskSet()["undoBuffer"] = input._valueGet();
+                        $input.click();
                     }).bind("mouseleave.inputmask", function () {
                         var $input = $(this), input = this;
                         if (opts.clearMaskOnLostFocus) {
@@ -889,7 +900,6 @@
                                 var clickPosition = selectedCaret.begin,
                                     lvp = getActiveMaskSet()["lastValidPosition"],
                                     lastPosition;
-
                                 determineInputDirection(input, selectedCaret);
                                 if (isRTL) {
                                     if (opts.numericInput) {
@@ -951,6 +961,8 @@
                         } else {
                             clearOptionalTail(el);
                         }
+                    } else {
+                        writeBuffer(el, getActiveBuffer());
                     }
 
                     installEventRuler(el);
@@ -1272,8 +1284,9 @@
                                 }, 0);
                             }
                         }
-
+                        var caretPos = caret(input);
                         opts.onKeyDown.call(this, e, getActiveBuffer(), opts); //extra stuff to execute on keydown
+                        caret(input, caretPos.begin, caretPos.end);
                         ignorable = $.inArray(k, opts.ignorables) != -1;
                     }
 
@@ -1309,9 +1322,9 @@
                                 }
 
                                 //should we clear a possible selection??
-                                var isSelection = (pos.end - pos.begin) > 1 || ((pos.end - pos.begin) == 1 && opts.insertMode);
+                                var isSelection = (pos.end - pos.begin) > 1 || ((pos.end - pos.begin) == 1 && opts.insertMode), redetermineLVP = false;
                                 if (isSelection) {
-                                    var initialIndex = activeMasksetIndex, redetermineLVP = false;
+                                    var initialIndex = activeMasksetIndex;
                                     $.each(masksets, function (ndx, lmnt) {
                                         activeMasksetIndex = ndx;
                                         getActiveMaskSet()["undoBuffer"] = getActiveBuffer().join(''); //init undobuffer for recovery when not valid
@@ -1327,7 +1340,7 @@
                                             }
                                         }
                                         if (getActiveMaskSet()["lastValidPosition"] > pos.begin && getActiveMaskSet()["lastValidPosition"] < posend) {
-                                            getActiveMaskSet()["lastValidPosition"] = isRTL ? posend : pos.begin;
+                                            getActiveMaskSet()["lastValidPosition"] = isRTL ? seekNext(posend) : seekPrevious(pos.begin);
                                         } else {
                                             redetermineLVP = true;
                                         }
@@ -1378,6 +1391,11 @@
                                                             maskL = buffer.length;
                                                         }
                                                         shiftL(firstUnmaskedPosition, p, c);
+                                                        //shift the lvp if needed
+                                                        var lvp = getActiveMaskSet()["lastValidPosition"], plvp = seekPrevious(lvp);
+                                                        if (lvp <= p && (getBufferElement(getActiveBuffer(), plvp) != getPlaceHolder(plvp))) {
+                                                            getActiveMaskSet()["lastValidPosition"] = plvp;
+                                                        }
                                                     } else getActiveMaskSet()["writeOutBuffer"] = false;
                                                 } else setBufferElement(buffer, p, c, true, isRTL);
                                             }
@@ -1406,9 +1424,14 @@
                                                     while (getBufferElement(bfrClone, lastUnmaskedPosition, true) != getPlaceHolder(lastUnmaskedPosition) && lastUnmaskedPosition >= p) {
                                                         lastUnmaskedPosition = lastUnmaskedPosition == 0 ? -1 : seekPrevious(lastUnmaskedPosition);
                                                     }
-                                                    if (lastUnmaskedPosition >= p)
+                                                    if (lastUnmaskedPosition >= p) {
                                                         shiftR(p, buffer.length, c);
-                                                    else getActiveMaskSet()["writeOutBuffer"] = false;
+                                                        //shift the lvp if needed
+                                                        var lvp = getActiveMaskSet()["lastValidPosition"], nlvp = seekNext(lvp);
+                                                        if (nlvp != getMaskLength() && lvp >= p && (getBufferElement(getActiveBuffer(), nlvp) != getPlaceHolder(nlvp))) {
+                                                            getActiveMaskSet()["lastValidPosition"] = nlvp;
+                                                        }
+                                                    } else getActiveMaskSet()["writeOutBuffer"] = false;
                                                 } else setBufferElement(buffer, p, c, true, isRTL);
                                             }
                                             getActiveMaskSet()["p"] = seekNext(p);
@@ -1429,7 +1452,7 @@
                                         setTimeout(function () { opts.onKeyValidation.call(self, result["result"], opts); }, 0);
                                         if (getActiveMaskSet()["writeOutBuffer"] && result["result"] !== false) {
                                             var buffer = getActiveBuffer();
-                                            writeBuffer(input, buffer, checkval ? undefined : (opts.numericInput ? seekNext(getActiveMaskSet()["p"]) : getActiveMaskSet()["p"]));
+                                            writeBuffer(input, buffer, checkval ? undefined : ((opts.numericInput && isRTL) ? seekNext(getActiveMaskSet()["p"]) : getActiveMaskSet()["p"]));
                                             setTimeout(function () { //timeout needed for IE
                                                 if (isComplete(buffer))
                                                     $input.trigger("complete");
@@ -1450,7 +1473,9 @@
 
                     function keyupEvent(e) {
                         var $input = $(this), input = this, k = e.keyCode, buffer = getActiveBuffer();
+                        var caretPos = caret(input);
                         opts.onKeyUp.call(this, e, buffer, opts); //extra stuff to execute on keyup
+                        caret(input, caretPos.begin, caretPos.end);
                         if (k == opts.keyCode.TAB && $input.hasClass('focus.inputmask') && input._valueGet().length == 0 && opts.showMaskOnFocus) {
                             buffer = getActiveBufferTemplate().slice();
                             writeBuffer(input, buffer);

+ 16 - 0
qunit/qunit.html

@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>jquery.inputmask - QUnit</title>
+  <link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-1.12.0.css">
+</head>
+<body>
+  <div id="qunit"></div>
+  <div id="qunit-fixture"></div>
+  <script src="http://code.jquery.com/jquery-1.10.2.min.js"></script>
+  <script src="http://code.jquery.com/qunit/qunit-1.12.0.js"></script>
+  <script src="../dist/jquery.inputmask.bundle.js"></script>
+  <script src="./tests.js"></script>
+</body>
+</html>

+ 821 - 0
qunit/tests.js

@@ -0,0 +1,821 @@
+var keyCodes = {
+    ALT: 18, BACKSPACE: 8, CAPS_LOCK: 20, COMMA: 188, COMMAND: 91, COMMAND_LEFT: 91, COMMAND_RIGHT: 93, CONTROL: 17, DELETE: 46, DOWN: 40, END: 35, ENTER: 13, ESCAPE: 27, HOME: 36, INSERT: 45, LEFT: 37, MENU: 93, NUMPAD_ADD: 107, NUMPAD_DECIMAL: 110, NUMPAD_DIVIDE: 111, NUMPAD_ENTER: 108,
+    NUMPAD_MULTIPLY: 106, NUMPAD_SUBTRACT: 109, PAGE_DOWN: 34, PAGE_UP: 33, PERIOD: 190, RIGHT: 39, SHIFT: 16, SPACE: 32, TAB: 9, UP: 38, WINDOWS: 91
+}
+
+$.fn.SendKey = function (keyCode, modifier) {
+    var sendDummyKeydown = false;
+    if (Object.prototype.toString.call(keyCode) == '[object String]') {
+        keyCode = keyCode.charCodeAt(0);
+        sendDummyKeydown = true;
+    }
+
+    function caret(input, begin, end) {
+        var npt = input.jquery && input.length > 0 ? input[0] : input, range;
+        if (typeof begin == 'number') {
+            if (!$(input).is(':visible')) {
+                return;
+            }
+            end = (typeof end == 'number') ? end : begin;
+            if (npt.setSelectionRange) {
+                npt.selectionStart = begin;
+                npt.selectionEnd = end;
+
+            } else if (npt.createTextRange) {
+                range = npt.createTextRange();
+                range.collapse(true);
+                range.moveEnd('character', end);
+                range.moveStart('character', begin);
+                range.select();
+            }
+        } else {
+            if (!$(input).is(':visible')) {
+                return { "begin": 0, "end": 0 };
+            }
+            if (npt.setSelectionRange) {
+                begin = npt.selectionStart;
+                end = npt.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 };
+        }
+    };
+
+    switch (keyCode) {
+        case keyCodes.LEFT: {
+            if (modifier == undefined) {
+                var pos = caret(this);
+                caret(this, pos.begin - 1);
+                break;
+            }
+        }
+        case keyCodes.RIGHT: {
+            if (modifier == undefined) {
+                var pos = caret(this);
+                caret(this, pos.begin + 1);
+                break;
+            }
+        }
+        default: {
+            var keydown = $.Event("keydown"),
+                keypress = $.Event("keypress"),
+                keyup = $.Event("keyup");
+
+            if (!sendDummyKeydown) {
+                keydown.keyCode = keyCode;
+                if (modifier == keyCodes.CONTROL)
+                    keydown.ctrlKey = true;
+            }
+            $(this).trigger(keydown);
+            if (!keydown.isDefaultPrevented()) {
+                keypress.keyCode = keyCode;
+                if (modifier == keyCodes.CONTROL)
+                    keypress.ctrlKey = true;
+                $(this).trigger(keypress);
+                if (!keypress.isDefaultPrevented()) {
+                    keyup.keyCode = keyCode;
+                    if (modifier == keyCodes.CONTROL)
+                        keyup.ctrlKey = true;
+                    $(this).trigger(keyup);
+                }
+            }
+        }
+    }
+}
+$.fn.Type = function (inputStr) {
+    var $input = $(this);
+    $.each(inputStr.split(''), function (ndx, lmnt) {
+        $input.SendKey(lmnt);
+    });
+}
+
+module("Simple masking");
+
+test("inputmask(\"99-99-99\", { clearMaskOnLostFocus: false}", function () {
+    $('body').append('<input type="text" id="testmask" />');
+    $("#testmask").inputmask("99-99-99", { clearMaskOnLostFocus: false });
+
+    equal(document.getElementById("testmask").value, "__-__-__", "Result " + document.getElementById("testmask").value);
+
+    $("#testmask").remove();
+});
+
+test("inputmask(\"99-99-99\", { clearMaskOnLostFocus: true}", function () {
+    $('body').append('<input type="text" id="testmask" />');
+    $("#testmask").inputmask("99-99-99", { clearMaskOnLostFocus: true });
+
+    equal(document.getElementById("testmask").value, "", "Result " + document.getElementById("testmask").value);
+
+    $("#testmask").remove();
+});
+
+test("inputmask(\"999.999.999\")", function () {
+    $('body').append('<input type="text" id="testmask" />');
+    $("#testmask").inputmask("999.999.999");
+
+    $("#testmask")[0].focus();
+
+    $("#testmask").SendKey(49);
+    $("#testmask").SendKey(50);
+    $("#testmask").SendKey(51);
+
+    equal($("#testmask").val(), "123.___.___", "Result " + $("#testmask").val());
+
+    $("#testmask").remove();
+});
+
+asyncTest("inputmask(\"999.999.999\", { oncomplete: ... })", 1, function () {
+    $('body').append('<input type="text" id="testmask" />');
+    $("#testmask").inputmask("999.999.999", {
+        oncomplete: function () {
+            equal($("#testmask").val(), "123.456.789", "Result " + $("#testmask").val());
+            start();
+            $("#testmask").remove();
+        }
+    });
+
+    $("#testmask")[0].focus();
+    $("#testmask").SendKey(49);
+    $("#testmask").SendKey(50);
+    $("#testmask").SendKey(51);
+    $("#testmask").SendKey(52);
+    $("#testmask").SendKey(53);
+    $("#testmask").SendKey(54);
+    $("#testmask").SendKey(55);
+    $("#testmask").SendKey(56);
+    $("#testmask").SendKey(57);
+});
+
+asyncTest("inputmask(\"9-AAA.999\") - change event", 1, function () {
+    $('body').append('<input type="text" id="testmask" />');
+    $("#testmask").inputmask("9-AAA.999").change(function () {
+        ok(true, "Change triggered");
+        setTimeout(function () {
+            $("#testmask").remove();
+            start();
+        });
+    });
+
+    $("#testmask")[0].focus();
+    $("#testmask").SendKey(49);
+    $("#testmask").SendKey(65);
+    $("#testmask").SendKey(66);
+    $("#testmask").SendKey(67);
+    $("#testmask").SendKey(50);
+    $("#testmask").SendKey(51);
+
+    $("#testmask").blur();
+});
+
+asyncTest("inputmask(\"9-AAA.999\", { onincomplete: ... })", 1, function () {
+    $('body').append('<input type="text" id="testmask" />');
+    $("#testmask").inputmask("9-AAA.999", {
+        onincomplete: function () {
+            equal($("#testmask").val(), "1-ABC.12_", "Result " + $("#testmask").val());
+            start();
+            $("#testmask").remove();
+        }
+    });
+
+    $("#testmask")[0].focus();
+    $("#testmask").SendKey(49);
+    $("#testmask").SendKey(65);
+    $("#testmask").SendKey(66);
+    $("#testmask").SendKey(67);
+    $("#testmask").SendKey(49);
+    $("#testmask").SendKey(50);
+
+    $("#testmask").blur();
+});
+
+test("inputmask(\"999.999.999\") - delete 2nd with backspace, continue the mask", function () {
+    $('body').append('<input type="text" id="testmask" />');
+    $("#testmask").inputmask("999.999.999");
+
+    $("#testmask")[0].focus();
+
+    $("#testmask").SendKey(49);
+    $("#testmask").SendKey(50);
+    $("#testmask").SendKey(51);
+    $("#testmask").SendKey(keyCodes.LEFT);
+    $("#testmask").SendKey(keyCodes.LEFT);
+    $("#testmask").SendKey(keyCodes.BACKSPACE);
+    $("#testmask").SendKey(52);
+    $("#testmask").SendKey(keyCodes.RIGHT);
+    $("#testmask").SendKey(53);
+    $("#testmask").SendKey(54);
+
+    equal($("#testmask").val(), "143.56_.___", "Result " + $("#testmask").val());
+
+    $("#testmask").remove();
+});
+
+test("inputmask(\"999.999.999\") - delete 2nd with delete, continue the mask", function () {
+    $('body').append('<input type="text" id="testmask" />');
+    $("#testmask").inputmask("999.999.999");
+
+    $("#testmask")[0].focus();
+
+    $("#testmask").SendKey(49);
+    $("#testmask").SendKey(50);
+    $("#testmask").SendKey(51);
+    $("#testmask").SendKey(keyCodes.LEFT);
+    $("#testmask").SendKey(keyCodes.LEFT);
+    $("#testmask").SendKey(keyCodes.LEFT);
+    $("#testmask").SendKey(keyCodes.DELETE);
+    $("#testmask").SendKey(52);
+    $("#testmask").SendKey(keyCodes.RIGHT);
+    $("#testmask").SendKey(53);
+    $("#testmask").SendKey(54);
+
+    equal($("#testmask").val(), "143.56_.___", "Result " + $("#testmask").val());
+
+    $("#testmask").remove();
+});
+
+
+
+test("inputmask(\"*****\")", function () {
+    $('body').append('<input type="text" id="testmask" />');
+    $("#testmask").inputmask("*****");
+
+    $("#testmask")[0].focus();
+
+    $("#testmask").Type("abe");
+    $("#testmask").SendKey(keyCodes.LEFT);
+    $("#testmask").Type("cd");
+
+    equal($("#testmask").val(), "abcde", "Result " + $("#testmask").val());
+
+    $("#testmask").remove();
+});
+
+
+module("Initial value setting");
+
+test("inputmask(\"999:99\", { placeholder: \"0\"}) value=\"007:20\"", function () {
+    $('body').append('<input type="text" id="testmask" value="007:20" />');
+    $("#testmask").inputmask("999:99", { placeholder: "0" });
+
+    equal($("#testmask").val(), "007:20", "Result " + $("#testmask").val());
+
+    $("#testmask").remove();
+});
+
+test("inputmask(\"99 999 999 999 9999 \\D\\E*** 9999\") ~ value=\"01 650 103 002 0001 DE101 5170\"", function () {
+    $('body').append('<input type="text" id="testmask" value="01 650 103 002 0001 DE101 5170" />');
+    $("#testmask").inputmask("99 999 999 999 9999 \\D\\E*** 9999");
+    equal($("#testmask").val(), "01 650 103 002 0001 DE101 5170", "Result " + $("#testmask").val());
+
+    $("#testmask").remove();
+});
+
+test("inputmask(\"99 999 999 999 9999 \\D\\E*** 9999\") ~ value=\"016501030020001DE1015170\"", function () {
+    $('body').append('<input type="text" id="testmask" value="016501030020001DE1015170" />');
+    $("#testmask").inputmask("99 999 999 999 9999 \\D\\E*** 9999");
+    equal($("#testmask").val(), "01 650 103 002 0001 DE101 5170", "Result " + $("#testmask").val());
+
+    $("#testmask").remove();
+});
+
+test("inputmask(\"\\D\\E***\") ~ value=\"DE001\"", function () {
+    $('body').append('<input type="text" id="testmask" value="DE001" />');
+    $("#testmask").inputmask("\\D\\E***");
+    equal($("#testmask").val(), "DE001", "Result " + $("#testmask").val());
+
+    $("#testmask").remove();
+});
+
+test("inputmask(\"decimal\") ~ value=\"123.45\"", function () {
+    $('body').append('<input type="text" id="testmask" value="123.45" />');
+    $("#testmask").inputmask("decimal");
+    equal($("#testmask").val(), "123.45", "Result " + $("#testmask").val());
+
+    $("#testmask").remove();
+});
+
+module("Set value with fn.val");
+test("inputmask(\"decimal\") ~ value=\"123.45\"", function () {
+    $('body').append('<input type="text" id="testmask" />');
+    $("#testmask").inputmask("decimal");
+    $("#testmask").val("123.45");
+    equal($("#testmask").val(), "123.45", "Result " + $("#testmask").val());
+
+    $("#testmask").remove();
+});
+
+test("inputmask(\"+7 (999) 999-99-99\") ~ value=\"+7 (+79114041112___) ___-__-__\"", function () {
+    $('body').append('<input type="text" id="testmask" />');
+    $("#testmask").inputmask("+7 (999) 999-99-99");
+    $("#testmask").val("+7 (+79114041112___) ___-__-__");
+    equal($("#testmask").val(), "+7 (911) 404-11-12", "Result " + $("#testmask").val());
+
+    $("#testmask").remove();
+});
+
+module("Optional & multi masks");
+test("inputmask(\"(99) 9999[9]-99999\") - input 121234-12345", function () {
+    $('body').append('<input type="text" id="testmask" />');
+    $("#testmask").inputmask("(99) 9999[9]-99999");
+
+    $("#testmask")[0].focus();
+
+    $("#testmask").SendKey("1");
+    $("#testmask").SendKey("2");
+    $("#testmask").SendKey("1");
+    $("#testmask").SendKey("2");
+    $("#testmask").SendKey("3");
+    $("#testmask").SendKey("4");
+    $("#testmask").SendKey("-");
+    $("#testmask").SendKey("1");
+    $("#testmask").SendKey("2");
+    $("#testmask").SendKey("3");
+    $("#testmask").SendKey("4");
+    $("#testmask").SendKey("5");
+
+    equal($("#testmask").val(), "(12) 1234-12345", "Result " + $("#testmask").val());
+
+    $("#testmask").remove();
+});
+test("inputmask(\"(99) 9999[9]-99999\") - input 121234512345", function () {
+    $('body').append('<input type="text" id="testmask" />');
+    $("#testmask").inputmask("(99) 9999[9]-99999");
+
+    $("#testmask")[0].focus();
+
+    $("#testmask").SendKey("1");
+    $("#testmask").SendKey("2");
+    $("#testmask").SendKey("1");
+    $("#testmask").SendKey("2");
+    $("#testmask").SendKey("3");
+    $("#testmask").SendKey("4");
+    $("#testmask").SendKey("5");
+    $("#testmask").SendKey("1");
+    $("#testmask").SendKey("2");
+    $("#testmask").SendKey("3");
+    $("#testmask").SendKey("4");
+    $("#testmask").SendKey("5");
+
+    equal($("#testmask").val(), "(12) 12345-12345", "Result " + $("#testmask").val());
+
+    $("#testmask").remove();
+});
+test("inputmask({ mask: [\"999.999.999-99\", \"99.999.999/9999-99\"]}) - input 12312312312", function () {
+    $('body').append('<input type="text" id="testmask" />');
+    $("#testmask").inputmask({ mask: ["999.999.999-99", "99.999.999/9999-99"] });
+
+    $("#testmask")[0].focus();
+    $("#testmask").Type("12312312312");
+    
+    equal($("#testmask").val(), "123.123.123-12", "Result " + $("#testmask").val());
+
+    $("#testmask").remove();
+});
+test("inputmask({ mask: [\"999.999.999-99\", \"99.999.999/9999-99\"]}) - input 12.123123123412", function () {
+    $('body').append('<input type="text" id="testmask" />');
+    $("#testmask").inputmask({ mask: ["999.999.999-99", "99.999.999/9999-99"] });
+
+    $("#testmask")[0].focus();
+    $("#testmask").Type("12.123123123412");
+ 
+    equal($("#testmask").val(), "12.123.123/1234-12", "Result " + $("#testmask").val());
+
+    $("#testmask").remove();
+});
+
+test("inputmask({ mask: [\"99999\", \"99999-9999\"]]}) - input 12345", function () {
+    $('body').append('<input type="text" id="testmask" />');
+    $("#testmask").inputmask({ mask: ["99999", "99999-9999"] });
+
+    $("#testmask")[0].focus();
+    $("#testmask").Type("12345");
+    equal($("#testmask").val(), "12345", "Result " + $("#testmask").val());
+
+    $("#testmask").remove();
+});
+test("inputmask({ mask: [\"99999\", \"99999-9999\"]]}) - input 12345-1234", function () {
+    $('body').append('<input type="text" id="testmask" />');
+    $("#testmask").inputmask({ mask: ["99999", "99999-9999"] });
+
+    $("#testmask")[0].focus();
+    $("#testmask").Type("12345-1234");
+    equal($("#testmask").val(), "12345-1234", "Result " + $("#testmask").val());
+
+    $("#testmask").remove();
+});
+test("inputmask({ mask: [\"99999\", \"99999-9999\"]]}) - input 123451234", function () {
+    $('body').append('<input type="text" id="testmask" />');
+    $("#testmask").inputmask({ mask: ["99999", "99999-9999"] });
+
+    $("#testmask")[0].focus();
+    $("#testmask").Type("123451234");
+    equal($("#testmask").val(), "12345-1234", "Result " + $("#testmask").val());
+
+    $("#testmask").remove();
+});
+test("inputmask({ mask: [\"99999\", \"99999-9999\"]]}) - input 1234512", function () {
+    $('body').append('<input type="text" id="testmask" />');
+    $("#testmask").inputmask({ mask: ["99999", "99999-9999"] });
+
+    $("#testmask")[0].focus();
+    $("#testmask").Type("1234512");
+    equal($("#testmask").val(), "12345-12__", "Result " + $("#testmask").val());
+
+    $("#testmask").remove();
+});
+
+test("inputmask({ mask: [\"99999\", \"99999-9999\", \"999999-9999\"]]}) - input 1234561234", function () {
+    $('body').append('<input type="text" id="testmask" />');
+    $("#testmask").inputmask({ mask: ["99999", "99999-9999", "999999-9999"] });
+
+    $("#testmask")[0].focus();
+    $("#testmask").Type("1234561234");
+    equal($("#testmask").val(), "123456-1234", "Result " + $("#testmask").val());
+
+    $("#testmask").remove();
+});
+test("inputmask({ mask: [\"99999\", \"99999-9999\", \"999999-9999\"]]}) - input 123456", function () {
+    $('body').append('<input type="text" id="testmask" />');
+    $("#testmask").inputmask({ mask: ["99999", "99999-9999", "999999-9999"] });
+
+    $("#testmask")[0].focus();
+    $("#testmask").Type("123456");
+    equal($("#testmask").val(), "12345-6___", "Result " + $("#testmask").val());
+    //this is correct as the sequence of the masks || currently "99999-9999", "999999-9999" are valid and thus showing "99999-9999"
+
+    $("#testmask").remove();
+});
+
+test("inputmask({ mask: \"99999[-9999]\", greedy: true }) - input 123", function () {
+    $('body').append('<input type="text" id="testmask" />');
+    $("#testmask").inputmask({ mask: "99999[-9999]", greedy: true });
+
+    $("#testmask")[0].focus();
+    $("#testmask").Type("123");
+    equal($("#testmask").val(), "123__-____", "Result " + $("#testmask").val());
+
+    $("#testmask").remove();
+});
+
+test("inputmask({ mask: \"99999[-9999]\", greedy: false }) - input 123", function () {
+    $('body').append('<input type="text" id="testmask" />');
+    $("#testmask").inputmask({ mask: "99999[-9999]", greedy: false });
+
+    $("#testmask")[0].focus();
+    $("#testmask").Type("123");
+    equal($("#testmask").val(), "123__", "Result " + $("#testmask").val());
+
+    $("#testmask").remove();
+});
+
+test("inputmask({ mask: \"99999[-9999]\", greedy: false }) - input 12345", function () {
+    $('body').append('<input type="text" id="testmask" />');
+    $("#testmask").inputmask({ mask: "99999[-9999]", greedy: false });
+
+    $("#testmask")[0].focus();
+    $("#testmask").Type("12345");
+    equal($("#testmask").val(), "12345", "Result " + $("#testmask").val());
+
+    $("#testmask").remove();
+});
+
+test("inputmask({ mask: \"99999[-9999]\", greedy: false }) - input 123456", function () {
+    $('body').append('<input type="text" id="testmask" />');
+    $("#testmask").inputmask({ mask: "99999[-9999]", greedy: false });
+
+    $("#testmask")[0].focus();
+    $("#testmask").Type("123456");
+    equal($("#testmask").val(), "12345-6___", "Result " + $("#testmask").val());
+
+    $("#testmask").remove();
+});
+
+test("inputmask({ mask: \"99999[-9999]\", greedy: false }) - input 123456789", function () {
+    $('body').append('<input type="text" id="testmask" />');
+    $("#testmask").inputmask({ mask: "99999[-9999]", greedy: false });
+
+    $("#testmask")[0].focus();
+    $("#testmask").Type("123456789");
+    equal($("#testmask").val(), "12345-6789", "Result " + $("#testmask").val());
+
+    $("#testmask").remove();
+});
+
+module("Date.Extensions");
+test("inputmask(\"dd/mm/yyyy\") - input 2331973", function () {
+    $('body').append('<input type="text" id="testmask" />');
+    $("#testmask").inputmask("dd/mm/yyyy");
+
+    $("#testmask")[0].focus();
+
+    $("#testmask").SendKey("2");
+    $("#testmask").SendKey("3");
+    $("#testmask").SendKey("3");
+    $("#testmask").SendKey("1");
+    $("#testmask").SendKey("9");
+    $("#testmask").SendKey("7");
+    $("#testmask").SendKey("3");
+
+    equal($("#testmask").val(), "23/03/1973", "Result " + $("#testmask").val());
+
+    $("#testmask").remove();
+});
+test("inputmask(\"mm/dd/yyyy\") - input 3231973", function () {
+    $('body').append('<input type="text" id="testmask" />');
+    $("#testmask").inputmask("mm/dd/yyyy");
+
+    $("#testmask")[0].focus();
+
+    $("#testmask").SendKey("3");
+    $("#testmask").SendKey("2");
+    $("#testmask").SendKey("3");
+    $("#testmask").SendKey("1");
+    $("#testmask").SendKey("9");
+    $("#testmask").SendKey("7");
+    $("#testmask").SendKey("3");
+
+    equal($("#testmask").val(), "03/23/1973", "Result " + $("#testmask").val());
+
+    $("#testmask").remove();
+});
+
+test("inputmask(\"dd/mm/yyyy\") - input 29022012", function () {
+    $('body').append('<input type="text" id="testmask" />');
+    $("#testmask").inputmask("dd/mm/yyyy");
+
+    $("#testmask")[0].focus();
+
+    $("#testmask").SendKey("2");
+    $("#testmask").SendKey("9");
+    $("#testmask").SendKey("0");
+    $("#testmask").SendKey("2");
+    $("#testmask").SendKey("2");
+    $("#testmask").SendKey("0");
+    $("#testmask").SendKey("1");
+    $("#testmask").SendKey("2");
+
+    equal($("#testmask").val(), "29/02/2012", "Result " + $("#testmask").val());
+
+    $("#testmask").remove();
+});
+
+test("inputmask(\"dd/mm/yyyy\") - input 29022013", function () {
+    $('body').append('<input type="text" id="testmask" />');
+    $("#testmask").inputmask("dd/mm/yyyy");
+
+    $("#testmask")[0].focus();
+
+    $("#testmask").SendKey("2");
+    $("#testmask").SendKey("9");
+    $("#testmask").SendKey("0");
+    $("#testmask").SendKey("2");
+    $("#testmask").SendKey("2");
+    $("#testmask").SendKey("0");
+    $("#testmask").SendKey("1");
+    $("#testmask").SendKey("3");
+
+    equal($("#testmask").val(), "29/02/201y", "Result " + $("#testmask").val());
+
+    $("#testmask").remove();
+});
+
+test("inputmask(\"mm/dd/yyyy\") - input 02292012", function () {
+    $('body').append('<input type="text" id="testmask" />');
+    $("#testmask").inputmask("mm/dd/yyyy");
+
+    $("#testmask")[0].focus();
+
+    $("#testmask").SendKey("0");
+    $("#testmask").SendKey("2");
+    $("#testmask").SendKey("2");
+    $("#testmask").SendKey("9");
+    $("#testmask").SendKey("2");
+    $("#testmask").SendKey("0");
+    $("#testmask").SendKey("1");
+    $("#testmask").SendKey("2");
+
+    equal($("#testmask").val(), "02/29/2012", "Result " + $("#testmask").val());
+
+    $("#testmask").remove();
+});
+
+test("inputmask(\"mm/dd/yyyy\") - input 02292013", function () {
+    $('body').append('<input type="text" id="testmask" />');
+    $("#testmask").inputmask("mm/dd/yyyy");
+
+    $("#testmask")[0].focus();
+
+    $("#testmask").SendKey("0");
+    $("#testmask").SendKey("2");
+    $("#testmask").SendKey("2");
+    $("#testmask").SendKey("9");
+    $("#testmask").SendKey("2");
+    $("#testmask").SendKey("0");
+    $("#testmask").SendKey("1");
+    $("#testmask").SendKey("3");
+
+    equal($("#testmask").val(), "02/29/201y", "Result " + $("#testmask").val());
+
+    $("#testmask").remove();
+});
+
+test("inputmask(\"dd/mm/yyyy\") - input CTRL RIGHT", function () {
+    $('body').append('<input type="text" id="testmask" />');
+    $("#testmask").inputmask("dd/mm/yyyy");
+
+    $("#testmask")[0].focus();
+    $("#testmask").SendKey(keyCodes.RIGHT, keyCodes.CONTROL);
+    ok($("#testmask").val() != "dd/mm/yyyy", "Result " + $("#testmask").val());
+
+    $("#testmask").remove();
+});
+
+test("inputmask(\"dd/mm/yyyy\") - input 2331973 BACKSPACE x4 2013", function () {
+    $('body').append('<input type="text" id="testmask" />');
+    $("#testmask").inputmask("dd/mm/yyyy");
+
+    $("#testmask")[0].focus();
+
+    $("#testmask").SendKey("2");
+    $("#testmask").SendKey("3");
+    $("#testmask").SendKey("3");
+    $("#testmask").SendKey("1");
+    $("#testmask").SendKey("9");
+    $("#testmask").SendKey("7");
+    $("#testmask").SendKey("3");
+    $("#testmask").SendKey(keyCodes.BACKSPACE);
+    $("#testmask").SendKey(keyCodes.BACKSPACE);
+    $("#testmask").SendKey(keyCodes.BACKSPACE);
+    $("#testmask").SendKey(keyCodes.BACKSPACE);
+    $("#testmask").SendKey("2");
+    $("#testmask").SendKey("0");
+    $("#testmask").SendKey("1");
+    $("#testmask").SendKey("3");
+
+    equal($("#testmask").val(), "23/03/2013", "Result " + $("#testmask").val());
+
+    $("#testmask").remove();
+});
+
+module("Numeric.Extensions");
+test("inputmask(\"decimal\", { autoGroup: true, groupSeparator: \",\" }\") - input 12345.123", function () {
+    $('body').append('<input type="text" id="testmask" />');
+    $("#testmask").inputmask("decimal", { autoGroup: true, groupSeparator: "," });
+
+    $("#testmask")[0].focus();
+
+    $("#testmask").SendKey("1");
+    $("#testmask").SendKey("2");
+    $("#testmask").SendKey("3");
+    $("#testmask").SendKey("4");
+    $("#testmask").SendKey("5");
+    $("#testmask").SendKey(".");
+    $("#testmask").SendKey("1");
+    $("#testmask").SendKey("2");
+    $("#testmask").SendKey("3");
+
+    equal($("#testmask").val(), "12,345.123", "Result " + $("#testmask").val());
+    $("#testmask").remove();
+});
+
+test("inputmask(\"decimal\", { autoGroup: true, groupSeparator: \",\" }\") - input 12345.123 + remove .123", function () {
+    $('body').append('<input type="text" id="testmask" />');
+    $("#testmask").inputmask("decimal", { autoGroup: true, groupSeparator: "," });
+
+    $("#testmask")[0].focus();
+
+    $("#testmask").Type("12345.123");
+    $("#testmask")[0].focus();
+    //$("#testmask").click();
+    $("#testmask").SendKey(keyCodes.LEFT);
+    $("#testmask").SendKey(keyCodes.LEFT);
+    $("#testmask").SendKey(keyCodes.LEFT);
+    $("#testmask").SendKey(keyCodes.LEFT);
+    $("#testmask").SendKey(keyCodes.DELETE);
+    $("#testmask").SendKey(keyCodes.DELETE);
+    $("#testmask").SendKey(keyCodes.DELETE);
+    $("#testmask").SendKey(keyCodes.BACKSPACE);
+
+    equal($("#testmask").val(), "12,345", "Result " + $("#testmask").val());
+    $("#testmask").remove();
+});
+test("inputmask(\"decimal\", { autoGroup: true, groupSeparator: \",\" }\") - input 12345.123 + replace .123 => .789", function () {
+    $('body').append('<input type="text" id="testmask" />');
+    $("#testmask").inputmask("decimal", { autoGroup: true, groupSeparator: "," });
+
+    $("#testmask")[0].focus();
+
+    $("#testmask").Type("12345.123");
+    //$("#testmask").click();
+    $("#testmask").SendKey(keyCodes.LEFT);
+    $("#testmask").SendKey(keyCodes.LEFT);
+    $("#testmask").SendKey(keyCodes.LEFT);
+    $("#testmask").SendKey(keyCodes.LEFT);
+    $("#testmask").SendKey(keyCodes.DELETE);
+    $("#testmask").SendKey(keyCodes.DELETE);
+    $("#testmask").SendKey(keyCodes.DELETE);
+    $("#testmask").Type(".789");
+
+    equal($("#testmask").val(), "12,345.789", "Result " + $("#testmask").val());
+    $("#testmask").remove();
+});
+
+test("inputmask(\"decimal\", { autoGroup: false, groupSeparator: \",\" }\") - input 12345.123 + remove .123", function () {
+    $('body').append('<input type="text" id="testmask" />');
+    $("#testmask").inputmask("decimal", { autoGroup: false, groupSeparator: "," });
+
+    $("#testmask")[0].focus();
+
+    $("#testmask").Type("12345.123");
+    //$("#testmask").click();
+    $("#testmask").SendKey(keyCodes.LEFT);
+    $("#testmask").SendKey(keyCodes.LEFT);
+    $("#testmask").SendKey(keyCodes.LEFT);
+    $("#testmask").SendKey(keyCodes.LEFT);
+    $("#testmask").SendKey(keyCodes.DELETE);
+    $("#testmask").SendKey(keyCodes.DELETE);
+    $("#testmask").SendKey(keyCodes.DELETE);
+    $("#testmask").SendKey(keyCodes.BACKSPACE);
+
+    equal($("#testmask").val(), "12345", "Result " + $("#testmask").val());
+    $("#testmask").remove();
+});
+test("inputmask(\"decimal\", { autoGroup: false, groupSeparator: \",\" }\") - input 12345.123 + replace .123 => .789", function () {
+    $('body').append('<input type="text" id="testmask" />');
+    $("#testmask").inputmask("decimal", { autoGroup: false, groupSeparator: "," });
+
+    $("#testmask")[0].focus();
+
+    $("#testmask").Type("12345.123");
+    //$("#testmask").click();
+    $("#testmask").SendKey(keyCodes.LEFT);
+    $("#testmask").SendKey(keyCodes.LEFT);
+    $("#testmask").SendKey(keyCodes.LEFT);
+    $("#testmask").SendKey(keyCodes.LEFT);
+    $("#testmask").SendKey(keyCodes.DELETE);
+    $("#testmask").SendKey(keyCodes.DELETE);
+    $("#testmask").SendKey(keyCodes.DELETE);
+    $("#testmask").Type(".789");
+
+    equal($("#testmask").val(), "12345.789", "Result " + $("#testmask").val());
+    $("#testmask").remove();
+});
+
+module("Direction RTL");
+test("inputmask(\"999.999.999\") - delete 2nd with backspace, continue the mask", function () {
+    $('body').append('<input type="text" id="testmask" dir="rtl" />');
+    $("#testmask").inputmask("999.999.999");
+
+    $("#testmask")[0].focus();
+
+    $("#testmask").SendKey("1");
+    $("#testmask").SendKey("2");
+    $("#testmask").SendKey("3");
+    $("#testmask").SendKey(keyCodes.RIGHT);
+    $("#testmask").SendKey(keyCodes.RIGHT);
+    $("#testmask").SendKey(keyCodes.BACKSPACE);
+    $("#testmask").SendKey("4");
+    $("#testmask").SendKey(keyCodes.LEFT);
+    $("#testmask").SendKey("5");
+    $("#testmask").SendKey("6");
+
+    equal($("#testmask").val(), "___._65.341", "Result " + $("#testmask").val());
+
+    $("#testmask").remove();
+});
+
+test("inputmask(\"999.999.999\") - delete 2nd with delete, continue the mask", function () {
+    $('body').append('<input type="text" id="testmask" dir="rtl" />');
+    $("#testmask").inputmask("999.999.999");
+
+    $("#testmask")[0].focus();
+
+    $("#testmask").SendKey("1");
+    $("#testmask").SendKey("2");
+    $("#testmask").SendKey("3");
+    $("#testmask").SendKey(keyCodes.RIGHT);
+    $("#testmask").SendKey(keyCodes.DELETE);
+    $("#testmask").SendKey("4");
+    $("#testmask").SendKey(keyCodes.LEFT);
+    $("#testmask").SendKey("5");
+    $("#testmask").SendKey("6");
+
+    equal($("#testmask").val(), "___._65.341", "Result " + $("#testmask").val());
+
+    $("#testmask").remove();
+});
+
+test("inputmask(\"999-aaa-999\")", function () {
+    $('body').append('<input type="text" id="testmask" dir="rtl" />');
+    $("#testmask").inputmask("999-aaa-999");
+
+    $("#testmask")[0].focus();
+    $("#testmask").Type("123abc12");
+
+    equal($("#testmask").val(), "_21-cba-321", "Result " + $("#testmask").val());
+
+    $("#testmask").remove();
+});