|
|
@@ -20,36 +20,58 @@
|
|
|
var //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
|
|
|
- formatCode = {
|
|
|
- d: "[1-9]|[12][0-9]|3[01]", //Day of the month as digits; no leading zero for single-digit days.
|
|
|
- dd: "0[1-9]|[12][0-9]|3[01]", //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]", //Month as digits; no leading zero for single-digit months.
|
|
|
- mm: "0[1-9]|1[012]", //Month as digits; leading zero for single-digit months.
|
|
|
- mmm: "", //Month as a three-letter abbreviation.
|
|
|
- mmmm: "", //Month as its full name.
|
|
|
- yy: "[0-9]{2}", //Year as last two digits; leading zero for years less than 10.
|
|
|
- yyyy: "[0-9]{4}",
|
|
|
- h: "[1-9]|1[0-2]", //Hours; no leading zero for single-digit hours (12-hour clock).
|
|
|
- hh: "0[1-9]|1[0-2]", //Hours; leading zero for single-digit hours (12-hour clock).
|
|
|
- hhh: "[0-9]+", //Hours; no limit
|
|
|
- H: "1?[1-9]|2[0-3]", //Hours; no leading zero for single-digit hours (24-hour clock).
|
|
|
- HH: "[01][1-9]|2[0-3]", //Hours; leading zero for single-digit hours (24-hour clock).
|
|
|
- HHH: "[0-9]+", //Hours; no limit
|
|
|
- M: "[1-5]?[0-9]", //Minutes; no leading zero for single-digit minutes. Uppercase M unlike CF timeFormat's m to avoid conflict with months.
|
|
|
- MM: "[0-5][0-9]", //Minutes; leading zero for single-digit minutes. Uppercase MM unlike CF timeFormat's mm to avoid conflict with months.
|
|
|
- s: "[1-5]?[0-9]", //Seconds; no leading zero for single-digit seconds.
|
|
|
- ss: "[0-5][0-9]", //Seconds; leading zero for single-digit seconds.
|
|
|
- l: "", //Milliseconds. 3 digits.
|
|
|
- L: "", //Milliseconds. 2 digits.
|
|
|
- t: "", //Lowercase, single-character time marker string: a or p.
|
|
|
- tt: "", //two-character time marker string: am or pm.
|
|
|
- T: "", //single-character time marker string: A or P.
|
|
|
- TT: "", //two-character time marker string: AM or PM.
|
|
|
- Z: "", //US timezone abbreviation, e.g. EST or MDT. With non-US timezones or in the Opera browser, the GMT/UTC offset is returned, e.g. GMT-0500
|
|
|
- o: "", //GMT/UTC timezone offset, e.g. -0500 or +0230.
|
|
|
- S: "" //The date's ordinal suffix (st, nd, rd, or th). Works well with d.
|
|
|
+ formatCode = { //regex, valueSetter, type, displayformatter
|
|
|
+ d: ["[1-9]|[12][0-9]|3[01]", Date.prototype.setDate, "day", Date.prototype.getDate], //Day of the month as digits; no leading zero for single-digit days.
|
|
|
+ dd: ["0[1-9]|[12][0-9]|3[01]", Date.prototype.setDate, "day", function () {
|
|
|
+ return pad(Date.prototype.getDate.call(this), 2);
|
|
|
+ }], //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 () {
|
|
|
+ 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 () {
|
|
|
+ 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.
|
|
|
+ mmmm: [""], //Month as its full name.
|
|
|
+ yy: ["[0-9]{2}", Date.prototype.setFullYear, "year", function () {
|
|
|
+ return pad(Date.prototype.getFullYear.call(this), 2);
|
|
|
+ }], //Year as last two digits; leading zero for years less than 10.
|
|
|
+ yyyy: ["[0-9]{4}", Date.prototype.setFullYear, "year", function () {
|
|
|
+ return pad(Date.prototype.getFullYear.call(this), 4);
|
|
|
+ }],
|
|
|
+ h: ["[1-9]|1[0-2]", Date.prototype.setHours, "hours", Date.prototype.getHours], //Hours; no leading zero for single-digit hours (12-hour clock).
|
|
|
+ hh: ["0[1-9]|1[0-2]", Date.prototype.setHours, "hours", function () {
|
|
|
+ return pad(Date.prototype.getHours.call(this), 2);
|
|
|
+ }], //Hours; leading zero for single-digit hours (12-hour clock).
|
|
|
+ hhh: ["[0-9]+", Date.prototype.setHours, "hours", Date.prototype.getHours], //Hours; no limit
|
|
|
+ H: ["1?[1-9]|2[0-3]", Date.prototype.setHours, "hours", Date.prototype.getHours], //Hours; no leading zero for single-digit hours (24-hour clock).
|
|
|
+ HH: ["[01][1-9]|2[0-3]", Date.prototype.setHours, "hours", function () {
|
|
|
+ return pad(Date.prototype.getHours.call(this), 2);
|
|
|
+ }], //Hours; leading zero for single-digit hours (24-hour clock).
|
|
|
+ HHH: ["[0-9]+", Date.prototype.setHours, "hours", Date.prototype.getHours], //Hours; no limit
|
|
|
+ M: ["[1-5]?[0-9]", Date.prototype.setMinutes, "minutes", Date.prototype.getMinutes], //Minutes; no leading zero for single-digit minutes. Uppercase M unlike CF timeFormat's m to avoid conflict with months.
|
|
|
+ MM: ["[0-5][0-9]", Date.prototype.setMinutes, "minutes", function () {
|
|
|
+ return pad(Date.prototype.getMinutes.call(this), 2);
|
|
|
+ }], //Minutes; leading zero for single-digit minutes. Uppercase MM unlike CF timeFormat's mm to avoid conflict with months.
|
|
|
+ s: ["[1-5]?[0-9]", Date.prototype.setSeconds, "seconds", Date.prototype.getSeconds], //Seconds; no leading zero for single-digit seconds.
|
|
|
+ ss: ["[0-5][0-9]", Date.prototype.setSeconds, "seconds", function () {
|
|
|
+ return pad(Date.prototype.getSeconds.call(this), 2);
|
|
|
+ }], //Seconds; leading zero for single-digit seconds.
|
|
|
+ l: ["[0-9]{3}", Date.prototype.setMilliseconds, "milliseconds", function () {
|
|
|
+ return pad(Date.prototype.getMilliseconds.call(this), 3);
|
|
|
+ }], //Milliseconds. 3 digits.
|
|
|
+ L: ["[0-9]{2}", Date.prototype.setMilliseconds, "milliseconds", function () {
|
|
|
+ return pad(Date.prototype.getMilliseconds.call(this), 2);
|
|
|
+ }], //Milliseconds. 2 digits.
|
|
|
+ t: [""], //Lowercase, single-character time marker string: a or p.
|
|
|
+ tt: [""], //two-character time marker string: am or pm.
|
|
|
+ T: [""], //single-character time marker string: A or P.
|
|
|
+ TT: [""], //two-character time marker string: AM or PM.
|
|
|
+ Z: [""], //US timezone abbreviation, e.g. EST or MDT. With non-US timezones or in the Opera browser, the GMT/UTC offset is returned, e.g. GMT-0500
|
|
|
+ o: [""], //GMT/UTC timezone offset, e.g. -0500 or +0230.
|
|
|
+ S: [""] //The date's ordinal suffix (st, nd, rd, or th). Works well with d.
|
|
|
},
|
|
|
formatAlias = {
|
|
|
isoDate: "yyyy-mm-dd", //2007-06-09
|
|
|
@@ -60,10 +82,12 @@
|
|
|
|
|
|
function getTokenizer(opts) {
|
|
|
if (!opts.tokenizer) {
|
|
|
- opts.tokenizer = "(" + $.map(formatCode, function (lmnt, ndx) {
|
|
|
- return ndx;
|
|
|
- }).join("|") + ")+|.";
|
|
|
-
|
|
|
+ var tokens = [];
|
|
|
+ for (var ndx in formatCode) {
|
|
|
+ if (tokens.indexOf(ndx[0]) === -1)
|
|
|
+ tokens.push(ndx[0]);
|
|
|
+ }
|
|
|
+ opts.tokenizer = "(" + tokens.join("+|") + ")+?|.";
|
|
|
opts.tokenizer = new RegExp(opts.tokenizer, "g");
|
|
|
}
|
|
|
|
|
|
@@ -88,16 +112,36 @@
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
- function parse(format, opts) {
|
|
|
+ //parse the given format and return a mask pattern
|
|
|
+ //when a dateObjValue is passed a datestring in the requested format is returned
|
|
|
+ function parse(format, dateObjValue, opts) {
|
|
|
//parse format to regex string
|
|
|
var mask = "", match;
|
|
|
while (match = getTokenizer(opts).exec(format)) {
|
|
|
- mask += formatCode[match[0]] ? "(" + ($.isFunction(formatCode[match[0]]) ? formatCode[match[0]](opts.min, opts.max) : formatCode[match[0]]) + ")" : match[0];
|
|
|
+ if (dateObjValue === undefined)
|
|
|
+ mask += formatCode[match[0]] ? "(" + formatCode[match[0]][0] + ")" : match[0];
|
|
|
+ else {
|
|
|
+ if (formatCode[match[0]]) {
|
|
|
+ var getFn = formatCode[match[0]][3];
|
|
|
+ mask += getFn.call(dateObjValue.date);
|
|
|
+ }
|
|
|
+ else mask += match[0];
|
|
|
+ }
|
|
|
}
|
|
|
return mask;
|
|
|
}
|
|
|
|
|
|
+ //padding function
|
|
|
+ function pad(val, len) {
|
|
|
+ val = String(val);
|
|
|
+ len = len || 2;
|
|
|
+ while (val.length < len) val = "0" + val;
|
|
|
+ return val;
|
|
|
+ }
|
|
|
+
|
|
|
function analyseMask(maskString, format, opts) {
|
|
|
+ var dateObj = {"date": new Date(1, 0, 1)}, targetProp, mask = maskString, match, dateOperation;
|
|
|
+
|
|
|
function extendYear(year) {
|
|
|
var correctedyear = year.length === 4 ? year : new Date().getFullYear().toString().substr(0, 4 - year.length) + year;
|
|
|
if (opts.min && opts.min.year && opts.max && opts.max.year) {
|
|
|
@@ -107,7 +151,7 @@
|
|
|
return correctedyear;
|
|
|
}
|
|
|
|
|
|
- function setValue(dateObj, value, dateOperation, opts) {
|
|
|
+ function setValue(dateObj, value, opts) {
|
|
|
if (targetProp === "year") {
|
|
|
dateObj[targetProp] = extendYear(value);
|
|
|
dateObj["raw" + targetProp] = value;
|
|
|
@@ -118,40 +162,17 @@
|
|
|
dateOperation.call(dateObj.date, targetProp == "month" ? parseInt(dateObj[targetProp]) - 1 : dateObj[targetProp]);
|
|
|
}
|
|
|
|
|
|
- var dateObj = {"date": new Date(1, 0, 1)}, targetProp, mask = maskString, match, dateOperation;
|
|
|
if (typeof mask === "string") {
|
|
|
while (match = getTokenizer(opts).exec(format)) {
|
|
|
- if (match[0].charAt(0) === "d") {
|
|
|
- targetProp = "day";
|
|
|
- dateOperation = Date.prototype.setDate;
|
|
|
- } else if (match[0].charAt(0) === "m") {
|
|
|
- targetProp = "month";
|
|
|
- dateOperation = Date.prototype.setMonth;
|
|
|
- } else if (match[0].charAt(0) === "y") {
|
|
|
- targetProp = "year";
|
|
|
- dateOperation = Date.prototype.setFullYear;
|
|
|
- } else if (match[0].charAt(0).toLowerCase() === "h") {
|
|
|
- targetProp = "hour";
|
|
|
- dateOperation = Date.prototype.setHours;
|
|
|
- } else if (match[0].charAt(0) === "M") {
|
|
|
- targetProp = "minutes";
|
|
|
- dateOperation = Date.prototype.setMinutes;
|
|
|
- } else if (match[0].charAt(0) === "s") {
|
|
|
- targetProp = "seconds";
|
|
|
- dateOperation = Date.prototype.setSeconds;
|
|
|
- } else if (formatCode.hasOwnProperty(match[0])) {
|
|
|
- targetProp = "unmatched";
|
|
|
- dateOperation = undefined
|
|
|
- } else { //separator
|
|
|
- var value = mask.split(match[0])[0];
|
|
|
- setValue(dateObj, value, dateOperation, opts);
|
|
|
- mask = mask.slice((value + match[0]).length);
|
|
|
- targetProp = undefined;
|
|
|
+ var value = mask.slice(0, match[0].length);
|
|
|
+ if (formatCode.hasOwnProperty(match[0])) {
|
|
|
+ targetProp = formatCode[match[0]][2];
|
|
|
+ dateOperation = formatCode[match[0]][1];
|
|
|
+ setValue(dateObj, value, opts);
|
|
|
}
|
|
|
+ mask = mask.slice(value.length);
|
|
|
}
|
|
|
- if (targetProp !== undefined) {
|
|
|
- setValue(dateObj, mask, dateOperation, opts);
|
|
|
- }
|
|
|
+
|
|
|
return dateObj;
|
|
|
}
|
|
|
return undefined;
|
|
|
@@ -166,7 +187,7 @@
|
|
|
opts.placeholder = opts.placeholder !== Inputmask.prototype.defaults.placeholder ? opts.placeholder : opts.inputFormat;
|
|
|
opts.min = analyseMask(opts.min, opts.inputFormat, opts);
|
|
|
opts.max = analyseMask(opts.max, opts.inputFormat, opts);
|
|
|
- opts.regex = parse(opts.inputFormat, opts);
|
|
|
+ opts.regex = parse(opts.inputFormat, undefined, opts);
|
|
|
// console.log(opts.regex);
|
|
|
return null; //migrate to regex mask
|
|
|
},
|
|
|
@@ -174,7 +195,18 @@
|
|
|
displayFormat: undefined, //visual format when the input looses focus
|
|
|
outputFormat: undefined, //unmasking format
|
|
|
min: null, //needs to be in the same format as the inputfornat
|
|
|
- max: null, //needs to be in the same format as the inputfornat
|
|
|
+ max: null, //needs to be in the same format as the inputfornat,
|
|
|
+ // Internationalization strings
|
|
|
+ i18n: {
|
|
|
+ dayNames: [
|
|
|
+ "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun",
|
|
|
+ "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"
|
|
|
+ ],
|
|
|
+ monthNames: [
|
|
|
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
|
|
|
+ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"
|
|
|
+ ]
|
|
|
+ },
|
|
|
postValidation: function (buffer, currentResult, opts) {
|
|
|
var result = currentResult, dateParts = analyseMask(buffer.join(""), opts.inputFormat, opts);
|
|
|
if (result && dateParts.date.getTime() === dateParts.date.getTime()) { //check for a valid date ~ an invalid date returns NaN which isn't equal
|
|
|
@@ -205,6 +237,9 @@
|
|
|
$(input).trigger("setvalue");
|
|
|
}
|
|
|
},
|
|
|
+ onUnMask: function (maskedValue, unmaskedValue, opts) {
|
|
|
+ return parse(opts.outputFormat, analyseMask(maskedValue, opts.inputFormat, opts), opts);
|
|
|
+ },
|
|
|
insertMode: false
|
|
|
}
|
|
|
});
|