+Фильтр для поля для ввода корректных дат
This commit is contained in:
3899
bootstrap/css/bootstrap-grid.css
vendored
Normal file
3899
bootstrap/css/bootstrap-grid.css
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
bootstrap/css/bootstrap-grid.css.map
Normal file
1
bootstrap/css/bootstrap-grid.css.map
Normal file
File diff suppressed because one or more lines are too long
7
bootstrap/css/bootstrap-grid.min.css
vendored
Normal file
7
bootstrap/css/bootstrap-grid.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
1
bootstrap/css/bootstrap-grid.min.css.map
Normal file
1
bootstrap/css/bootstrap-grid.min.css.map
Normal file
File diff suppressed because one or more lines are too long
327
bootstrap/css/bootstrap-reboot.css
vendored
Normal file
327
bootstrap/css/bootstrap-reboot.css
vendored
Normal file
@@ -0,0 +1,327 @@
|
||||
/*!
|
||||
* Bootstrap Reboot v4.4.1 (https://getbootstrap.com/)
|
||||
* Copyright 2011-2019 The Bootstrap Authors
|
||||
* Copyright 2011-2019 Twitter, Inc.
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
||||
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
|
||||
*/
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html {
|
||||
font-family: sans-serif;
|
||||
line-height: 1.15;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
article, aside, figcaption, figure, footer, header, hgroup, main, nav, section {
|
||||
display: block;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
||||
font-size: 1rem;
|
||||
font-weight: 400;
|
||||
line-height: 1.5;
|
||||
color: #212529;
|
||||
text-align: left;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
[tabindex="-1"]:focus:not(:focus-visible) {
|
||||
outline: 0 !important;
|
||||
}
|
||||
|
||||
hr {
|
||||
box-sizing: content-box;
|
||||
height: 0;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
abbr[title],
|
||||
abbr[data-original-title] {
|
||||
text-decoration: underline;
|
||||
-webkit-text-decoration: underline dotted;
|
||||
text-decoration: underline dotted;
|
||||
cursor: help;
|
||||
border-bottom: 0;
|
||||
-webkit-text-decoration-skip-ink: none;
|
||||
text-decoration-skip-ink: none;
|
||||
}
|
||||
|
||||
address {
|
||||
margin-bottom: 1rem;
|
||||
font-style: normal;
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
ol,
|
||||
ul,
|
||||
dl {
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
ol ol,
|
||||
ul ul,
|
||||
ol ul,
|
||||
ul ol {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
dt {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
dd {
|
||||
margin-bottom: .5rem;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
margin: 0 0 1rem;
|
||||
}
|
||||
|
||||
b,
|
||||
strong {
|
||||
font-weight: bolder;
|
||||
}
|
||||
|
||||
small {
|
||||
font-size: 80%;
|
||||
}
|
||||
|
||||
sub,
|
||||
sup {
|
||||
position: relative;
|
||||
font-size: 75%;
|
||||
line-height: 0;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
sub {
|
||||
bottom: -.25em;
|
||||
}
|
||||
|
||||
sup {
|
||||
top: -.5em;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #007bff;
|
||||
text-decoration: none;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: #0056b3;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
a:not([href]) {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:not([href]):hover {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
pre,
|
||||
code,
|
||||
kbd,
|
||||
samp {
|
||||
font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
pre {
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
figure {
|
||||
margin: 0 0 1rem;
|
||||
}
|
||||
|
||||
img {
|
||||
vertical-align: middle;
|
||||
border-style: none;
|
||||
}
|
||||
|
||||
svg {
|
||||
overflow: hidden;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
caption {
|
||||
padding-top: 0.75rem;
|
||||
padding-bottom: 0.75rem;
|
||||
color: #6c757d;
|
||||
text-align: left;
|
||||
caption-side: bottom;
|
||||
}
|
||||
|
||||
th {
|
||||
text-align: inherit;
|
||||
}
|
||||
|
||||
label {
|
||||
display: inline-block;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
button {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
button:focus {
|
||||
outline: 1px dotted;
|
||||
outline: 5px auto -webkit-focus-ring-color;
|
||||
}
|
||||
|
||||
input,
|
||||
button,
|
||||
select,
|
||||
optgroup,
|
||||
textarea {
|
||||
margin: 0;
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
button,
|
||||
input {
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
button,
|
||||
select {
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
select {
|
||||
word-wrap: normal;
|
||||
}
|
||||
|
||||
button,
|
||||
[type="button"],
|
||||
[type="reset"],
|
||||
[type="submit"] {
|
||||
-webkit-appearance: button;
|
||||
}
|
||||
|
||||
button:not(:disabled),
|
||||
[type="button"]:not(:disabled),
|
||||
[type="reset"]:not(:disabled),
|
||||
[type="submit"]:not(:disabled) {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
button::-moz-focus-inner,
|
||||
[type="button"]::-moz-focus-inner,
|
||||
[type="reset"]::-moz-focus-inner,
|
||||
[type="submit"]::-moz-focus-inner {
|
||||
padding: 0;
|
||||
border-style: none;
|
||||
}
|
||||
|
||||
input[type="radio"],
|
||||
input[type="checkbox"] {
|
||||
box-sizing: border-box;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
input[type="date"],
|
||||
input[type="time"],
|
||||
input[type="datetime-local"],
|
||||
input[type="month"] {
|
||||
-webkit-appearance: listbox;
|
||||
}
|
||||
|
||||
textarea {
|
||||
overflow: auto;
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
fieldset {
|
||||
min-width: 0;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
legend {
|
||||
display: block;
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
padding: 0;
|
||||
margin-bottom: .5rem;
|
||||
font-size: 1.5rem;
|
||||
line-height: inherit;
|
||||
color: inherit;
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
progress {
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
[type="number"]::-webkit-inner-spin-button,
|
||||
[type="number"]::-webkit-outer-spin-button {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
[type="search"] {
|
||||
outline-offset: -2px;
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
[type="search"]::-webkit-search-decoration {
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
::-webkit-file-upload-button {
|
||||
font: inherit;
|
||||
-webkit-appearance: button;
|
||||
}
|
||||
|
||||
output {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
summary {
|
||||
display: list-item;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
template {
|
||||
display: none;
|
||||
}
|
||||
|
||||
[hidden] {
|
||||
display: none !important;
|
||||
}
|
||||
/*# sourceMappingURL=bootstrap-reboot.css.map */
|
1
bootstrap/css/bootstrap-reboot.css.map
Normal file
1
bootstrap/css/bootstrap-reboot.css.map
Normal file
File diff suppressed because one or more lines are too long
8
bootstrap/css/bootstrap-reboot.min.css
vendored
Normal file
8
bootstrap/css/bootstrap-reboot.min.css
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
/*!
|
||||
* Bootstrap Reboot v4.4.1 (https://getbootstrap.com/)
|
||||
* Copyright 2011-2019 The Bootstrap Authors
|
||||
* Copyright 2011-2019 Twitter, Inc.
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
||||
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
|
||||
*/*,::after,::before{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}article,aside,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:left;background-color:#fff}[tabindex="-1"]:focus:not(:focus-visible){outline:0!important}hr{box-sizing:content-box;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem}p{margin-top:0;margin-bottom:1rem}abbr[data-original-title],abbr[title]{text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;border-bottom:0;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#007bff;text-decoration:none;background-color:transparent}a:hover{color:#0056b3;text-decoration:underline}a:not([href]){color:inherit;text-decoration:none}a:not([href]):hover{color:inherit;text-decoration:none}code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:1em}pre{margin-top:0;margin-bottom:1rem;overflow:auto}figure{margin:0 0 1rem}img{vertical-align:middle;border-style:none}svg{overflow:hidden;vertical-align:middle}table{border-collapse:collapse}caption{padding-top:.75rem;padding-bottom:.75rem;color:#6c757d;text-align:left;caption-side:bottom}th{text-align:inherit}label{display:inline-block;margin-bottom:.5rem}button{border-radius:0}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,input{overflow:visible}button,select{text-transform:none}select{word-wrap:normal}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{padding:0;border-style:none}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=date],input[type=datetime-local],input[type=month],input[type=time]{-webkit-appearance:listbox}textarea{overflow:auto;resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;max-width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit;color:inherit;white-space:normal}progress{vertical-align:baseline}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:none}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}summary{display:list-item;cursor:pointer}template{display:none}[hidden]{display:none!important}
|
||||
/*# sourceMappingURL=bootstrap-reboot.min.css.map */
|
1
bootstrap/css/bootstrap-reboot.min.css.map
Normal file
1
bootstrap/css/bootstrap-reboot.min.css.map
Normal file
File diff suppressed because one or more lines are too long
10224
bootstrap/css/bootstrap.css
vendored
Normal file
10224
bootstrap/css/bootstrap.css
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
bootstrap/css/bootstrap.css.map
Normal file
1
bootstrap/css/bootstrap.css.map
Normal file
File diff suppressed because one or more lines are too long
7
bootstrap/css/bootstrap.min.css
vendored
Normal file
7
bootstrap/css/bootstrap.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
1
bootstrap/css/bootstrap.min.css.map
Normal file
1
bootstrap/css/bootstrap.min.css.map
Normal file
File diff suppressed because one or more lines are too long
7134
bootstrap/js/bootstrap.bundle.js
vendored
Normal file
7134
bootstrap/js/bootstrap.bundle.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
bootstrap/js/bootstrap.bundle.js.map
Normal file
1
bootstrap/js/bootstrap.bundle.js.map
Normal file
File diff suppressed because one or more lines are too long
7
bootstrap/js/bootstrap.bundle.min.js
vendored
Normal file
7
bootstrap/js/bootstrap.bundle.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
bootstrap/js/bootstrap.bundle.min.js.map
Normal file
1
bootstrap/js/bootstrap.bundle.min.js.map
Normal file
File diff suppressed because one or more lines are too long
4521
bootstrap/js/bootstrap.js
vendored
Normal file
4521
bootstrap/js/bootstrap.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
bootstrap/js/bootstrap.js.map
Normal file
1
bootstrap/js/bootstrap.js.map
Normal file
File diff suppressed because one or more lines are too long
7
bootstrap/js/bootstrap.min.js
vendored
Normal file
7
bootstrap/js/bootstrap.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
bootstrap/js/bootstrap.min.js.map
Normal file
1
bootstrap/js/bootstrap.min.js.map
Normal file
File diff suppressed because one or more lines are too long
9
build-es6.sh
Executable file
9
build-es6.sh
Executable file
@@ -0,0 +1,9 @@
|
||||
#!/bin/bash
|
||||
|
||||
cat /dev/null > ./es6/smart-date.js
|
||||
|
||||
for i in AbstractSmartDatePart SmartDateStaticPart AbstractSmartDateNumericPart SmartDateDayPart SmartDateMonthPart SmartDateYearPart SmartDateParseState SmartDateFormat SmartDateField; do
|
||||
|
||||
cat ./src-es6/$i.js >> ./es6/smart-date.js
|
||||
|
||||
done
|
1102
es5/smart-date.js
Normal file
1102
es5/smart-date.js
Normal file
File diff suppressed because it is too large
Load Diff
1
es5/smart-date.min.js
vendored
Normal file
1
es5/smart-date.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
997
es6/smart-date.js
Normal file
997
es6/smart-date.js
Normal file
@@ -0,0 +1,997 @@
|
||||
|
||||
class AbstractSmartDatePart
|
||||
{
|
||||
constructor(placeholder, isStatic)
|
||||
{
|
||||
this._state = AbstractSmartDatePart.STATE_NONE;
|
||||
this._cleanedValue = '';
|
||||
this._parsedValue = '';
|
||||
|
||||
this._scanned = '';
|
||||
this._placeholder = placeholder;
|
||||
this._static = isStatic;
|
||||
}
|
||||
|
||||
state()
|
||||
{
|
||||
return this._state;
|
||||
}
|
||||
|
||||
isNoState()
|
||||
{
|
||||
return this._state === AbstractSmartDatePart.STATE_NONE;
|
||||
}
|
||||
|
||||
isIncomplete()
|
||||
{
|
||||
return this._state === AbstractSmartDatePart.STATE_INCOMPLETE;
|
||||
}
|
||||
|
||||
isComplete()
|
||||
{
|
||||
return this._state === AbstractSmartDatePart.STATE_COMPLETE;
|
||||
}
|
||||
|
||||
resetState()
|
||||
{
|
||||
this._state = AbstractSmartDatePart.STATE_NONE;
|
||||
}
|
||||
|
||||
cleanedValue()
|
||||
{
|
||||
return this._cleanedValue;
|
||||
}
|
||||
|
||||
parsedValue()
|
||||
{
|
||||
return this._parsedValue;
|
||||
}
|
||||
|
||||
placeHolder()
|
||||
{
|
||||
return this._placeholder;
|
||||
}
|
||||
|
||||
isStatic()
|
||||
{
|
||||
return this._static;
|
||||
}
|
||||
|
||||
_isNumericSymbol(symbol)
|
||||
{
|
||||
return '0' <= symbol && symbol <= '9';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {SmartDateCheckState} state
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
check(state)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
AbstractSmartDatePart.STATE_NONE = 0;
|
||||
AbstractSmartDatePart.STATE_INCOMPLETE = 1;
|
||||
AbstractSmartDatePart.STATE_COMPLETE = 2;
|
||||
|
||||
class SmartDateStaticPart extends AbstractSmartDatePart
|
||||
{
|
||||
constructor(placeholder)
|
||||
{
|
||||
super(placeholder, true);
|
||||
this._cleanedValue = placeholder;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {SmartDateCheckState} state
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
parse(state)
|
||||
{
|
||||
let value = state.value();
|
||||
let index = state.valueIndex();
|
||||
|
||||
while (index < value.length && !this._isNumericSymbol(value[index])) {
|
||||
index++;
|
||||
}
|
||||
|
||||
this._parsedValue = value.substring(state.valueIndex(), index);
|
||||
this._state = AbstractSmartDatePart.STATE_COMPLETE;
|
||||
|
||||
state.setValueIndex(index);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
class AbstractSmartDateNumericPart extends AbstractSmartDatePart
|
||||
{
|
||||
constructor(placeholder, size)
|
||||
{
|
||||
super(placeholder, false);
|
||||
this._numericValue = 0;
|
||||
this._size = size;
|
||||
}
|
||||
|
||||
numericValue()
|
||||
{
|
||||
return this._numericValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Date} date
|
||||
* @returns {String}
|
||||
*/
|
||||
formatDate(date)
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
formatValue(value)
|
||||
{
|
||||
let stringValue = String(this._correctValue(value));
|
||||
|
||||
if (stringValue === '0') {
|
||||
return stringValue;
|
||||
}
|
||||
|
||||
if (stringValue.length > this._size) {
|
||||
return stringValue.substring(0, this._size);
|
||||
}
|
||||
|
||||
if (stringValue.length < this._size) {
|
||||
return stringValue.padStart(this._size, '0');
|
||||
}
|
||||
|
||||
return stringValue;
|
||||
}
|
||||
|
||||
_correctValue(value)
|
||||
{
|
||||
return Math.round(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {SmartDateCheckState} state
|
||||
* @returns {String}
|
||||
*/
|
||||
scanStringNumber(state)
|
||||
{
|
||||
let index = state.valueIndex();
|
||||
let value = state.value();
|
||||
|
||||
while (index < value.length && this._isNumericSymbol(value[index])) {
|
||||
index++;
|
||||
}
|
||||
|
||||
let stringValue = value.substring(state.valueIndex(), index);
|
||||
|
||||
state.setValueIndex(index);
|
||||
|
||||
return stringValue;
|
||||
}
|
||||
|
||||
calculateNumericValue(stringValue, maximalNumber)
|
||||
{
|
||||
var startIndex = 0;
|
||||
var endIndex = 0;
|
||||
var numericValue = 0;
|
||||
|
||||
while (startIndex < stringValue.length && stringValue[startIndex] === 0) {
|
||||
startIndex++;
|
||||
}
|
||||
|
||||
endIndex = startIndex;
|
||||
|
||||
while (endIndex < stringValue.length && numericValue < maximalNumber) {
|
||||
numericValue = numericValue * 10 + Number(stringValue[endIndex]);
|
||||
endIndex++;
|
||||
}
|
||||
|
||||
if (numericValue > maximalNumber) {
|
||||
endIndex--;
|
||||
}
|
||||
|
||||
return Number(stringValue.substring(startIndex, endIndex));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {SmartDateCheckState} state
|
||||
* @param {Number} maximalValue
|
||||
*/
|
||||
scanValue(state, maximalValue)
|
||||
{
|
||||
let index = state.valueIndex();
|
||||
let value = state.value();
|
||||
|
||||
let numericValue = 0;
|
||||
|
||||
while (index < value.length && this._isNumericSymbol(value[index]) && numericValue < maximalValue) {
|
||||
numericValue = numericValue * 10 + Number(value[index]);
|
||||
index++;
|
||||
}
|
||||
|
||||
if (numericValue > maximalValue) {
|
||||
index--;
|
||||
}
|
||||
|
||||
let stringValue = value.substring(state.valueIndex(), index);
|
||||
|
||||
state.setValueIndex(index);
|
||||
|
||||
return stringValue;
|
||||
}
|
||||
|
||||
_defineParsingState(maximalValue, isAtEnd)
|
||||
{
|
||||
if (this._numericValue > 0 && (this._parsedValue.length >= this._size || !isAtEnd)) {
|
||||
this._state = AbstractSmartDatePart.STATE_COMPLETE;
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._numericValue * 10 > maximalValue) {
|
||||
this._state = AbstractSmartDatePart.STATE_COMPLETE;
|
||||
return;
|
||||
}
|
||||
|
||||
this._state = AbstractSmartDatePart.STATE_INCOMPLETE;
|
||||
}
|
||||
|
||||
_defineCleanValue()
|
||||
{
|
||||
this._cleanedValue = '';
|
||||
|
||||
if (this.isNoState()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.isComplete()) {
|
||||
this._cleanedValue = this.formatValue(this._numericValue);
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._parsedValue.length > 0) {
|
||||
this._cleanedValue = String(this._numericValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class SmartDateDayPart extends AbstractSmartDateNumericPart
|
||||
{
|
||||
constructor()
|
||||
{
|
||||
super(SmartDateFormat.DAY_PLACEHOLDER, 2);
|
||||
this.maximalValue = SmartDateDayPart.MAXIMAL_VALUE;
|
||||
}
|
||||
|
||||
resetState()
|
||||
{
|
||||
super.resetState();
|
||||
this.maximalValue = SmartDateDayPart.MAXIMAL_VALUE;
|
||||
}
|
||||
|
||||
setMaximalValue(value)
|
||||
{
|
||||
if (value != value /* isNaN */ || value < SmartDateDayPart.MAXIMAL_VALUE_LOW_LIMIT || SmartDateDayPart.MAXIMAL_VALUE_HIGH_LIMIT < value) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.maximalValue = value;
|
||||
|
||||
if (this._numericValue <= this.maximalValue) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._numericValue = this.maximalValue;
|
||||
this._defineCleanValue();
|
||||
}
|
||||
|
||||
resetMaximalValue()
|
||||
{
|
||||
this.maximalValue = SmartDateDayPart.MAXIMAL_VALUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Date} date
|
||||
* @returns {String}
|
||||
*/
|
||||
formatDate(date)
|
||||
{
|
||||
return this.formatValue(date.getDate());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {SmartDateCheckState} state
|
||||
*/
|
||||
parse(state)
|
||||
{
|
||||
this._parsedValue = this.scanStringNumber(state);
|
||||
this._numericValue = this.calculateNumericValue(this._parsedValue, this.maximalValue);
|
||||
|
||||
this._defineParsingState(this.maximalValue, state.isOver());
|
||||
this._defineCleanValue();
|
||||
}
|
||||
}
|
||||
|
||||
SmartDateDayPart.MAXIMAL_VALUE_LOW_LIMIT = 28;
|
||||
SmartDateDayPart.MAXIMAL_VALUE_HIGH_LIMIT = 31;
|
||||
|
||||
SmartDateDayPart.MAXIMAL_VALUE = SmartDateDayPart.MAXIMAL_VALUE_HIGH_LIMIT;
|
||||
|
||||
class SmartDateMonthPart extends AbstractSmartDateNumericPart
|
||||
{
|
||||
constructor()
|
||||
{
|
||||
super(SmartDateFormat.MONTH_PLACEHOLDER, 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Date} date
|
||||
* @returns {String}
|
||||
*/
|
||||
formatDate(date)
|
||||
{
|
||||
return this.formatValue(date.getMonth() + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {SmartDateCheckState} state
|
||||
*/
|
||||
parse(state)
|
||||
{
|
||||
this._parsedValue = this.scanStringNumber(state);
|
||||
this._numericValue = this.calculateNumericValue(this._parsedValue, SmartDateMonthPart.MAXIMAL_VALUE);
|
||||
|
||||
this._defineParsingState(SmartDateMonthPart.MAXIMAL_VALUE, state.isOver());
|
||||
this._defineCleanValue();
|
||||
}
|
||||
}
|
||||
|
||||
SmartDateMonthPart.MAXIMAL_VALUE = 12;
|
||||
|
||||
class SmartDateYearPart extends AbstractSmartDateNumericPart
|
||||
{
|
||||
constructor()
|
||||
{
|
||||
super(SmartDateFormat.YEAR_PLACEHOLDER, 4);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Date} date
|
||||
* @returns {String}
|
||||
*/
|
||||
formatDate(date)
|
||||
{
|
||||
return this.formatValue(date.getFullYear());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {SmartDateCheckState} state
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
parse(state)
|
||||
{
|
||||
this._parsedValue = this.scanStringNumber(state);
|
||||
this._numericValue = Number(this._parsedValue);
|
||||
|
||||
this._defineParsingState();
|
||||
|
||||
if (this._numericValue > SmartDateYearPart.MAXIMAL_VALUE) {
|
||||
this._numericValue = SmartDateYearPart.MAXIMAL_VALUE;
|
||||
}
|
||||
|
||||
if (this.isComplete() && this._numericValue < SmartDateYearPart.MINIMAL_VALUE) {
|
||||
this._numericValue = SmartDateYearPart.MINIMAL_VALUE;
|
||||
}
|
||||
|
||||
this._defineCleanValue();
|
||||
}
|
||||
|
||||
_defineParsingState()
|
||||
{
|
||||
if (this._numericValue > 0 && this._parsedValue.length >= this._size) {
|
||||
this._state = AbstractSmartDatePart.STATE_COMPLETE;
|
||||
return;
|
||||
}
|
||||
|
||||
this._state = AbstractSmartDatePart.STATE_INCOMPLETE;
|
||||
}
|
||||
|
||||
_defineCleanValue()
|
||||
{
|
||||
if (this._numericValue > 0) {
|
||||
this._cleanedValue = String(this._numericValue);
|
||||
}
|
||||
else {
|
||||
this._cleanedValue = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SmartDateYearPart.MINIMAL_VALUE = 1000;
|
||||
SmartDateYearPart.MAXIMAL_VALUE = 9999;
|
||||
|
||||
class SmartDateParseState
|
||||
{
|
||||
constructor()
|
||||
{
|
||||
this._value = '';
|
||||
this._valueIndex = 0;
|
||||
}
|
||||
|
||||
start(value)
|
||||
{
|
||||
this._value = value;
|
||||
this._valueIndex = 0;
|
||||
}
|
||||
|
||||
current()
|
||||
{
|
||||
return this.isOver() ? '' : this._value[this._valueIndex];
|
||||
}
|
||||
|
||||
next()
|
||||
{
|
||||
if (this.isOver()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this._valueIndex++;
|
||||
|
||||
return !this.isOver();
|
||||
}
|
||||
|
||||
isOver()
|
||||
{
|
||||
return this._valueIndex >= this._value.length;
|
||||
}
|
||||
|
||||
value()
|
||||
{
|
||||
return this._value;
|
||||
}
|
||||
|
||||
valueIndex()
|
||||
{
|
||||
return this._valueIndex;
|
||||
}
|
||||
|
||||
setValueIndex(index)
|
||||
{
|
||||
if (this._valueIndex < index) {
|
||||
this._valueIndex = index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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];
|
||||
class SmartDateField
|
||||
{
|
||||
constructor(field, options)
|
||||
{
|
||||
this._dateYmdParser = new RegExp('^([0-9]{4})[,\._\/\-]+([0-9]{1,2})[,\._\/\-]+([0-9]{1,2})$');
|
||||
this._dateDmyParser = new RegExp('^([0-9]{1,2})[,\._\/\-]+([0-9]{1,2})[,\._\/\-]+([0-9]{4})$');
|
||||
|
||||
this._loadOptions(options);
|
||||
|
||||
this._formatter = new SmartDateFormat(this._format, this._minimalDate, this._maximalDate);
|
||||
|
||||
this._lastCorrectValue = (this._defaultDate === null ? null : this._formatter.formatDate(this._defaultDate));
|
||||
|
||||
this._initField(field);
|
||||
|
||||
this._subscribeEvents();
|
||||
}
|
||||
|
||||
|
||||
_loadDefaultOptions()
|
||||
{
|
||||
this._format = 'd.m.y';
|
||||
this._minimalDate = new Date(1900, 0, 1);
|
||||
this._maximalDate = new Date(2099, 11, 31);
|
||||
this._defaultDate = null;
|
||||
}
|
||||
|
||||
_loadOptions(options)
|
||||
{
|
||||
this._loadDefaultOptions();
|
||||
|
||||
if (typeof(options) !== 'object' || options == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof(options.format) === 'string'
|
||||
&& options.format.indexOf('d') >= 0
|
||||
&& options.format.indexOf('m') >= 0
|
||||
&& options.format.indexOf('y') >= 0) {
|
||||
this._format = options.format;
|
||||
}
|
||||
|
||||
if (typeof(options.minimal) !== 'undefined') {
|
||||
let date = this._parseDateValue(options.minimal);
|
||||
this._minimalDate = date;
|
||||
}
|
||||
|
||||
if (typeof(options.maximal) !== 'undefined') {
|
||||
let date = this._parseDateValue(options.maximal);
|
||||
this._maximalDate = date;
|
||||
}
|
||||
|
||||
if (typeof(options.default) !== 'undefined') {
|
||||
let date = this._parseDateValue(options.default);
|
||||
this._defaultDate = date;
|
||||
}
|
||||
|
||||
this._correctDateOptions();
|
||||
}
|
||||
|
||||
_correctDateOptions()
|
||||
{
|
||||
if (this._minimalDate.valueOf() > this._maximalDate.valueOf()) {
|
||||
let temporaryDate = this._minimalDate;
|
||||
this._minimalDate = this._maximalDate;
|
||||
this._maximalDate = temporaryDate;
|
||||
}
|
||||
|
||||
if (this._defaultDate === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._defaultDate.valueOf() < this._minimalDate.valueOf()) {
|
||||
this._defaultDate = this._minimalDate;
|
||||
}
|
||||
|
||||
if (this._defaultDate.valueOf() > this._maximalDate.valueOf()) {
|
||||
this._defaultDate = this._maximalDate;
|
||||
}
|
||||
}
|
||||
|
||||
_parseDateValue(date)
|
||||
{
|
||||
if (typeof(date) === 'object' && date !== null && date instanceof Date) {
|
||||
return date;
|
||||
}
|
||||
|
||||
if (typeof(date) !== 'string' || date.trim() === '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
let parsed = this._dateYmdParser.exec(date);
|
||||
|
||||
if (parsed !== null) {
|
||||
return new Date(Number(parsed[1]), Number(parsed[2]) - 1, Number(parsed[3]));
|
||||
}
|
||||
|
||||
parsed = this._dateDmyParser.exec(date);
|
||||
|
||||
if (parsed === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new Date(Number(parsed[3]), Number(parsed[2]) - 1, Number(parsed[1]));
|
||||
}
|
||||
|
||||
_initField(field)
|
||||
{
|
||||
this._field = field;
|
||||
this._field.placeholder = this._formatter.getPlaceHolder();
|
||||
|
||||
if (this._isEmptyValue(this._field.value)) {
|
||||
this._field.value = (this._defaultDate === null ? '' : this._formatter.formatDate(this._defaultDate));
|
||||
}
|
||||
else {
|
||||
this.correctValue(true);
|
||||
}
|
||||
}
|
||||
|
||||
_subscribeEvents()
|
||||
{
|
||||
let _this = this;
|
||||
|
||||
let correct = function (event) {
|
||||
if (event === null || event.type !== 'keyup') {
|
||||
_this.correctValue(true);
|
||||
}
|
||||
|
||||
if (_this._isServiceCode(event.keyCode)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.keyCode === 27) { // Escape
|
||||
_this.returnLastCorrectValue();
|
||||
}
|
||||
|
||||
_this.correctValue(true);
|
||||
};
|
||||
|
||||
this._field.addEventListener('change', correct);
|
||||
this._field.addEventListener('keyup', correct);
|
||||
|
||||
this._field.addEventListener('blur', function () {
|
||||
_this.correctValue(true);
|
||||
_this.returnLastCorrectValue();
|
||||
});
|
||||
}
|
||||
|
||||
_isServiceCode(code) {
|
||||
return code === 8 /* backspace */
|
||||
|| code === 46 /* delete */
|
||||
|| code === 16 /* shift */
|
||||
|| code === 17 /* shift */
|
||||
|| code === 18 /* shift */
|
||||
|| code === 20 /* caps lock */
|
||||
|| code === 35 /* end */
|
||||
|| code === 36 /* home */
|
||||
|| code === 37 /* left */
|
||||
|| code === 39 /* right */
|
||||
|| code === 46 /* delete */;
|
||||
}
|
||||
|
||||
_isEmptyValue(value)
|
||||
{
|
||||
return value.trim() === '';
|
||||
}
|
||||
|
||||
getDefaultValue()
|
||||
{
|
||||
return this._defaultDate === null ? '' : this._formatter.formatDate(this._defaultDate);
|
||||
}
|
||||
|
||||
correctValue(autocomplete)
|
||||
{
|
||||
this._formatter.parse(this._field.value, autocomplete);
|
||||
|
||||
let parsedValue = this._getLimitedParsedValue();
|
||||
|
||||
if (this._formatter.isComplete()) {
|
||||
this._lastCorrectValue = parsedValue;
|
||||
}
|
||||
|
||||
if (this._field.value === parsedValue) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._setValueToFieled(parsedValue);
|
||||
}
|
||||
|
||||
setValue(value)
|
||||
{
|
||||
let date = this._parseDateValue(value);
|
||||
|
||||
if (date === null || date.valueOf() < this._minimalDate.valueOf() || date.valueOf() > this._maximalDate.valueOf()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._lastCorrectValue = this._formatter.formatDate(date);
|
||||
this._field.value = this._lastCorrectValue;
|
||||
}
|
||||
|
||||
_getLimitedParsedValue()
|
||||
{
|
||||
if (!this._formatter.isComplete()) {
|
||||
return this._formatter.getCorrectedValue();
|
||||
}
|
||||
|
||||
let date = this._formatter.getParsedDate();
|
||||
|
||||
if (date.valueOf() < this._minimalDate.valueOf()) {
|
||||
return this._formatter.formatDate(this._minimalDate);
|
||||
}
|
||||
else if (date.valueOf() > this._maximalDate.valueOf()) {
|
||||
return this._formatter.formatDate(this._maximalDate);
|
||||
}
|
||||
|
||||
return this._formatter.getCorrectedValue();
|
||||
}
|
||||
|
||||
_setValueToFieled(newValue)
|
||||
{
|
||||
let position = this._field.selectionStart;
|
||||
let isAtEnd = (position === this._field.value.length);
|
||||
|
||||
this._field.value = newValue;
|
||||
|
||||
if (!isAtEnd && position < this._field.value.length) {
|
||||
this._field.selectionStart = position;
|
||||
this._field.selectionEnd = position;
|
||||
}
|
||||
}
|
||||
|
||||
returnLastCorrectValue()
|
||||
{
|
||||
if (this._lastCorrectValue !== null) {
|
||||
this._field.value = this._lastCorrectValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SmartDateField.initBy = function (id) {
|
||||
return SmartDateField.initFor(document.getElementById(id));
|
||||
};
|
||||
|
||||
SmartDateField.initFor = function (field, options) {
|
||||
if (typeof(field) !== 'object'
|
||||
|| field === null
|
||||
|| field.tagName.toLowerCase() !== 'input'
|
||||
|| field.type.toLowerCase() !== 'text') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof(field._smartDate) === 'object' && field._smartDate !== null && field._smartDate instanceof SmartDateField) {
|
||||
return;
|
||||
}
|
||||
|
||||
field._smartDate = new SmartDateField(field, options);
|
||||
};
|
||||
|
||||
jQuery.fn.smartdate = function (options) {
|
||||
let collection = [];
|
||||
let field = null;
|
||||
|
||||
for (let i = 0; i < this.length; i++) {
|
||||
field = SmartDateField.initFor(this[i], options);
|
||||
|
||||
if (field !== null) {
|
||||
collection.push(field);
|
||||
}
|
||||
}
|
||||
|
||||
return jQuery(this);
|
||||
};
|
||||
|
||||
jQuery.fn.setDateValue = function (value) {
|
||||
for (let i = 0; i < this.length; i++) {
|
||||
if (typeof(this[i]._smartDate) === 'object' && this[i]._smartDate !== null && this[i]._smartDate instanceof SmartDateField) {
|
||||
this[i]._smartDate.setValue(value);
|
||||
}
|
||||
}
|
||||
|
||||
return jQuery(this);
|
||||
};
|
1
es6/smart-date.min.js
vendored
Normal file
1
es6/smart-date.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
38
index-dev.html
Normal file
38
index-dev.html
Normal file
@@ -0,0 +1,38 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title></title>
|
||||
<script language="JavaScript" src="/jquery/jquery.min.js"></script>
|
||||
<link href="/css/style.css" type="text/css" rel="stylesheet" />
|
||||
<link href="/bootstrap/css/bootstrap.min.css" type="text/css" rel="stylesheet" />
|
||||
<script language="JavaScript" src="/bootstrap/js/bootstrap.min.js"></script>
|
||||
|
||||
<script language="JavaScript" src="/src-es6/AbstractSmartDatePart.js"></script>
|
||||
<script language="JavaScript" src="/src-es6/SmartDateStaticPart.js"></script>
|
||||
<script language="JavaScript" src="/src-es6/AbstractSmartDateNumericPart.js"></script>
|
||||
<script language="JavaScript" src="/src-es6/SmartDateDayPart.js"></script>
|
||||
<script language="JavaScript" src="/src-es6/SmartDateMonthPart.js"></script>
|
||||
<script language="JavaScript" src="/src-es6/SmartDateYearPart.js"></script>
|
||||
<script language="JavaScript" src="/src-es6/SmartDateParseState.js"></script>
|
||||
<script language="JavaScript" src="/src-es6/SmartDateFormat.js"></script>
|
||||
<script language="JavaScript" src="/src-es6/SmartDateField.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<br/>
|
||||
<br/>
|
||||
123 <input type="text" id="date" value="1.3.2019"/>
|
||||
<script language="JavaScript">
|
||||
|
||||
jQuery('#date').smartdate({
|
||||
format: 'd.m.y',
|
||||
minimal: '1900-01-01',
|
||||
maximal: '2099-12-31',
|
||||
//default: new Date(),
|
||||
});
|
||||
|
||||
//jQuery('#date').setDateValue('2019-4-5');
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
30
index-es5.html
Normal file
30
index-es5.html
Normal file
@@ -0,0 +1,30 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title></title>
|
||||
<script language="JavaScript" src="/jquery/jquery.min.js"></script>
|
||||
<link href="/css/style.css" type="text/css" rel="stylesheet" />
|
||||
<link href="/bootstrap/css/bootstrap.min.css" type="text/css" rel="stylesheet" />
|
||||
<script language="JavaScript" src="/bootstrap/js/bootstrap.min.js"></script>
|
||||
|
||||
<script language="JavaScript" src="/es5/smart-date.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<br/>
|
||||
<br/>
|
||||
123 <input type="text" id="date" value="1.3.2019"/>
|
||||
<script language="JavaScript">
|
||||
|
||||
jQuery('#date').smartdate({
|
||||
format: 'd.m.y',
|
||||
minimal: '1900-01-01',
|
||||
maximal: '2099-12-31',
|
||||
//default: new Date(),
|
||||
});
|
||||
|
||||
//jQuery('#date').setDateValue('2019-4-5');
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
30
index-es6.html
Normal file
30
index-es6.html
Normal file
@@ -0,0 +1,30 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title></title>
|
||||
<script language="JavaScript" src="/jquery/jquery.min.js"></script>
|
||||
<link href="/css/style.css" type="text/css" rel="stylesheet" />
|
||||
<link href="/bootstrap/css/bootstrap.min.css" type="text/css" rel="stylesheet" />
|
||||
<script language="JavaScript" src="/bootstrap/js/bootstrap.min.js"></script>
|
||||
|
||||
<script language="JavaScript" src="/es6/smart-date.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<br/>
|
||||
<br/>
|
||||
123 <input type="text" id="date" value="1.3.2019"/>
|
||||
<script language="JavaScript">
|
||||
|
||||
jQuery('#date').smartdate({
|
||||
format: 'd.m.y',
|
||||
minimal: '1900-01-01',
|
||||
maximal: '2099-12-31',
|
||||
//default: new Date(),
|
||||
});
|
||||
|
||||
//jQuery('#date').setDateValue('2019-4-5');
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
39
index.php
Normal file
39
index.php
Normal file
@@ -0,0 +1,39 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title></title>
|
||||
<script language="JavaScript" src="/jquery/jquery.min.js"></script>
|
||||
<link href="/css/style.css" type="text/css" rel="stylesheet" />
|
||||
<link href="/bootstrap/css/bootstrap.min.css" type="text/css" rel="stylesheet" />
|
||||
<script language="JavaScript" src="/bootstrap/js/bootstrap.min.js"></script>
|
||||
<script language="JavaScript" src="/src-es6/AbstractSmartDatePart.js"></script>
|
||||
<script language="JavaScript" src="/src-es6/SmartDateStaticPart.js"></script>
|
||||
<script language="JavaScript" src="/src-es6/AbstractSmartDateNumericPart.js"></script>
|
||||
<script language="JavaScript" src="/src-es6/SmartDateDayPart.js"></script>
|
||||
<script language="JavaScript" src="/src-es6/SmartDateMonthPart.js"></script>
|
||||
<script language="JavaScript" src="/src-es6/SmartDateYearPart.js"></script>
|
||||
<script language="JavaScript" src="/src-es6/SmartDateParseState.js"></script>
|
||||
<script language="JavaScript" src="/src-es6/SmartDateFormat.js"></script>
|
||||
<script language="JavaScript" src="/src-es6/SmartDateField.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<br/>
|
||||
<br/>
|
||||
123 <input type="text" id="date"/>
|
||||
<script language="JavaScript">
|
||||
|
||||
//ETrafficDateField.init(document.getElementById('date'));
|
||||
|
||||
jQuery('#date').smartdate({
|
||||
format: 'd.m.y',
|
||||
minimal: '1900-01-01',
|
||||
maximal: '2099-12-31',
|
||||
default: new Date(),
|
||||
});
|
||||
|
||||
//jQuery('#date').setDateValue('2022-4-5');
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
14
jquery/README.md
Normal file
14
jquery/README.md
Normal file
@@ -0,0 +1,14 @@
|
||||
jQuery Component
|
||||
================
|
||||
|
||||
Shim [repository](https://github.com/components/jquery) for the [jQuery](http://jquery.com).
|
||||
|
||||
If you're looking for jquery-migrate: It got it's [own repository](https://github.com/components/jquery-migrate) since jQuery v3.0.0.
|
||||
|
||||
Package Managers
|
||||
----------------
|
||||
|
||||
* [Bower](http://bower.io/): `jquery`
|
||||
* [Component](https://github.com/component/component): `components/jquery`
|
||||
* [Composer](http://packagist.org/packages/components/jquery): `components/jquery`
|
||||
* [spm](http://spmjs.io/package/jquery): `jquery`
|
16
jquery/bower.json
Normal file
16
jquery/bower.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"name": "jquery",
|
||||
"version": "3.3.1",
|
||||
"description": "jQuery component",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
"jquery",
|
||||
"component"
|
||||
],
|
||||
"main": "jquery.js",
|
||||
"ignore": [
|
||||
"component.json",
|
||||
"package.json",
|
||||
"composer.json"
|
||||
]
|
||||
}
|
22
jquery/component.json
Normal file
22
jquery/component.json
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"name": "jquery",
|
||||
"repo": "components/jquery",
|
||||
"version": "3.3.1",
|
||||
"description": "jQuery component",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
"jquery",
|
||||
"component"
|
||||
],
|
||||
"main": "jquery.js",
|
||||
"scripts": [
|
||||
"jquery.js",
|
||||
"jquery.min.js",
|
||||
"jquery.slim.js",
|
||||
"jquery.slim.min.js"
|
||||
],
|
||||
"files": [
|
||||
"jquery.min.map",
|
||||
"jquery.slim.min.map"
|
||||
]
|
||||
}
|
34
jquery/composer.json
Normal file
34
jquery/composer.json
Normal file
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"name": "components/jquery",
|
||||
"description": "jQuery JavaScript Library",
|
||||
"type": "component",
|
||||
"homepage": "http://jquery.com",
|
||||
"license": "MIT",
|
||||
"support": {
|
||||
"irc": "irc://irc.freenode.org/jquery",
|
||||
"issues": "https://github.com/jquery/jquery/issues",
|
||||
"forum": "http://forum.jquery.com",
|
||||
"wiki": "http://docs.jquery.com/",
|
||||
"source": "https://github.com/jquery/jquery"
|
||||
},
|
||||
"authors": [
|
||||
{
|
||||
"name": "JS Foundation and other contributors",
|
||||
"url": "https://github.com/jquery/jquery/blob/master/AUTHORS.txt"
|
||||
}
|
||||
],
|
||||
"extra": {
|
||||
"component": {
|
||||
"scripts": [
|
||||
"jquery.js"
|
||||
],
|
||||
"files": [
|
||||
"jquery.min.js",
|
||||
"jquery.min.map",
|
||||
"jquery.slim.js",
|
||||
"jquery.slim.min.js",
|
||||
"jquery.slim.min.map"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
10364
jquery/jquery.js
vendored
Normal file
10364
jquery/jquery.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
2
jquery/jquery.min.js
vendored
Normal file
2
jquery/jquery.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
jquery/jquery.min.map
Normal file
1
jquery/jquery.min.map
Normal file
File diff suppressed because one or more lines are too long
8269
jquery/jquery.slim.js
Normal file
8269
jquery/jquery.slim.js
Normal file
File diff suppressed because it is too large
Load Diff
2
jquery/jquery.slim.min.js
vendored
Normal file
2
jquery/jquery.slim.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
jquery/jquery.slim.min.map
Normal file
1
jquery/jquery.slim.min.map
Normal file
File diff suppressed because one or more lines are too long
33
jquery/package.json
Normal file
33
jquery/package.json
Normal file
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"name": "jquery",
|
||||
"description": "JavaScript library for DOM operations",
|
||||
"version": "3.3.1",
|
||||
"homepage": "http://jquery.com",
|
||||
"author": {
|
||||
"name": "jQuery Foundation and other contributors",
|
||||
"url": "https://github.com/jquery/jquery/blob/master/AUTHORS.txt"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/jquery/jquery.git"
|
||||
},
|
||||
"keywords": [
|
||||
"jquery",
|
||||
"javascript",
|
||||
"browser",
|
||||
"library"
|
||||
],
|
||||
"bugs": {
|
||||
"url": "https://github.com/jquery/jquery/issues"
|
||||
},
|
||||
"licenses": [
|
||||
{
|
||||
"type": "MIT",
|
||||
"url": "https://github.com/jquery/jquery/blob/master/LICENSE.txt"
|
||||
}
|
||||
],
|
||||
"spm": {
|
||||
"main": "jquery.js"
|
||||
}
|
||||
}
|
||||
|
11
package.json
Normal file
11
package.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"name": "smart-date",
|
||||
"version": "0.1.0",
|
||||
"scripts": {
|
||||
"build-es6": "bash ./build-es6.sh; minify ./es6/smart-date.js --out-file ./es6/smart-date.min.js",
|
||||
"build-es5": "babel ./es6/smart-date.js --out-file ./es5/smart-date.js --presets @babel/env; minify ./es6/smart-date.js --out-file ./es6/smart-date.min.js"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-cli": "^6.0.0"
|
||||
}
|
||||
}
|
152
src-es6/AbstractSmartDateNumericPart.js
Normal file
152
src-es6/AbstractSmartDateNumericPart.js
Normal file
@@ -0,0 +1,152 @@
|
||||
|
||||
class AbstractSmartDateNumericPart extends AbstractSmartDatePart
|
||||
{
|
||||
constructor(placeholder, size)
|
||||
{
|
||||
super(placeholder, false);
|
||||
this._numericValue = 0;
|
||||
this._size = size;
|
||||
}
|
||||
|
||||
numericValue()
|
||||
{
|
||||
return this._numericValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Date} date
|
||||
* @returns {String}
|
||||
*/
|
||||
formatDate(date)
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
formatValue(value)
|
||||
{
|
||||
let stringValue = String(this._correctValue(value));
|
||||
|
||||
if (stringValue === '0') {
|
||||
return stringValue;
|
||||
}
|
||||
|
||||
if (stringValue.length > this._size) {
|
||||
return stringValue.substring(0, this._size);
|
||||
}
|
||||
|
||||
if (stringValue.length < this._size) {
|
||||
return stringValue.padStart(this._size, '0');
|
||||
}
|
||||
|
||||
return stringValue;
|
||||
}
|
||||
|
||||
_correctValue(value)
|
||||
{
|
||||
return Math.round(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {SmartDateCheckState} state
|
||||
* @returns {String}
|
||||
*/
|
||||
scanStringNumber(state)
|
||||
{
|
||||
let index = state.valueIndex();
|
||||
let value = state.value();
|
||||
|
||||
while (index < value.length && this._isNumericSymbol(value[index])) {
|
||||
index++;
|
||||
}
|
||||
|
||||
let stringValue = value.substring(state.valueIndex(), index);
|
||||
|
||||
state.setValueIndex(index);
|
||||
|
||||
return stringValue;
|
||||
}
|
||||
|
||||
calculateNumericValue(stringValue, maximalNumber)
|
||||
{
|
||||
var startIndex = 0;
|
||||
var endIndex = 0;
|
||||
var numericValue = 0;
|
||||
|
||||
while (startIndex < stringValue.length && stringValue[startIndex] === 0) {
|
||||
startIndex++;
|
||||
}
|
||||
|
||||
endIndex = startIndex;
|
||||
|
||||
while (endIndex < stringValue.length && numericValue < maximalNumber) {
|
||||
numericValue = numericValue * 10 + Number(stringValue[endIndex]);
|
||||
endIndex++;
|
||||
}
|
||||
|
||||
if (numericValue > maximalNumber) {
|
||||
endIndex--;
|
||||
}
|
||||
|
||||
return Number(stringValue.substring(startIndex, endIndex));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {SmartDateCheckState} state
|
||||
* @param {Number} maximalValue
|
||||
*/
|
||||
scanValue(state, maximalValue)
|
||||
{
|
||||
let index = state.valueIndex();
|
||||
let value = state.value();
|
||||
|
||||
let numericValue = 0;
|
||||
|
||||
while (index < value.length && this._isNumericSymbol(value[index]) && numericValue < maximalValue) {
|
||||
numericValue = numericValue * 10 + Number(value[index]);
|
||||
index++;
|
||||
}
|
||||
|
||||
if (numericValue > maximalValue) {
|
||||
index--;
|
||||
}
|
||||
|
||||
let stringValue = value.substring(state.valueIndex(), index);
|
||||
|
||||
state.setValueIndex(index);
|
||||
|
||||
return stringValue;
|
||||
}
|
||||
|
||||
_defineParsingState(maximalValue, isAtEnd)
|
||||
{
|
||||
if (this._numericValue > 0 && (this._parsedValue.length >= this._size || !isAtEnd)) {
|
||||
this._state = AbstractSmartDatePart.STATE_COMPLETE;
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._numericValue * 10 > maximalValue) {
|
||||
this._state = AbstractSmartDatePart.STATE_COMPLETE;
|
||||
return;
|
||||
}
|
||||
|
||||
this._state = AbstractSmartDatePart.STATE_INCOMPLETE;
|
||||
}
|
||||
|
||||
_defineCleanValue()
|
||||
{
|
||||
this._cleanedValue = '';
|
||||
|
||||
if (this.isNoState()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.isComplete()) {
|
||||
this._cleanedValue = this.formatValue(this._numericValue);
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._parsedValue.length > 0) {
|
||||
this._cleanedValue = String(this._numericValue);
|
||||
}
|
||||
}
|
||||
}
|
77
src-es6/AbstractSmartDatePart.js
Normal file
77
src-es6/AbstractSmartDatePart.js
Normal file
@@ -0,0 +1,77 @@
|
||||
|
||||
class AbstractSmartDatePart
|
||||
{
|
||||
constructor(placeholder, isStatic)
|
||||
{
|
||||
this._state = AbstractSmartDatePart.STATE_NONE;
|
||||
this._cleanedValue = '';
|
||||
this._parsedValue = '';
|
||||
|
||||
this._scanned = '';
|
||||
this._placeholder = placeholder;
|
||||
this._static = isStatic;
|
||||
}
|
||||
|
||||
state()
|
||||
{
|
||||
return this._state;
|
||||
}
|
||||
|
||||
isNoState()
|
||||
{
|
||||
return this._state === AbstractSmartDatePart.STATE_NONE;
|
||||
}
|
||||
|
||||
isIncomplete()
|
||||
{
|
||||
return this._state === AbstractSmartDatePart.STATE_INCOMPLETE;
|
||||
}
|
||||
|
||||
isComplete()
|
||||
{
|
||||
return this._state === AbstractSmartDatePart.STATE_COMPLETE;
|
||||
}
|
||||
|
||||
resetState()
|
||||
{
|
||||
this._state = AbstractSmartDatePart.STATE_NONE;
|
||||
}
|
||||
|
||||
cleanedValue()
|
||||
{
|
||||
return this._cleanedValue;
|
||||
}
|
||||
|
||||
parsedValue()
|
||||
{
|
||||
return this._parsedValue;
|
||||
}
|
||||
|
||||
placeHolder()
|
||||
{
|
||||
return this._placeholder;
|
||||
}
|
||||
|
||||
isStatic()
|
||||
{
|
||||
return this._static;
|
||||
}
|
||||
|
||||
_isNumericSymbol(symbol)
|
||||
{
|
||||
return '0' <= symbol && symbol <= '9';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {SmartDateCheckState} state
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
check(state)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
AbstractSmartDatePart.STATE_NONE = 0;
|
||||
AbstractSmartDatePart.STATE_INCOMPLETE = 1;
|
||||
AbstractSmartDatePart.STATE_COMPLETE = 2;
|
62
src-es6/SmartDateDayPart.js
Normal file
62
src-es6/SmartDateDayPart.js
Normal file
@@ -0,0 +1,62 @@
|
||||
|
||||
class SmartDateDayPart extends AbstractSmartDateNumericPart
|
||||
{
|
||||
constructor()
|
||||
{
|
||||
super(SmartDateFormat.DAY_PLACEHOLDER, 2);
|
||||
this.maximalValue = SmartDateDayPart.MAXIMAL_VALUE;
|
||||
}
|
||||
|
||||
resetState()
|
||||
{
|
||||
super.resetState();
|
||||
this.maximalValue = SmartDateDayPart.MAXIMAL_VALUE;
|
||||
}
|
||||
|
||||
setMaximalValue(value)
|
||||
{
|
||||
if (value != value /* isNaN */ || value < SmartDateDayPart.MAXIMAL_VALUE_LOW_LIMIT || SmartDateDayPart.MAXIMAL_VALUE_HIGH_LIMIT < value) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.maximalValue = value;
|
||||
|
||||
if (this._numericValue <= this.maximalValue) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._numericValue = this.maximalValue;
|
||||
this._defineCleanValue();
|
||||
}
|
||||
|
||||
resetMaximalValue()
|
||||
{
|
||||
this.maximalValue = SmartDateDayPart.MAXIMAL_VALUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Date} date
|
||||
* @returns {String}
|
||||
*/
|
||||
formatDate(date)
|
||||
{
|
||||
return this.formatValue(date.getDate());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {SmartDateCheckState} state
|
||||
*/
|
||||
parse(state)
|
||||
{
|
||||
this._parsedValue = this.scanStringNumber(state);
|
||||
this._numericValue = this.calculateNumericValue(this._parsedValue, this.maximalValue);
|
||||
|
||||
this._defineParsingState(this.maximalValue, state.isOver());
|
||||
this._defineCleanValue();
|
||||
}
|
||||
}
|
||||
|
||||
SmartDateDayPart.MAXIMAL_VALUE_LOW_LIMIT = 28;
|
||||
SmartDateDayPart.MAXIMAL_VALUE_HIGH_LIMIT = 31;
|
||||
|
||||
SmartDateDayPart.MAXIMAL_VALUE = SmartDateDayPart.MAXIMAL_VALUE_HIGH_LIMIT;
|
283
src-es6/SmartDateField.js
Normal file
283
src-es6/SmartDateField.js
Normal file
@@ -0,0 +1,283 @@
|
||||
class SmartDateField
|
||||
{
|
||||
constructor(field, options)
|
||||
{
|
||||
this._dateYmdParser = new RegExp('^([0-9]{4})[,\._\/\-]+([0-9]{1,2})[,\._\/\-]+([0-9]{1,2})$');
|
||||
this._dateDmyParser = new RegExp('^([0-9]{1,2})[,\._\/\-]+([0-9]{1,2})[,\._\/\-]+([0-9]{4})$');
|
||||
|
||||
this._loadOptions(options);
|
||||
|
||||
this._formatter = new SmartDateFormat(this._format, this._minimalDate, this._maximalDate);
|
||||
|
||||
this._lastCorrectValue = (this._defaultDate === null ? null : this._formatter.formatDate(this._defaultDate));
|
||||
|
||||
this._initField(field);
|
||||
|
||||
this._subscribeEvents();
|
||||
}
|
||||
|
||||
|
||||
_loadDefaultOptions()
|
||||
{
|
||||
this._format = 'd.m.y';
|
||||
this._minimalDate = new Date(1900, 0, 1);
|
||||
this._maximalDate = new Date(2099, 11, 31);
|
||||
this._defaultDate = null;
|
||||
}
|
||||
|
||||
_loadOptions(options)
|
||||
{
|
||||
this._loadDefaultOptions();
|
||||
|
||||
if (typeof(options) !== 'object' || options == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof(options.format) === 'string'
|
||||
&& options.format.indexOf('d') >= 0
|
||||
&& options.format.indexOf('m') >= 0
|
||||
&& options.format.indexOf('y') >= 0) {
|
||||
this._format = options.format;
|
||||
}
|
||||
|
||||
if (typeof(options.minimal) !== 'undefined') {
|
||||
let date = this._parseDateValue(options.minimal);
|
||||
this._minimalDate = date;
|
||||
}
|
||||
|
||||
if (typeof(options.maximal) !== 'undefined') {
|
||||
let date = this._parseDateValue(options.maximal);
|
||||
this._maximalDate = date;
|
||||
}
|
||||
|
||||
if (typeof(options.default) !== 'undefined') {
|
||||
let date = this._parseDateValue(options.default);
|
||||
this._defaultDate = date;
|
||||
}
|
||||
|
||||
this._correctDateOptions();
|
||||
}
|
||||
|
||||
_correctDateOptions()
|
||||
{
|
||||
if (this._minimalDate.valueOf() > this._maximalDate.valueOf()) {
|
||||
let temporaryDate = this._minimalDate;
|
||||
this._minimalDate = this._maximalDate;
|
||||
this._maximalDate = temporaryDate;
|
||||
}
|
||||
|
||||
if (this._defaultDate === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._defaultDate.valueOf() < this._minimalDate.valueOf()) {
|
||||
this._defaultDate = this._minimalDate;
|
||||
}
|
||||
|
||||
if (this._defaultDate.valueOf() > this._maximalDate.valueOf()) {
|
||||
this._defaultDate = this._maximalDate;
|
||||
}
|
||||
}
|
||||
|
||||
_parseDateValue(date)
|
||||
{
|
||||
if (typeof(date) === 'object' && date !== null && date instanceof Date) {
|
||||
return date;
|
||||
}
|
||||
|
||||
if (typeof(date) !== 'string' || date.trim() === '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
let parsed = this._dateYmdParser.exec(date);
|
||||
|
||||
if (parsed !== null) {
|
||||
return new Date(Number(parsed[1]), Number(parsed[2]) - 1, Number(parsed[3]));
|
||||
}
|
||||
|
||||
parsed = this._dateDmyParser.exec(date);
|
||||
|
||||
if (parsed === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new Date(Number(parsed[3]), Number(parsed[2]) - 1, Number(parsed[1]));
|
||||
}
|
||||
|
||||
_initField(field)
|
||||
{
|
||||
this._field = field;
|
||||
this._field.placeholder = this._formatter.getPlaceHolder();
|
||||
|
||||
if (this._isEmptyValue(this._field.value)) {
|
||||
this._field.value = (this._defaultDate === null ? '' : this._formatter.formatDate(this._defaultDate));
|
||||
}
|
||||
else {
|
||||
this.correctValue(true);
|
||||
}
|
||||
}
|
||||
|
||||
_subscribeEvents()
|
||||
{
|
||||
let _this = this;
|
||||
|
||||
let correct = function (event) {
|
||||
if (event === null || event.type !== 'keyup') {
|
||||
_this.correctValue(true);
|
||||
}
|
||||
|
||||
if (_this._isServiceCode(event.keyCode)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.keyCode === 27) { // Escape
|
||||
_this.returnLastCorrectValue();
|
||||
}
|
||||
|
||||
_this.correctValue(true);
|
||||
};
|
||||
|
||||
this._field.addEventListener('change', correct);
|
||||
this._field.addEventListener('keyup', correct);
|
||||
|
||||
this._field.addEventListener('blur', function () {
|
||||
_this.correctValue(true);
|
||||
_this.returnLastCorrectValue();
|
||||
});
|
||||
}
|
||||
|
||||
_isServiceCode(code) {
|
||||
return code === 8 /* backspace */
|
||||
|| code === 46 /* delete */
|
||||
|| code === 16 /* shift */
|
||||
|| code === 17 /* shift */
|
||||
|| code === 18 /* shift */
|
||||
|| code === 20 /* caps lock */
|
||||
|| code === 35 /* end */
|
||||
|| code === 36 /* home */
|
||||
|| code === 37 /* left */
|
||||
|| code === 39 /* right */
|
||||
|| code === 46 /* delete */;
|
||||
}
|
||||
|
||||
_isEmptyValue(value)
|
||||
{
|
||||
return value.trim() === '';
|
||||
}
|
||||
|
||||
getDefaultValue()
|
||||
{
|
||||
return this._defaultDate === null ? '' : this._formatter.formatDate(this._defaultDate);
|
||||
}
|
||||
|
||||
correctValue(autocomplete)
|
||||
{
|
||||
this._formatter.parse(this._field.value, autocomplete);
|
||||
|
||||
let parsedValue = this._getLimitedParsedValue();
|
||||
|
||||
if (this._formatter.isComplete()) {
|
||||
this._lastCorrectValue = parsedValue;
|
||||
}
|
||||
|
||||
if (this._field.value === parsedValue) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._setValueToFieled(parsedValue);
|
||||
}
|
||||
|
||||
setValue(value)
|
||||
{
|
||||
let date = this._parseDateValue(value);
|
||||
|
||||
if (date === null || date.valueOf() < this._minimalDate.valueOf() || date.valueOf() > this._maximalDate.valueOf()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._lastCorrectValue = this._formatter.formatDate(date);
|
||||
this._field.value = this._lastCorrectValue;
|
||||
}
|
||||
|
||||
_getLimitedParsedValue()
|
||||
{
|
||||
if (!this._formatter.isComplete()) {
|
||||
return this._formatter.getCorrectedValue();
|
||||
}
|
||||
|
||||
let date = this._formatter.getParsedDate();
|
||||
|
||||
if (date.valueOf() < this._minimalDate.valueOf()) {
|
||||
return this._formatter.formatDate(this._minimalDate);
|
||||
}
|
||||
else if (date.valueOf() > this._maximalDate.valueOf()) {
|
||||
return this._formatter.formatDate(this._maximalDate);
|
||||
}
|
||||
|
||||
return this._formatter.getCorrectedValue();
|
||||
}
|
||||
|
||||
_setValueToFieled(newValue)
|
||||
{
|
||||
let position = this._field.selectionStart;
|
||||
let isAtEnd = (position === this._field.value.length);
|
||||
|
||||
this._field.value = newValue;
|
||||
|
||||
if (!isAtEnd && position < this._field.value.length) {
|
||||
this._field.selectionStart = position;
|
||||
this._field.selectionEnd = position;
|
||||
}
|
||||
}
|
||||
|
||||
returnLastCorrectValue()
|
||||
{
|
||||
if (this._lastCorrectValue !== null) {
|
||||
this._field.value = this._lastCorrectValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SmartDateField.initBy = function (id) {
|
||||
return SmartDateField.initFor(document.getElementById(id));
|
||||
};
|
||||
|
||||
SmartDateField.initFor = function (field, options) {
|
||||
if (typeof(field) !== 'object'
|
||||
|| field === null
|
||||
|| field.tagName.toLowerCase() !== 'input'
|
||||
|| field.type.toLowerCase() !== 'text') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof(field._smartDate) === 'object' && field._smartDate !== null && field._smartDate instanceof SmartDateField) {
|
||||
return;
|
||||
}
|
||||
|
||||
field._smartDate = new SmartDateField(field, options);
|
||||
};
|
||||
|
||||
jQuery.fn.smartdate = function (options) {
|
||||
let collection = [];
|
||||
let field = null;
|
||||
|
||||
for (let i = 0; i < this.length; i++) {
|
||||
field = SmartDateField.initFor(this[i], options);
|
||||
|
||||
if (field !== null) {
|
||||
collection.push(field);
|
||||
}
|
||||
}
|
||||
|
||||
return jQuery(this);
|
||||
};
|
||||
|
||||
jQuery.fn.setDateValue = function (value) {
|
||||
for (let i = 0; i < this.length; i++) {
|
||||
if (typeof(this[i]._smartDate) === 'object' && this[i]._smartDate !== null && this[i]._smartDate instanceof SmartDateField) {
|
||||
this[i]._smartDate.setValue(value);
|
||||
}
|
||||
}
|
||||
|
||||
return jQuery(this);
|
||||
};
|
247
src-es6/SmartDateFormat.js
Normal file
247
src-es6/SmartDateFormat.js
Normal file
@@ -0,0 +1,247 @@
|
||||
|
||||
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];
|
31
src-es6/SmartDateMonthPart.js
Normal file
31
src-es6/SmartDateMonthPart.js
Normal file
@@ -0,0 +1,31 @@
|
||||
|
||||
class SmartDateMonthPart extends AbstractSmartDateNumericPart
|
||||
{
|
||||
constructor()
|
||||
{
|
||||
super(SmartDateFormat.MONTH_PLACEHOLDER, 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Date} date
|
||||
* @returns {String}
|
||||
*/
|
||||
formatDate(date)
|
||||
{
|
||||
return this.formatValue(date.getMonth() + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {SmartDateCheckState} state
|
||||
*/
|
||||
parse(state)
|
||||
{
|
||||
this._parsedValue = this.scanStringNumber(state);
|
||||
this._numericValue = this.calculateNumericValue(this._parsedValue, SmartDateMonthPart.MAXIMAL_VALUE);
|
||||
|
||||
this._defineParsingState(SmartDateMonthPart.MAXIMAL_VALUE, state.isOver());
|
||||
this._defineCleanValue();
|
||||
}
|
||||
}
|
||||
|
||||
SmartDateMonthPart.MAXIMAL_VALUE = 12;
|
53
src-es6/SmartDateParseState.js
Normal file
53
src-es6/SmartDateParseState.js
Normal file
@@ -0,0 +1,53 @@
|
||||
|
||||
class SmartDateParseState
|
||||
{
|
||||
constructor()
|
||||
{
|
||||
this._value = '';
|
||||
this._valueIndex = 0;
|
||||
}
|
||||
|
||||
start(value)
|
||||
{
|
||||
this._value = value;
|
||||
this._valueIndex = 0;
|
||||
}
|
||||
|
||||
current()
|
||||
{
|
||||
return this.isOver() ? '' : this._value[this._valueIndex];
|
||||
}
|
||||
|
||||
next()
|
||||
{
|
||||
if (this.isOver()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this._valueIndex++;
|
||||
|
||||
return !this.isOver();
|
||||
}
|
||||
|
||||
isOver()
|
||||
{
|
||||
return this._valueIndex >= this._value.length;
|
||||
}
|
||||
|
||||
value()
|
||||
{
|
||||
return this._value;
|
||||
}
|
||||
|
||||
valueIndex()
|
||||
{
|
||||
return this._valueIndex;
|
||||
}
|
||||
|
||||
setValueIndex(index)
|
||||
{
|
||||
if (this._valueIndex < index) {
|
||||
this._valueIndex = index;
|
||||
}
|
||||
}
|
||||
}
|
30
src-es6/SmartDateStaticPart.js
Normal file
30
src-es6/SmartDateStaticPart.js
Normal file
@@ -0,0 +1,30 @@
|
||||
|
||||
class SmartDateStaticPart extends AbstractSmartDatePart
|
||||
{
|
||||
constructor(placeholder)
|
||||
{
|
||||
super(placeholder, true);
|
||||
this._cleanedValue = placeholder;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {SmartDateCheckState} state
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
parse(state)
|
||||
{
|
||||
let value = state.value();
|
||||
let index = state.valueIndex();
|
||||
|
||||
while (index < value.length && !this._isNumericSymbol(value[index])) {
|
||||
index++;
|
||||
}
|
||||
|
||||
this._parsedValue = value.substring(state.valueIndex(), index);
|
||||
this._state = AbstractSmartDatePart.STATE_COMPLETE;
|
||||
|
||||
state.setValueIndex(index);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
62
src-es6/SmartDateYearPart.js
Normal file
62
src-es6/SmartDateYearPart.js
Normal file
@@ -0,0 +1,62 @@
|
||||
|
||||
class SmartDateYearPart extends AbstractSmartDateNumericPart
|
||||
{
|
||||
constructor()
|
||||
{
|
||||
super(SmartDateFormat.YEAR_PLACEHOLDER, 4);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Date} date
|
||||
* @returns {String}
|
||||
*/
|
||||
formatDate(date)
|
||||
{
|
||||
return this.formatValue(date.getFullYear());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {SmartDateCheckState} state
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
parse(state)
|
||||
{
|
||||
this._parsedValue = this.scanStringNumber(state);
|
||||
this._numericValue = Number(this._parsedValue);
|
||||
|
||||
this._defineParsingState();
|
||||
|
||||
if (this._numericValue > SmartDateYearPart.MAXIMAL_VALUE) {
|
||||
this._numericValue = SmartDateYearPart.MAXIMAL_VALUE;
|
||||
}
|
||||
|
||||
if (this.isComplete() && this._numericValue < SmartDateYearPart.MINIMAL_VALUE) {
|
||||
this._numericValue = SmartDateYearPart.MINIMAL_VALUE;
|
||||
}
|
||||
|
||||
this._defineCleanValue();
|
||||
}
|
||||
|
||||
_defineParsingState()
|
||||
{
|
||||
if (this._numericValue > 0 && this._parsedValue.length >= this._size) {
|
||||
this._state = AbstractSmartDatePart.STATE_COMPLETE;
|
||||
return;
|
||||
}
|
||||
|
||||
this._state = AbstractSmartDatePart.STATE_INCOMPLETE;
|
||||
}
|
||||
|
||||
_defineCleanValue()
|
||||
{
|
||||
if (this._numericValue > 0) {
|
||||
this._cleanedValue = String(this._numericValue);
|
||||
}
|
||||
else {
|
||||
this._cleanedValue = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SmartDateYearPart.MINIMAL_VALUE = 1000;
|
||||
SmartDateYearPart.MAXIMAL_VALUE = 9999;
|
Reference in New Issue
Block a user