Browse Source

update numeric extension + some fixes

Robin Herbots 11 years ago
parent
commit
075a8f0070

+ 1 - 1
bower.json

@@ -1,6 +1,6 @@
 {
     "name": "jquery.inputmask",
-    "version": "3.0.10",
+    "version": "3.0.11",
     "main": "./dist/jquery.inputmask.bundle.js",
 	"keywords" : ["jQuery", "plugins", "input", "form", "inputmask", "mask"],
 	"description": "jquery.inputmask is a jquery plugin which create an input mask.",

+ 1 - 1
build.properties

@@ -7,7 +7,7 @@ distdir = dist
 
 build.major = 3
 build.minor = 0
-build.revision = 10
+build.revision = 11
 
 target = jquery.inputmask.bundle.js
 target.min = jquery.inputmask.bundle.min.js

BIN
dist/jQuery.InputMask.3.0.10.nupkg


BIN
dist/jQuery.InputMask.3.0.11.nupkg


+ 64 - 184
dist/jquery.inputmask.bundle.js

@@ -3,7 +3,7 @@
 * http://github.com/RobinHerbots/jquery.inputmask
 * Copyright (c) 2010 - 2014 Robin Herbots
 * Licensed under the MIT license (http://www.opensource.org/licenses/mit-license.php)
-* Version: 3.0.10
+* Version: 3.0.11
 */
 
 (function ($) {
@@ -37,7 +37,7 @@
             var ms = [];
 
             function analyseMask(mask) {
-                var tokenizer = /(?:[?*+]|\{[0-9]+(?:,[0-9\+\*]*)?\})\??|[^.?*+^${[]()|\\]+|./g,
+                var tokenizer = /(?:[?*+]|\{[0-9\+\*]+(?:,[0-9\+\*]*)?\})\??|[^.?*+^${[]()|\\]+|./g,
                     escaped = false;
 
                 function maskToken(isGroup, isOptional, isQuantifier, isAlternator) {
@@ -100,9 +100,14 @@
                             var quantifier = new maskToken(false, false, true);
 
                             m = m.replace(/[{}]/g, "");
-                            var mq = m.split(","), mq0 = isNaN(mq[0]) ? mq[0] : parseInt(mq[0]), mq1 = mq.length == 1 ? mq0 : (isNaN(mq[1]) ? mq[1] : parseInt(mq[1]));
+                            var mq = m.split(","),
+                                mq0 = isNaN(mq[0]) ? mq[0] : parseInt(mq[0]),
+                                mq1 = mq.length == 1 ? mq0 : (isNaN(mq[1]) ? mq[1] : parseInt(mq[1]));
+                            if (mq1 == "*" || mq1 == "+") {
+                                mq0 = mq0 == "*" ? 0 : 1;
+                                opts.greedy = false;
+                            }
                             quantifier.quantifier = { min: mq0, max: mq1 };
-                            if (mq1 == "*" || mq1 == "+") opts.greedy = false;
                             if (openenings.length > 0) {
                                 var matches = openenings[openenings.length - 1]["matches"];
                                 var match = matches.pop();
@@ -280,7 +285,7 @@
                 return lastValidPosition;
             }
 
-            function setValidPosition(pos, validTest, strict, fromSetValid) {
+            function setValidPosition(pos, validTest, fromSetValid) {
                 if (opts.insertMode && getMaskSet()["validPositions"][pos] != undefined && fromSetValid == undefined) {
                     //reposition & revalidate others
                     var positionsClone = $.extend(true, {}, getMaskSet()["validPositions"]), lvp = getLastValidPosition(), i;
@@ -293,13 +298,14 @@
                         var j = seekNext(i);
                         var t = positionsClone[i];
                         if (t != undefined) {
-                            var nextTest = getTest(j);
+                            var nextTest = getTest(j, t["locator"].slice(), i);
                             if (nextTest.fn == null && nextTest.def == "")
                                 valid = false;
                             else if (t["match"].fn == null || t["match"].def == nextTest.def) {
-                                valid = valid && isValid(j, t["input"], strict, true) !== false;
+                                valid = valid && isValid(j, t["input"], true, true) !== false;
                             }
                         }
+                        if (!valid) break;
                         i = j;
                     }
 
@@ -338,11 +344,12 @@
                 resetMaskSet(true);
             }
 
-            function getTest(pos) {
+            function getTest(pos, ndxIntlzr, tstPs) {
                 if (getMaskSet()['validPositions'][pos]) {
                     return getMaskSet()['validPositions'][pos]["match"];
                 }
-                return getTests(pos)[0]["match"];
+                var testPos = getTests(pos, ndxIntlzr, tstPs);
+                return testPos[0]["match"];
             }
 
             function getTests(pos, ndxIntlzr, tstPs) {
@@ -440,7 +447,7 @@
                         break;
                     }
                 }
-                if (matches.length == 0 || (insertStop && matches.length < 2))
+                if (matches.length == 0 || insertStop)
                     matches.push({ "match": { fn: null, cardinality: 0, optionality: true, casing: null, def: "" }, "locator": [] });
 
                 getMaskSet()['tests'][pos] = matches;
@@ -524,7 +531,7 @@
                                 else {
                                     refreshFromBuffer(refresh["start"], refresh["end"]);
                                 }
-                                if (rslt.pos == undefined) {
+                                if (rslt.pos == undefined && rslt.c == undefined) {
                                     rslt.pos = getLastValidPosition();
                                     return false;//breakout if refreshFromBuffer && nothing to insert
                                 }
@@ -539,7 +546,7 @@
                             if (ndx > 0) {
                                 resetMaskSet(true);
                             }
-                            if (!setValidPosition(validatedPos, $.extend({}, tst, { "input": casing(elem, test) }), strict, fromSetValid))
+                            if (!setValidPosition(validatedPos, $.extend({}, tst, { "input": casing(elem, test) }), fromSetValid))
                                 rslt = false;
                             return false; //break from $.each
                         }
@@ -573,18 +580,16 @@
                 var maskLength;
                 maxLength = $el.prop('maxLength');
                 if (maxLength == -1) maxLength = undefined; /* FF sets no defined max length to -1 */
-                if (opts.greedy == false) { //TODO FIXME OPTIMIZE ME
-                    var lvp = getLastValidPosition() + 1,
-                        test = getTest(lvp);
-                    while (!(test.fn == null && test.def == "")) { //determine last possible position
-                        test = getTest(++lvp);
-                        if (test.optionality !== true) {
-                            var tests = getTests(lvp);
-                            test = tests[tests.length - 1]["match"];
-                        }
+                if (opts.greedy == false) {
+                    var pos, lvp = getLastValidPosition(), testPos = getMaskSet()["validPositions"][lvp],
+                        ndxIntlzr = testPos != undefined ? testPos["locator"].slice() : undefined;
+                    for (pos = lvp + 1; testPos == undefined || (testPos["match"]["fn"] != null || (testPos["match"]["fn"] == null && testPos["match"]["def"] != "")) ; pos++) {
+                        testPos = getTests(pos, ndxIntlzr, pos - 1);
+                        var firstMatch = testPos[0]["match"];
+                        testPos = testPos[(opts.greedy || (firstMatch.optionality === true && firstMatch.newBlockMarker === false && firstMatch.optionalQuantifier !== true)) ? 0 : (testPos.length - 1)];
+                        ndxIntlzr = testPos["locator"].slice();
                     }
-                    maskLength = getMaskTemplate(true, lvp).length;
-                    getMaskSet()["tests"] = {}; //cleanup tests
+                    maskLength = pos;
                 } else
                     maskLength = getBuffer().length;
 
@@ -968,7 +973,10 @@
                 var keydownResult = opts.onKeyDown.call(this, e, getBuffer(), opts);
                 if (keydownResult && keydownResult["refreshFromBuffer"] === true) { //extra stuff to execute on keydown
                     getMaskSet()["validPositions"] = {};
+                    getMaskSet()["tests"] = {};
                     refreshFromBuffer(0, getBuffer().length);
+                    resetMaskSet(true);
+                    writeBuffer(input, getBuffer());
                     caret(input, currentCaretPos.begin, currentCaretPos.end);
                 }
                 ignorable = $.inArray(k, opts.ignorables) != -1;
@@ -1006,7 +1014,7 @@
                             HandleRemove(input, opts.keyCode.DELETE, pos);
                             if (!opts.insertMode) { //preserve some space
                                 opts.insertMode = !opts.insertMode;
-                                setValidPosition(pos.begin, undefined, strict);
+                                setValidPosition(pos.begin, strict);
                                 opts.insertMode = !opts.insertMode;
                             }
                             isSlctn = !opts.multi;
@@ -1090,7 +1098,10 @@
                 var keyupResult = opts.onKeyUp.call(this, e, buffer, opts);
                 if (keyupResult && keyupResult["refreshFromBuffer"] === true) {
                     getMaskSet()["validPositions"] = {};
+                    getMaskSet()["tests"] = {};
                     refreshFromBuffer(0, getBuffer().length);
+                    resetMaskSet(true);
+                    writeBuffer(input, getBuffer());
                 }
                 if (k == opts.keyCode.TAB && opts.showMaskOnFocus) {
                     if ($input.hasClass('focus.inputmask') && input._valueGet().length == 0) {
@@ -1837,7 +1848,7 @@ Input Mask plugin extensions
 http://github.com/RobinHerbots/jquery.inputmask
 Copyright (c) 2010 - 2014 Robin Herbots
 Licensed under the MIT license (http://www.opensource.org/licenses/mit-license.php)
-Version: 3.0.10
+Version: 3.0.11
 
 Optional extensions on the jquery.inputmask base
 */
@@ -1947,7 +1958,7 @@ Input Mask plugin extensions
 http://github.com/RobinHerbots/jquery.inputmask
 Copyright (c) 2010 - 2014 Robin Herbots
 Licensed under the MIT license (http://www.opensource.org/licenses/mit-license.php)
-Version: 3.0.10
+Version: 3.0.11
 
 Optional extensions on the jquery.inputmask base
 */
@@ -2410,7 +2421,7 @@ Input Mask plugin extensions
 http://github.com/RobinHerbots/jquery.inputmask
 Copyright (c) 2010 - 2014 Robin Herbots
 Licensed under the MIT license (http://www.opensource.org/licenses/mit-license.php)
-Version: 3.0.10
+Version: 3.0.11
 
 Optional extensions on the jquery.inputmask base
 */
@@ -2420,23 +2431,25 @@ Optional extensions on the jquery.inputmask base
         'numeric': {
             mask: function (opts) {
                 var mask = opts.prefix;
-                mask += "[+]~{1," + opts.integerDigits + "}";
-                mask += "[" + opts.radixPoint + "~{" + opts.digits + "}]";
+                mask += "[+]";
+                mask += "~{1," + opts.integerDigits + "}";
+                if (parseInt(opts.digits) > 0)
+                    mask += "[" + opts.radixPoint + "~{" + opts.digits + "}]";
                 mask += opts.suffix;
                 return mask;
             },
             placeholder: "",
             greedy: false,
             numericInput: false,
-            isNumeric: false,
-            digits: "2", //number of fractionalDigits
+            isNumeric: true,
+            digits: "*", //number of fractionalDigits
             groupSeparator: "",//",", // | "."
             radixPoint: ".",
             groupSize: 3,
             autoGroup: false,
             allowPlus: true,
             allowMinus: true,
-            integerDigits: "20", //number of integerDigits
+            integerDigits: "*", //number of integerDigits
             defaultValue: "",
             prefix: "",
             suffix: "",
@@ -2470,6 +2483,13 @@ Optional extensions on the jquery.inputmask base
 
                 return reformatOnly ? pos : newPos;
             },
+            onKeyDown: function (e, buffer, opts) {
+                var $input = $(this), input = this;
+                if (opts.autoGroup && e.keyCode == opts.keyCode.DELETE || e.keyCode == opts.keyCode.BACKSPACE) {
+                    opts.postFormat(buffer, 0, true, opts);
+                    return { "refreshFromBuffer": true };
+                }
+            },
             regex: {
                 integerPart: function (opts) { return new RegExp('[-\+]?\\d+'); }
             },
@@ -2491,7 +2511,13 @@ Optional extensions on the jquery.inputmask base
                                 }
                             }
                         }
-                        var isValid = new RegExp("[0-9]").test(chrs);
+                        var isValid = strict ? new RegExp("[0-9" + $.inputmask.escapeRegex.call(this, opts.groupSeparator) + "]").test(chrs) : new RegExp("[0-9]").test(chrs);
+
+                        if (isValid != false && !strict && chrs != opts.radixPoint) {
+                            var newPos = opts.postFormat(buffer, pos, (chrs == "-" || chrs == "+") ? true : false, opts);
+                            return { "pos": newPos, "refreshFromBuffer": true };
+                        }
+
                         return isValid;
                     },
                     cardinality: 1,
@@ -2514,157 +2540,11 @@ Optional extensions on the jquery.inputmask base
             autoUnmask: false
         },
         'decimal': {
-            mask: "~",
-            placeholder: "",
-            repeat: "*",
-            greedy: false,
-            numericInput: false,
-            isNumeric: true,
-            digits: "*", //number of fractionalDigits
-            groupSeparator: "",//",", // | "."
-            radixPoint: ".",
-            groupSize: 3,
-            autoGroup: false,
-            allowPlus: true,
-            allowMinus: true,
-            //todo
-            integerDigits: "*", //number of integerDigits
-            defaultValue: "",
-            prefix: "",
-            suffix: "",
-            postFormat: function (buffer, pos, reformatOnly, opts) {
-                if (opts.groupSeparator == "") return pos;
-                var cbuf = buffer.slice(),
-                    radixPos = $.inArray(opts.radixPoint, buffer);
-                if (!reformatOnly) {
-                    cbuf.splice(pos, 0, "?"); //set position indicator
-                }
-                var bufVal = cbuf.join('');
-                if (opts.autoGroup || (reformatOnly && bufVal.indexOf(opts.groupSeparator) != -1)) {
-                    var escapedGroupSeparator = $.inputmask.escapeRegex.call(this, opts.groupSeparator);
-                    bufVal = bufVal.replace(new RegExp(escapedGroupSeparator, "g"), '');
-                    var radixSplit = bufVal.split(opts.radixPoint);
-                    bufVal = radixSplit[0];
-                    var reg = new RegExp('([-\+]?[\\d\?]+)([\\d\?]{' + opts.groupSize + '})');
-                    while (reg.test(bufVal)) {
-                        bufVal = bufVal.replace(reg, '$1' + opts.groupSeparator + '$2');
-                        bufVal = bufVal.replace(opts.groupSeparator + opts.groupSeparator, opts.groupSeparator);
-                    }
-                    if (radixSplit.length > 1)
-                        bufVal += opts.radixPoint + radixSplit[1];
-                }
-                buffer.length = bufVal.length; //align the length
-                for (var i = 0, l = bufVal.length; i < l; i++) {
-                    buffer[i] = bufVal.charAt(i);
-                }
-                var newPos = $.inArray("?", buffer);
-                if (!reformatOnly) buffer.splice(newPos, 1);
-
-                return reformatOnly ? pos : newPos;
-            },
-            regex: {
-                number: function (opts) {
-                    var escapedRadixPoint = $.inputmask.escapeRegex.call(this, opts.radixPoint);
-                    var digitExpression = isNaN(opts.digits) ? opts.digits : '{0,' + opts.digits + '}';
-                    var integerExpression = isNaN(opts.integerDigits) ? opts.integerDigits : '{1,' + opts.integerDigits + '}';
-                    var signedExpression = opts.allowPlus || opts.allowMinus ? "[" + (opts.allowPlus ? "\+" : "") + (opts.allowMinus ? "-" : "") + "]?" : "";
-
-                    var currentRegExp = "^" + signedExpression + "\\d" + integerExpression + "(" + escapedRadixPoint + "\\d" + digitExpression + ")?$";
-                    return new RegExp(currentRegExp);
-
-                }
-            },
-            onKeyDown: function (e, buffer, opts) {
-                var $input = $(this), input = this;
-                if (e.keyCode == opts.keyCode.TAB) {
-                    var radixPosition = $.inArray(opts.radixPoint, buffer);
-                    if (radixPosition != -1) {
-                        var masksets = $input.data('_inputmask')['masksets'];
-                        var activeMasksetIndex = $input.data('_inputmask')['activeMasksetIndex'];
-                        for (var i = 1; i <= opts.digits && i < opts.getMaskLength(masksets[activeMasksetIndex]["_buffer"], opts.greedy, opts.repeat, buffer, opts) ; i++) {
-                            if (buffer[radixPosition + i] == undefined || buffer[radixPosition + i] == "") buffer[radixPosition + i] = "0";
-                        }
-                        return { "refreshFromBuffer": true };
-                    }
-                } else if (e.keyCode == opts.keyCode.DELETE || e.keyCode == opts.keyCode.BACKSPACE) {
-                    opts.postFormat(buffer, 0, true, opts);
-                    input._valueSet(buffer.join(''));
-                    return { "refreshFromBuffer": true };
-                }
-            },
-            definitions: {
-                '~': { //real number
-                    validator: function (chrs, buffer, pos, strict, opts) {
-                        var iopts = $.extend({}, opts, { digits: strict ? "*" : opts.digits });
-                        if (chrs == "") return false;
-                        if (!strict && pos <= 1 && buffer[0] === '0' && new RegExp("[\\d-]").test(chrs) && buffer.join('').length == 1) { //handle first char
-                            buffer[0] = "";
-                            return { "pos": 0 };
-                        }
-
-                        var cbuf = strict ? buffer.slice(0, pos) : buffer.slice();
-
-                        cbuf.splice(pos, 0, chrs);
-                        var bufferStr = cbuf.join('');
-
-                        //strip groupseparator
-                        var escapedGroupSeparator = $.inputmask.escapeRegex.call(this, opts.groupSeparator);
-                        bufferStr = bufferStr.replace(new RegExp(escapedGroupSeparator, "g"), '');
-                        if (strict && bufferStr.lastIndexOf(opts.radixPoint) == bufferStr.length - 1) {
-                            var escapedRadixPoint = $.inputmask.escapeRegex.call(this, opts.radixPoint);
-                            bufferStr = bufferStr.replace(new RegExp(escapedRadixPoint, "g"), '');
-                        }
-                        if (!strict && bufferStr == "") return false;
-
-                        var isValid = opts.regex.number(iopts).test(bufferStr);
-                        if (!isValid) {
-                            //let's help the regex a bit
-                            bufferStr += "0";
-                            isValid = opts.regex.number(iopts).test(bufferStr);
-                            if (!isValid) {
-                                //make a valid group
-                                var lastGroupSeparator = bufferStr.lastIndexOf(opts.groupSeparator);
-                                for (var i = bufferStr.length - lastGroupSeparator; i <= 3; i++) {
-                                    bufferStr += "0";
-                                }
-
-                                isValid = opts.regex.number(iopts).test(bufferStr);
-                                if (!isValid && !strict) {
-                                    if (chrs == opts.radixPoint) {
-                                        isValid = opts.regex.number(iopts).test("0" + bufferStr + "0");
-                                        if (isValid) {
-                                            buffer[pos] = "0";
-                                            pos++;
-                                            return { "pos": pos };
-                                        }
-                                    }
-                                }
-                            }
-                        }
-
-                        if (isValid != false && !strict && chrs != opts.radixPoint) {
-                            var newPos = opts.postFormat(buffer, pos, (chrs == "-" || chrs == "+") ? true : false, opts);
-                            return { "pos": newPos, "refreshFromBuffer": true };
-                        }
-
-                        return isValid;
-                    },
-                    cardinality: 1,
-                    prevalidator: null
-                }
-            },
-            insertMode: true,
-            autoUnmask: false
+            alias: "numeric"
         },
         'integer': {
-            regex: {
-                number: function (opts) {
-                    var escapedGroupSeparator = $.inputmask.escapeRegex.call(this, opts.groupSeparator);
-                    var signedExpression = opts.allowPlus || opts.allowMinus ? "[" + (opts.allowPlus ? "\+" : "") + (opts.allowMinus ? "-" : "") + "]?" : "";
-                    return new RegExp("^" + signedExpression + "(\\d+|\\d{1," + opts.groupSize + "}((" + escapedGroupSeparator + "\\d{" + opts.groupSize + "})?)+)$");
-                }
-            },
-            alias: "decimal"
+            alias: "numeric",
+            digits: "0"
         }
     });
 })(jQuery);
@@ -2673,7 +2553,7 @@ Input Mask plugin extensions
 http://github.com/RobinHerbots/jquery.inputmask
 Copyright (c) 2010 - 2014 Robin Herbots
 Licensed under the MIT license (http://www.opensource.org/licenses/mit-license.php)
-Version: 3.0.10
+Version: 3.0.11
 
 Regex extensions on the jquery.inputmask base
 Allows for using regular expressions as a mask
@@ -2860,7 +2740,7 @@ Input Mask plugin extensions
 http://github.com/RobinHerbots/jquery.inputmask
 Copyright (c) 2010 - 2014 Robin Herbots
 Licensed under the MIT license (http://www.opensource.org/licenses/mit-license.php)
-Version: 3.0.10
+Version: 3.0.11
 
 Phone extension.
 When using this extension make sure you specify the correct url to get the masks

File diff suppressed because it is too large
+ 88 - 91
dist/jquery.inputmask.bundle.min.js


File diff suppressed because it is too large
+ 59 - 58
dist/min/jquery.inputmask.js


File diff suppressed because it is too large
+ 5 - 9
dist/min/jquery.inputmask.numeric.extensions.js


+ 1 - 1
jquery.inputmask.jquery.json

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

+ 34 - 23
js/jquery.inputmask.js

@@ -37,7 +37,7 @@
             var ms = [];
 
             function analyseMask(mask) {
-                var tokenizer = /(?:[?*+]|\{[0-9]+(?:,[0-9\+\*]*)?\})\??|[^.?*+^${[]()|\\]+|./g,
+                var tokenizer = /(?:[?*+]|\{[0-9\+\*]+(?:,[0-9\+\*]*)?\})\??|[^.?*+^${[]()|\\]+|./g,
                     escaped = false;
 
                 function maskToken(isGroup, isOptional, isQuantifier, isAlternator) {
@@ -100,9 +100,14 @@
                             var quantifier = new maskToken(false, false, true);
 
                             m = m.replace(/[{}]/g, "");
-                            var mq = m.split(","), mq0 = isNaN(mq[0]) ? mq[0] : parseInt(mq[0]), mq1 = mq.length == 1 ? mq0 : (isNaN(mq[1]) ? mq[1] : parseInt(mq[1]));
+                            var mq = m.split(","),
+                                mq0 = isNaN(mq[0]) ? mq[0] : parseInt(mq[0]),
+                                mq1 = mq.length == 1 ? mq0 : (isNaN(mq[1]) ? mq[1] : parseInt(mq[1]));
+                            if (mq1 == "*" || mq1 == "+") {
+                                mq0 = mq0 == "*" ? 0 : 1;
+                                opts.greedy = false;
+                            }
                             quantifier.quantifier = { min: mq0, max: mq1 };
-                            if (mq1 == "*" || mq1 == "+") opts.greedy = false;
                             if (openenings.length > 0) {
                                 var matches = openenings[openenings.length - 1]["matches"];
                                 var match = matches.pop();
@@ -280,7 +285,7 @@
                 return lastValidPosition;
             }
 
-            function setValidPosition(pos, validTest, strict, fromSetValid) {
+            function setValidPosition(pos, validTest, fromSetValid) {
                 if (opts.insertMode && getMaskSet()["validPositions"][pos] != undefined && fromSetValid == undefined) {
                     //reposition & revalidate others
                     var positionsClone = $.extend(true, {}, getMaskSet()["validPositions"]), lvp = getLastValidPosition(), i;
@@ -293,13 +298,14 @@
                         var j = seekNext(i);
                         var t = positionsClone[i];
                         if (t != undefined) {
-                            var nextTest = getTest(j);
+                            var nextTest = getTest(j, t["locator"].slice(), i);
                             if (nextTest.fn == null && nextTest.def == "")
                                 valid = false;
                             else if (t["match"].fn == null || t["match"].def == nextTest.def) {
-                                valid = valid && isValid(j, t["input"], strict, true) !== false;
+                                valid = valid && isValid(j, t["input"], true, true) !== false;
                             }
                         }
+                        if (!valid) break;
                         i = j;
                     }
 
@@ -338,11 +344,12 @@
                 resetMaskSet(true);
             }
 
-            function getTest(pos) {
+            function getTest(pos, ndxIntlzr, tstPs) {
                 if (getMaskSet()['validPositions'][pos]) {
                     return getMaskSet()['validPositions'][pos]["match"];
                 }
-                return getTests(pos)[0]["match"];
+                var testPos = getTests(pos, ndxIntlzr, tstPs);
+                return testPos[0]["match"];
             }
 
             function getTests(pos, ndxIntlzr, tstPs) {
@@ -440,7 +447,7 @@
                         break;
                     }
                 }
-                if (matches.length == 0 || (insertStop && matches.length < 2))
+                if (matches.length == 0 || insertStop)
                     matches.push({ "match": { fn: null, cardinality: 0, optionality: true, casing: null, def: "" }, "locator": [] });
 
                 getMaskSet()['tests'][pos] = matches;
@@ -524,7 +531,7 @@
                                 else {
                                     refreshFromBuffer(refresh["start"], refresh["end"]);
                                 }
-                                if (rslt.pos == undefined) {
+                                if (rslt.pos == undefined && rslt.c == undefined) {
                                     rslt.pos = getLastValidPosition();
                                     return false;//breakout if refreshFromBuffer && nothing to insert
                                 }
@@ -539,7 +546,7 @@
                             if (ndx > 0) {
                                 resetMaskSet(true);
                             }
-                            if (!setValidPosition(validatedPos, $.extend({}, tst, { "input": casing(elem, test) }), strict, fromSetValid))
+                            if (!setValidPosition(validatedPos, $.extend({}, tst, { "input": casing(elem, test) }), fromSetValid))
                                 rslt = false;
                             return false; //break from $.each
                         }
@@ -573,18 +580,16 @@
                 var maskLength;
                 maxLength = $el.prop('maxLength');
                 if (maxLength == -1) maxLength = undefined; /* FF sets no defined max length to -1 */
-                if (opts.greedy == false) { //TODO FIXME OPTIMIZE ME
-                    var lvp = getLastValidPosition() + 1,
-                        test = getTest(lvp);
-                    while (!(test.fn == null && test.def == "")) { //determine last possible position
-                        test = getTest(++lvp);
-                        if (test.optionality !== true) {
-                            var tests = getTests(lvp);
-                            test = tests[tests.length - 1]["match"];
-                        }
+                if (opts.greedy == false) {
+                    var pos, lvp = getLastValidPosition(), testPos = getMaskSet()["validPositions"][lvp],
+                        ndxIntlzr = testPos != undefined ? testPos["locator"].slice() : undefined;
+                    for (pos = lvp + 1; testPos == undefined || (testPos["match"]["fn"] != null || (testPos["match"]["fn"] == null && testPos["match"]["def"] != "")) ; pos++) {
+                        testPos = getTests(pos, ndxIntlzr, pos - 1);
+                        var firstMatch = testPos[0]["match"];
+                        testPos = testPos[(opts.greedy || (firstMatch.optionality === true && firstMatch.newBlockMarker === false && firstMatch.optionalQuantifier !== true)) ? 0 : (testPos.length - 1)];
+                        ndxIntlzr = testPos["locator"].slice();
                     }
-                    maskLength = getMaskTemplate(true, lvp).length;
-                    getMaskSet()["tests"] = {}; //cleanup tests
+                    maskLength = pos;
                 } else
                     maskLength = getBuffer().length;
 
@@ -968,7 +973,10 @@
                 var keydownResult = opts.onKeyDown.call(this, e, getBuffer(), opts);
                 if (keydownResult && keydownResult["refreshFromBuffer"] === true) { //extra stuff to execute on keydown
                     getMaskSet()["validPositions"] = {};
+                    getMaskSet()["tests"] = {};
                     refreshFromBuffer(0, getBuffer().length);
+                    resetMaskSet(true);
+                    writeBuffer(input, getBuffer());
                     caret(input, currentCaretPos.begin, currentCaretPos.end);
                 }
                 ignorable = $.inArray(k, opts.ignorables) != -1;
@@ -1006,7 +1014,7 @@
                             HandleRemove(input, opts.keyCode.DELETE, pos);
                             if (!opts.insertMode) { //preserve some space
                                 opts.insertMode = !opts.insertMode;
-                                setValidPosition(pos.begin, undefined, strict);
+                                setValidPosition(pos.begin, strict);
                                 opts.insertMode = !opts.insertMode;
                             }
                             isSlctn = !opts.multi;
@@ -1090,7 +1098,10 @@
                 var keyupResult = opts.onKeyUp.call(this, e, buffer, opts);
                 if (keyupResult && keyupResult["refreshFromBuffer"] === true) {
                     getMaskSet()["validPositions"] = {};
+                    getMaskSet()["tests"] = {};
                     refreshFromBuffer(0, getBuffer().length);
+                    resetMaskSet(true);
+                    writeBuffer(input, getBuffer());
                 }
                 if (k == opts.keyCode.TAB && opts.showMaskOnFocus) {
                     if ($input.hasClass('focus.inputmask') && input._valueGet().length == 0) {

+ 24 - 155
js/jquery.inputmask.numeric.extensions.js

@@ -13,23 +13,25 @@ Optional extensions on the jquery.inputmask base
         'numeric': {
             mask: function (opts) {
                 var mask = opts.prefix;
-                mask += "[+]~{1," + opts.integerDigits + "}";
-                mask += "[" + opts.radixPoint + "~{" + opts.digits + "}]";
+                mask += "[+]";
+                mask += "~{1," + opts.integerDigits + "}";
+                if (parseInt(opts.digits) > 0)
+                    mask += "[" + opts.radixPoint + "~{" + opts.digits + "}]";
                 mask += opts.suffix;
                 return mask;
             },
             placeholder: "",
             greedy: false,
             numericInput: false,
-            isNumeric: false,
-            digits: "2", //number of fractionalDigits
+            isNumeric: true,
+            digits: "*", //number of fractionalDigits
             groupSeparator: "",//",", // | "."
             radixPoint: ".",
             groupSize: 3,
             autoGroup: false,
             allowPlus: true,
             allowMinus: true,
-            integerDigits: "20", //number of integerDigits
+            integerDigits: "*", //number of integerDigits
             defaultValue: "",
             prefix: "",
             suffix: "",
@@ -63,6 +65,13 @@ Optional extensions on the jquery.inputmask base
 
                 return reformatOnly ? pos : newPos;
             },
+            onKeyDown: function (e, buffer, opts) {
+                var $input = $(this), input = this;
+                if (opts.autoGroup && e.keyCode == opts.keyCode.DELETE || e.keyCode == opts.keyCode.BACKSPACE) {
+                    opts.postFormat(buffer, 0, true, opts);
+                    return { "refreshFromBuffer": true };
+                }
+            },
             regex: {
                 integerPart: function (opts) { return new RegExp('[-\+]?\\d+'); }
             },
@@ -84,7 +93,13 @@ Optional extensions on the jquery.inputmask base
                                 }
                             }
                         }
-                        var isValid = new RegExp("[0-9]").test(chrs);
+                        var isValid = strict ? new RegExp("[0-9" + $.inputmask.escapeRegex.call(this, opts.groupSeparator) + "]").test(chrs) : new RegExp("[0-9]").test(chrs);
+
+                        if (isValid != false && !strict && chrs != opts.radixPoint) {
+                            var newPos = opts.postFormat(buffer, pos, (chrs == "-" || chrs == "+") ? true : false, opts);
+                            return { "pos": newPos, "refreshFromBuffer": true };
+                        }
+
                         return isValid;
                     },
                     cardinality: 1,
@@ -107,157 +122,11 @@ Optional extensions on the jquery.inputmask base
             autoUnmask: false
         },
         'decimal': {
-            mask: "~",
-            placeholder: "",
-            repeat: "*",
-            greedy: false,
-            numericInput: false,
-            isNumeric: true,
-            digits: "*", //number of fractionalDigits
-            groupSeparator: "",//",", // | "."
-            radixPoint: ".",
-            groupSize: 3,
-            autoGroup: false,
-            allowPlus: true,
-            allowMinus: true,
-            //todo
-            integerDigits: "*", //number of integerDigits
-            defaultValue: "",
-            prefix: "",
-            suffix: "",
-            postFormat: function (buffer, pos, reformatOnly, opts) {
-                if (opts.groupSeparator == "") return pos;
-                var cbuf = buffer.slice(),
-                    radixPos = $.inArray(opts.radixPoint, buffer);
-                if (!reformatOnly) {
-                    cbuf.splice(pos, 0, "?"); //set position indicator
-                }
-                var bufVal = cbuf.join('');
-                if (opts.autoGroup || (reformatOnly && bufVal.indexOf(opts.groupSeparator) != -1)) {
-                    var escapedGroupSeparator = $.inputmask.escapeRegex.call(this, opts.groupSeparator);
-                    bufVal = bufVal.replace(new RegExp(escapedGroupSeparator, "g"), '');
-                    var radixSplit = bufVal.split(opts.radixPoint);
-                    bufVal = radixSplit[0];
-                    var reg = new RegExp('([-\+]?[\\d\?]+)([\\d\?]{' + opts.groupSize + '})');
-                    while (reg.test(bufVal)) {
-                        bufVal = bufVal.replace(reg, '$1' + opts.groupSeparator + '$2');
-                        bufVal = bufVal.replace(opts.groupSeparator + opts.groupSeparator, opts.groupSeparator);
-                    }
-                    if (radixSplit.length > 1)
-                        bufVal += opts.radixPoint + radixSplit[1];
-                }
-                buffer.length = bufVal.length; //align the length
-                for (var i = 0, l = bufVal.length; i < l; i++) {
-                    buffer[i] = bufVal.charAt(i);
-                }
-                var newPos = $.inArray("?", buffer);
-                if (!reformatOnly) buffer.splice(newPos, 1);
-
-                return reformatOnly ? pos : newPos;
-            },
-            regex: {
-                number: function (opts) {
-                    var escapedRadixPoint = $.inputmask.escapeRegex.call(this, opts.radixPoint);
-                    var digitExpression = isNaN(opts.digits) ? opts.digits : '{0,' + opts.digits + '}';
-                    var integerExpression = isNaN(opts.integerDigits) ? opts.integerDigits : '{1,' + opts.integerDigits + '}';
-                    var signedExpression = opts.allowPlus || opts.allowMinus ? "[" + (opts.allowPlus ? "\+" : "") + (opts.allowMinus ? "-" : "") + "]?" : "";
-
-                    var currentRegExp = "^" + signedExpression + "\\d" + integerExpression + "(" + escapedRadixPoint + "\\d" + digitExpression + ")?$";
-                    return new RegExp(currentRegExp);
-
-                }
-            },
-            onKeyDown: function (e, buffer, opts) {
-                var $input = $(this), input = this;
-                if (e.keyCode == opts.keyCode.TAB) {
-                    var radixPosition = $.inArray(opts.radixPoint, buffer);
-                    if (radixPosition != -1) {
-                        var masksets = $input.data('_inputmask')['masksets'];
-                        var activeMasksetIndex = $input.data('_inputmask')['activeMasksetIndex'];
-                        for (var i = 1; i <= opts.digits && i < opts.getMaskLength(masksets[activeMasksetIndex]["_buffer"], opts.greedy, opts.repeat, buffer, opts) ; i++) {
-                            if (buffer[radixPosition + i] == undefined || buffer[radixPosition + i] == "") buffer[radixPosition + i] = "0";
-                        }
-                        return { "refreshFromBuffer": true };
-                    }
-                } else if (e.keyCode == opts.keyCode.DELETE || e.keyCode == opts.keyCode.BACKSPACE) {
-                    opts.postFormat(buffer, 0, true, opts);
-                    input._valueSet(buffer.join(''));
-                    return { "refreshFromBuffer": true };
-                }
-            },
-            definitions: {
-                '~': { //real number
-                    validator: function (chrs, buffer, pos, strict, opts) {
-                        var iopts = $.extend({}, opts, { digits: strict ? "*" : opts.digits });
-                        if (chrs == "") return false;
-                        if (!strict && pos <= 1 && buffer[0] === '0' && new RegExp("[\\d-]").test(chrs) && buffer.join('').length == 1) { //handle first char
-                            buffer[0] = "";
-                            return { "pos": 0 };
-                        }
-
-                        var cbuf = strict ? buffer.slice(0, pos) : buffer.slice();
-
-                        cbuf.splice(pos, 0, chrs);
-                        var bufferStr = cbuf.join('');
-
-                        //strip groupseparator
-                        var escapedGroupSeparator = $.inputmask.escapeRegex.call(this, opts.groupSeparator);
-                        bufferStr = bufferStr.replace(new RegExp(escapedGroupSeparator, "g"), '');
-                        if (strict && bufferStr.lastIndexOf(opts.radixPoint) == bufferStr.length - 1) {
-                            var escapedRadixPoint = $.inputmask.escapeRegex.call(this, opts.radixPoint);
-                            bufferStr = bufferStr.replace(new RegExp(escapedRadixPoint, "g"), '');
-                        }
-                        if (!strict && bufferStr == "") return false;
-
-                        var isValid = opts.regex.number(iopts).test(bufferStr);
-                        if (!isValid) {
-                            //let's help the regex a bit
-                            bufferStr += "0";
-                            isValid = opts.regex.number(iopts).test(bufferStr);
-                            if (!isValid) {
-                                //make a valid group
-                                var lastGroupSeparator = bufferStr.lastIndexOf(opts.groupSeparator);
-                                for (var i = bufferStr.length - lastGroupSeparator; i <= 3; i++) {
-                                    bufferStr += "0";
-                                }
-
-                                isValid = opts.regex.number(iopts).test(bufferStr);
-                                if (!isValid && !strict) {
-                                    if (chrs == opts.radixPoint) {
-                                        isValid = opts.regex.number(iopts).test("0" + bufferStr + "0");
-                                        if (isValid) {
-                                            buffer[pos] = "0";
-                                            pos++;
-                                            return { "pos": pos };
-                                        }
-                                    }
-                                }
-                            }
-                        }
-
-                        if (isValid != false && !strict && chrs != opts.radixPoint) {
-                            var newPos = opts.postFormat(buffer, pos, (chrs == "-" || chrs == "+") ? true : false, opts);
-                            return { "pos": newPos, "refreshFromBuffer": true };
-                        }
-
-                        return isValid;
-                    },
-                    cardinality: 1,
-                    prevalidator: null
-                }
-            },
-            insertMode: true,
-            autoUnmask: false
+            alias: "numeric"
         },
         'integer': {
-            regex: {
-                number: function (opts) {
-                    var escapedGroupSeparator = $.inputmask.escapeRegex.call(this, opts.groupSeparator);
-                    var signedExpression = opts.allowPlus || opts.allowMinus ? "[" + (opts.allowPlus ? "\+" : "") + (opts.allowMinus ? "-" : "") + "]?" : "";
-                    return new RegExp("^" + signedExpression + "(\\d+|\\d{1," + opts.groupSize + "}((" + escapedGroupSeparator + "\\d{" + opts.groupSize + "})?)+)$");
-                }
-            },
-            alias: "decimal"
+            alias: "numeric",
+            digits: "0"
         }
     });
 })(jQuery);