|
|
@@ -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);
|