Browse Source

datetime enhancementrs

Robin Herbots 4 years ago
parent
commit
240dcd258a

+ 1 - 0
CHANGELOG.md

@@ -10,6 +10,7 @@
 - add casing definition option to the readme
 
 ### Updates
+- alias \\d to [0-9] in regex masks
 - clear masktemplate before submitting regardsless of the clearMaskOnLostFocus option
 
 ## [5.0.6 - 01/06/2021]

+ 1 - 1
bower.json

@@ -1,6 +1,6 @@
 {
   "name": "inputmask",
-  "version": "5.0.7-beta.9",
+  "version": "5.0.7-beta.10",
   "main": [
 	  "./index.js",
     "./css/inputmask.css"

+ 1 - 1
composer.json

@@ -1,7 +1,7 @@
 {
   "name": "robinherbots/inputmask",
   "description": "Inputmask is a javascript library which creates an input mask.  Inputmask can run against vanilla javascript, jQuery and jqlite.",
-  "version": "5.0.7-beta.9",
+  "version": "5.0.7-beta.10",
   "type": "library",
   "keywords": ["jquery", "plugins", "input", "form", "inputmask", "mask"],
   "homepage": "http://robinherbots.github.io/Inputmask",

File diff suppressed because it is too large
+ 896 - 898
dist/inputmask.js


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


File diff suppressed because it is too large
+ 785 - 787
dist/jquery.inputmask.js


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


+ 74 - 65
lib/extensions/inputmask.date.extensions.js

@@ -8,9 +8,11 @@ import Inputmask from "../inputmask";
 import keyCode from "../keycode.json";
 import escapeRegex from "../escapeRegex";
 import {seekNext} from "../positioning";
+import {getMaskTemplate} from "../validation-tests";
 
 const $ = Inputmask.dependencyLib;
-var currentYear = new Date().getFullYear(),
+let currentYear = new Date().getFullYear(),
+	useDateObject = false,
 	//supported codes for formatting
 	//http://blog.stevenlevithan.com/archives/date-time-format
 	//https://docs.microsoft.com/en-us/dotnet/standard/base-types/custom-date-and-time-format-strings?view=netframework-4.7
@@ -21,10 +23,18 @@ var currentYear = new Date().getFullYear(),
 		}], //Day of the month as digits; leading zero for single-digit days.
 		ddd: [""], //Day of the week as a three-letter abbreviation.
 		dddd: [""], //Day of the week as its full name.
-		m: ["[1-9]|1[012]", Date.prototype.setMonth, "month", function () {
+		m: ["[1-9]|1[012]", function (val) {
+			let mval = val ? parseInt(val) : 0;
+			if (mval > 0) mval--;
+			return Date.prototype.setMonth.call(this, mval);
+		}, "month", function () {
 			return Date.prototype.getMonth.call(this) + 1;
 		}], //Month as digits; no leading zero for single-digit months.
-		mm: ["0[1-9]|1[012]", Date.prototype.setMonth, "month", function () {
+		mm: ["0[1-9]|1[012]", function (val) {
+			let mval = val ? parseInt(val) : 0;
+			if (mval > 0) mval--;
+			return Date.prototype.setMonth.call(this, mval);
+		}, "month", function () {
 			return pad(Date.prototype.getMonth.call(this) + 1, 2);
 		}], //Month as digits; leading zero for single-digit months.
 		mmm: [""], //Month as a three-letter abbreviation.
@@ -157,6 +167,7 @@ function prefillYear(dateParts, currentResult, opts) {
 }
 
 function isValidDate(dateParts, currentResult, opts) {
+	if (!useDateObject) return true;
 	if (dateParts.rawday === undefined
 		|| (!isFinite(dateParts.rawday) && new Date(dateParts.date.getFullYear(), isFinite(dateParts.rawmonth) ? dateParts.month : dateParts.date.getMonth() + 1, 0).getDate() >= dateParts.day)
 		|| (dateParts.day == "29" && !Number.isFinite(dateParts.rawyear))
@@ -183,63 +194,46 @@ function isValidDate(dateParts, currentResult, opts) {
 
 function isDateInRange(dateParts, result, opts, maskset, fromCheckval) {
 	if (!result) return result;
-	if (opts.min) {
-		if (dateParts["rawyear"]) {
-			var rawYear = dateParts["rawyear"].replace(/[^0-9]/g, ""),
-				minYear = opts.min.year.substr(0, rawYear.length), maxYear;
-			if (rawYear < minYear) { //is out of range?
-				var tokenMatch = getTokenMatch(result.pos, opts);
-				rawYear = dateParts["rawyear"].substr(0, (result.pos - tokenMatch.targetMatchIndex) + 1).replace(/[^0-9]/g, "0");
-				minYear = opts.min.year.substr(0, rawYear.length);
-				if (minYear <= rawYear) { //this can match
-					result.remove = tokenMatch.targetMatchIndex + rawYear.length;
-					return result;
-				} else { //can we match the input on a next position
-					if (tokenMatch.targetMatch[0] === "yyyy") {
-						rawYear = dateParts["rawyear"].substr(1, 1);
-					} else {
-						rawYear = dateParts["rawyear"].substr(0, 1);
-					}
-					minYear = opts.min.year.substr(2, 1);
-					maxYear = opts.max ? opts.max.year.substr(2, 1) : rawYear;
-					if (rawYear.length === 1 && minYear <= rawYear && rawYear <= maxYear && fromCheckval !== true) { //this can match
-						if (tokenMatch.targetMatch[0] === "yyyy") {
-							result.insert = [{
-								pos: result.pos + 1, c: rawYear, strict: true
-							}];
-							result.caret = result.pos + 2;
-							maskset.validPositions[result.pos].input = opts.min.year[1];  //postval ~ position is already validated
-						} else {
-							result.insert = [{
-								pos: result.pos + 1, c: opts.min.year[1], strict: true
-							}, {
-								pos: result.pos + 2, c: rawYear, strict: true
-							}];
-							result.caret = result.pos + 3;
-							maskset.validPositions[result.pos].input = opts.min.year[0];  //postval ~ position is already validated
+	if (result && opts.min) {
+		if (useDateObject && (dateParts["year"] === undefined || dateParts["yearSet"]) && opts.min.date.getTime() === opts.min.date.getTime()) {
+			let match = getTokenMatch(result.pos || 0, opts).targetMatch, offset = 0;
+			getTokenizer(opts).lastIndex = match.index;
+			do {
+				var fcode;
+				if ((fcode = formatcode(match))) {
+					if (fcode[3]) {
+						var setFn = fcode[1];
+						var current = dateParts[fcode[2]],
+							minVal = opts.min[fcode[2]],
+							maxVal = opts.max ? opts.max[fcode[2]] : minVal,
+							curVal = [];
+
+						let forceCurrentValue = false;
+						for (let i = 0; i < current.length; i++) {
+							if (maskset.validPositions[i + match.index - offset] === undefined && !forceCurrentValue) {
+								curVal[i] = minVal[i];
+								// ADD +1 to whoile
+								if (fcode[2] === "year" && current.length - 1 == i && minVal != maxVal)
+									curVal = (parseInt(curVal.join("")) + 1).toString().split("");
+							} else {
+								curVal[i] = current[i];
+								forceCurrentValue = forceCurrentValue || current[i] > minVal[i];
+							}
 						}
-						return result;
-					}
-					result = false;
-				}
-			}
-		}
-
-		for (var dpp in dateParts) {
-			if (dpp.indexOf("raw") === -1 && dateParts[`raw${dpp}`] && dateParts[dpp] !== dateParts[`raw${dpp}`]) {
-				//console.log(dpp + " copy value from minvalue");
-			}
-		}
 
-		if (result && dateParts["year"] && dateParts["year"] === dateParts["rawyear"]) {
-			if (opts.min.date.getTime() === opts.min.date.getTime()) {
-				result = opts.min.date.getTime() <= dateParts.date.getTime();
-			}
+						setFn.call(dateParts.date, curVal.join(""));
+						offset = 0;
+					}
+				} else offset++;
+			} while ((match = getTokenizer(opts).exec(opts.inputFormat)));
+			result = opts.min.date.getTime() <= dateParts.date.getTime();
 		}
 	}
 
-	if (result && opts.max && opts.max.date.getTime() === opts.max.date.getTime()) {
-		result = opts.max.date.getTime() >= dateParts.date.getTime();
+	if (result && opts.max) {
+		if (useDateObject && opts.max.date.getTime() === opts.max.date.getTime()) {
+			result = opts.max.date.getTime() >= dateParts.date.getTime();
+		}
 	}
 	return result;
 }
@@ -295,7 +289,7 @@ function pad(val, len, right) {
 function analyseMask(maskString, format, opts) {
 	var dateObj = {"date": new Date(1, 0, 1)}, targetProp, mask = maskString, match, dateOperation;
 
-	function setValue(dateObj, value, opts) {
+	function setValue(dateObj, value, fcode, opts) {
 		dateObj[targetProp] = targetProp === "ampm" ? value : value.replace(/[^0-9]/g, "0");
 		dateObj["raw" + targetProp] = value;
 
@@ -307,12 +301,19 @@ function analyseMask(maskString, format, opts) {
 					dateObj.date.setFullYear(2012, 1, 29);
 				}
 			}
-			if (targetProp === "day" && parseInt(datavalue) === 0)
-				datavalue = 1;
-			if (targetProp === "month" && (datavalue = parseInt(datavalue), datavalue > 0))
-				datavalue -= 1;
-			if (targetProp === "year" && datavalue.length < 4)
-				datavalue = pad(datavalue, 4, true);
+			if (targetProp === "day") {
+				useDateObject = true;
+				if (parseInt(datavalue) === 0)
+					datavalue = 1;
+			}
+			if (targetProp === "month")
+				useDateObject = true;
+			if (targetProp === "year") {
+				useDateObject = true;
+				dateObj["yearSet"] = value != fcode;
+				if (datavalue.length < 4)
+					datavalue = pad(datavalue, 4, true);
+			}
 			if (datavalue !== "" && !isNaN(datavalue)) dateOperation.call(dateObj.date, datavalue);
 			if (targetProp === "ampm")
 				dateOperation.call(dateObj.date, datavalue);
@@ -338,7 +339,7 @@ function analyseMask(maskString, format, opts) {
 				// targetValidator = formatCode[match[0]][0];
 				targetProp = formatCode[fcode][2];
 				dateOperation = formatCode[fcode][1];
-				setValue(dateObj, value, opts);
+				setValue(dateObj, value, fcode, opts);
 			}
 			mask = mask.slice(value.length);
 		}
@@ -361,7 +362,7 @@ function getTokenMatch(pos, opts) {
 		var dynMatches = new RegExp("\\d+$").exec(match[0]);
 		matchLength = dynMatches ? parseInt(dynMatches[0]) : match[0].length;
 		calcPos += matchLength;
-		if (calcPos >= pos) {
+		if (calcPos >= pos + 1) {
 			targetMatch = match;
 			match = getTokenizer(opts).exec(opts.inputFormat);
 			break;
@@ -477,11 +478,19 @@ Inputmask.extendAliases({
 			//full validate target
 			tokenMatch = getTokenMatch(pos, opts);
 			if (tokenMatch.targetMatch && tokenMatch.targetMatch[0] && formatCode[tokenMatch.targetMatch[0]] !== undefined) {
-				validator = formatCode[tokenMatch.targetMatch[0]][0];
+				let fcode = formatCode[tokenMatch.targetMatch[0]];
+				validator = fcode[0];
 				var part = buffer.slice(tokenMatch.targetMatchIndex, tokenMatch.targetMatchIndex + tokenMatch.targetMatch[0].length);
 				if (new RegExp(validator).test(part.join("")) === false && tokenMatch.targetMatch[0].length === 2 && maskset.validPositions[tokenMatch.targetMatchIndex] && maskset.validPositions[tokenMatch.targetMatchIndex + 1]) {
 					maskset.validPositions[tokenMatch.targetMatchIndex + 1].input = "0";
 				}
+				if (fcode[2] == "year") {
+					var _buffer = getMaskTemplate.call(inputmask, false, 1, undefined, true);
+					for (let i = pos + 1; i < buffer.length; i++) {
+						buffer[i] = _buffer[i];
+						delete maskset.validPositions[i];
+					}
+				}
 			}
 
 			var result = currentResult, dateParts = analyseMask(buffer.join(""), opts.inputFormat, opts);

+ 19 - 12
lib/mask-lexer.js

@@ -318,31 +318,38 @@ function analyseMask(mask, regexMask, opts) {
 					}
 					break;
 			}
+			switch (m) {
+				case "\\d":
+					m = "[0-9]";
+					break;
+			}
 		}
 
 		if (escaped) {
 			defaultCase();
 			continue;
 		}
-		switch (m.charAt(0)) {
-			case "$":
-			case "^":
-				//ignore beginswith and endswith as in masking this makes no point
-				if (!regexMask) {
-					defaultCase();
-				}
-				break;
+		switch (m) {
 			case "(?=": //lookahead
-				openenings.push(new MaskToken(true));
+				// openenings.push(new MaskToken(true));
 				break;
 			case "(?!": //negative lookahead
-				openenings.push(new MaskToken(true));
+				// openenings.push(new MaskToken(true));
 				break;
 			case "(?<=": //lookbehind
-				openenings.push(new MaskToken(true));
+				// openenings.push(new MaskToken(true));
 				break;
 			case "(?<!": //negative lookbehind
-				openenings.push(new MaskToken(true));
+				// openenings.push(new MaskToken(true));
+				break;
+		}
+		switch (m.charAt(0)) {
+			case "$":
+			case "^":
+				//ignore beginswith and endswith as in masking this makes no point
+				if (!regexMask) {
+					defaultCase();
+				}
 				break;
 			case opts.escapeChar:
 				escaped = true;

+ 1 - 1
lib/validation.js

@@ -14,7 +14,7 @@ import {
 	isMask,
 	resetMaskSet,
 	seekNext,
-	seekPrevious, translatePosition
+	seekPrevious
 } from "./positioning";
 import {EventHandlers} from "./eventhandlers";
 

File diff suppressed because it is too large
+ 6691 - 758
package-lock.json


+ 8 - 8
package.json

@@ -1,6 +1,6 @@
 {
   "name": "inputmask",
-  "version": "5.0.7-beta.9",
+  "version": "5.0.7-beta.10",
   "description": "Inputmask is a javascript library which creates an input mask.  Inputmask can run against vanilla javascript, jQuery and jqlite.",
   "main": "dist/inputmask.js",
   "files": [
@@ -36,10 +36,10 @@
   },
   "homepage": "https://github.com/RobinHerbots/Inputmask",
   "devDependencies": {
-    "@babel/core": "^7.14.3",
-    "@babel/plugin-transform-modules-commonjs": "^7.14.0",
-    "@babel/preset-env": "^7.14.4",
-    "@babel/preset-typescript": "7.13.0",
+    "@babel/core": "^7.15.0",
+    "@babel/plugin-transform-modules-commonjs": "^7.15.0",
+    "@babel/preset-env": "^7.15.0",
+    "@babel/preset-typescript": "7.15.0",
     "@robinherbots/grunt-available-tasks": "^0.6.4",
     "@robinherbots/grunt-nuget": "^0.3.2",
     "babel-loader": "^8.2.2",
@@ -53,8 +53,8 @@
     "jquery": "^3.6.0",
     "load-grunt-tasks": "^5.1.0",
     "lodash": "^4.17.21",
-    "qunit": "^2.15.0",
-    "webpack": "^5.38.1",
-    "webpack-cli": "^4.7.0"
+    "qunit": "^2.16.0",
+    "webpack": "^5.51.1",
+    "webpack-cli": "^4.8.0"
   }
 }

+ 17 - 0
qunit/tests_date.js

@@ -1104,4 +1104,21 @@ export default function (qunit, Inputmask) {
 
 		assert.equal(testmask.value, "02/29/2012", "Result " + testmask.value);
 	});
+
+	qunit.test("H2:MM min 12:59- #2297", function (assert) {
+		var $fixture = $("#qunit-fixture");
+		$fixture.append("<input type=\"text\" id=\"testmask\" />");
+		var testmask = document.getElementById("testmask");
+		Inputmask("datetime", {
+			inputFormat: "H2:MM",
+			placeholder: "0",
+			min: "12:59",
+			max: "33:33"
+		}).mask(testmask);
+
+		testmask.focus();
+		$("#testmask").Type("12:44");
+
+		assert.equal(testmask.value, "12:00", "Result " + testmask.value);
+	});
 }

+ 2 - 2
webpack.config.js

@@ -1,5 +1,5 @@
 var webpack = require("webpack"),
-    terserPlugin = require("terser-webpack-plugin"),
+	terserPlugin = require("terser-webpack-plugin"),
 	_ = require("lodash"),
 	fs = require("fs");
 
@@ -95,7 +95,7 @@ module.exports = function (env, argv) {
 			extensions: [".wasm", ".mjs", ".js", ".ts", ".json"],
 			alias: {
 				// "./dependencyLibs/inputmask.dependencyLib": "./dependencyLibs/inputmask.dependencyLib.jquery"
-			}
+			},
 		},
 		devtool: env === "production" ? undefined : "source-map",
 		plugins: [