You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

248 lines
6.2 KiB
JavaScript

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

class SmartDateFormat
{
constructor(format)
{
this._day = null;
this._month = null;
this._year = null;
this.loadFormat(format);
this._parseState = new SmartDateParseState();
}
loadFormat(format)
{
let index = 0;
let lowFormat = format.toLowerCase();
this._format = format;
this._parts = [];
while (index < format.length) {
index = this._scanPart(index, format, lowFormat);
}
}
_scanPart(index, format, lowFormat)
{
switch (lowFormat[index]) {
case SmartDateFormat.DAY_ANCHOR:
return this._scanDay(index, lowFormat);
case SmartDateFormat.MONTH_ANCHOR:
return this._scanMonth(index, lowFormat);
case SmartDateFormat.YEAR_ANCHOR:
return this._scanYear(index, lowFormat);
}
return this._scanStatic(index, format, lowFormat);
}
_scanDay(startIndex, lowFormat)
{
this._checkLastIsStatic();
this._day = new SmartDateDayPart();
this._parts.push(this._day);
return this._avoidAnchor(SmartDateFormat.DAY_ANCHOR, startIndex, lowFormat);
}
_scanMonth(startIndex, lowFormat)
{
this._checkLastIsStatic();
this._month = new SmartDateMonthPart();
this._parts.push(this._month);
return this._avoidAnchor(SmartDateFormat.MONTH_ANCHOR, startIndex, lowFormat);
}
_scanYear(startIndex, lowFormat)
{
this._checkLastIsStatic();
this._year = new SmartDateYearPart();
this._parts.push(this._year);
return this._avoidAnchor(SmartDateFormat.YEAR_ANCHOR, startIndex, lowFormat);
}
_avoidAnchor(anchor, startIndex, lowFormat)
{
let endingIndex = startIndex;
while (endingIndex < lowFormat.length && lowFormat[endingIndex] === anchor) {
endingIndex++;
}
return endingIndex;
}
_checkLastIsStatic()
{
if (this._parts.length === 0) {
return;
}
if (!this._parts[this._parts.length - 1].isStatic()) {
throw new Error('Dynamic date parts must be separated by static substrings');
}
}
_scanStatic(startIndex, format, lowFormat)
{
let endingIndex = startIndex;
while (endingIndex < format.length && this._isStaticAnchorSymbol(lowFormat[endingIndex])) {
endingIndex++;
}
this._parts.push(new SmartDateStaticPart(format.substring(startIndex, endingIndex)));
return endingIndex;
}
_isStaticAnchorSymbol(symbol)
{
return symbol !== SmartDateFormat.DAY_ANCHOR
&& symbol !== SmartDateFormat.MONTH_ANCHOR
&& symbol !== SmartDateFormat.YEAR_ANCHOR;
}
getPlaceHolder()
{
let placeHolder = '';
for (let i = 0; i < this._parts.length; i++) {
placeHolder += this._parts[i].placeHolder();
}
return placeHolder;
}
/**
* @param {Date} date
* @returns {String}
*/
formatDate(date)
{
var formattedDate = '';
for (let i = 0; i < this._parts.length; i++) {
if (this._parts[i].isStatic()) {
formattedDate += this._parts[i].placeHolder();
}
else {
formattedDate += this._parts[i].formatDate(date);
}
}
return formattedDate;
}
parse(value, autocomplete)
{
this._resetParseState();
this._parseState.start(value);
this._parseParts(autocomplete);
this._correctDate();
}
_resetParseState()
{
for (let i = 0; i < this._parts.length; i++) {
this._parts[i].resetState();
}
}
_parseParts(autocomplete)
{
let index = 0;
while (index < this._parts.length && (autocomplete || !this._parseState.isOver())) {
this._parts[index].parse(this._parseState);
if (!this._parts[index].isComplete()) {
return;
}
index++;
}
}
_correctDate()
{
if (!this._day.isComplete() || !this._month.isComplete()) {
return;
}
this._day.setMaximalValue(this._getMonthSize(this._month.numericValue() - 1, !this._year.isComplete() || this._isLeaPYear(this._year.numericValue())));
}
getParsedDate()
{
if (!this.isComplete()) {
return null;
}
return new Date(this._year.numericValue(), this._month.numericValue() - 1, this._day.numericValue());
}
_getMonthSize(monthIndex, isLeapYear)
{
if (monthIndex < 0 || monthIndex >= SmartDateMonthPart.MAXIMAL_VALUE) {
return SmartDateMonthPart.MAXIMAL_VALUE;
}
if (monthIndex === 1 && isLeapYear) { // February
return SmartDateFormat.BASIC_MONTH_SIZES[monthIndex] + 1;
}
return SmartDateFormat.BASIC_MONTH_SIZES[monthIndex];
}
_isLeaPYear(year)
{
return year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0);
}
getCorrectedValue()
{
let index = 0;
let value = '';
while (index < this._parts.length && !this._parts[index].isNoState()) {
value += this._parts[index].cleanedValue();
index++;
}
return value;
}
isComplete()
{
return this._parts[this._parts.length - 1].isComplete();
}
}
SmartDateFormat.DAY_ANCHOR = 'd';
SmartDateFormat.DAY_PLACEHOLDER = 'ДД';
SmartDateFormat.MONTH_ANCHOR = 'm';
SmartDateFormat.MONTH_PLACEHOLDER = 'ММ';
SmartDateFormat.YEAR_ANCHOR = 'y';
SmartDateFormat.YEAR_PLACEHOLDER = 'ГГГГ';
SmartDateFormat.BASIC_MONTH_SIZES = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];