commit 2e4eace7ae73369347bf9c5f1220b5d4461580a5 Author: Anoop Date: Thu Oct 27 10:57:41 2022 +0530 Rebranded diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..7c229cb --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2016 Timofey Marochkin + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..cf4cf1f --- /dev/null +++ b/README.md @@ -0,0 +1,112 @@ +# Air Datepicker + +Lightweight customizable cross-browser jQuery datepicker, built with es5 and css-flexbox. Works in all modern desktop and mobile browsers (tested on Android 4.4+ and iOS8+). + +![air datepicker image](https://github.com/t1m0n/air-datepicker/raw/master/docs/img/promo-img-time.png) + +## Install + +### bower +``` +bower i --save air-datepicker +``` +### npm +``` +npm i --save air-datepicker +``` + +## Usage +```javascript +$('.my-datepicker').datepicker([options]) +``` + +## Demo and docs +* [In English](http://t1m0n.name/air-datepicker/docs/) +* [In Russian](http://t1m0n.name/air-datepicker/docs/index-ru.html) + +## Change log + +### v2.2.3 +* fixed min,max dates in decade mode + +### v2.2.2 +* fixed min,max dates handling + +### v2.2.1 +* changed RegExp for recognizing date parts +* changed jquery version dependency + +### v2.2.0 +* added `onlyTimepicker` option +* added `onShow` and `onHide` callbacks +* added `VERSION` field to plugin's prototype +* now for selecting same date in `range` mode, you should set `{toggleSelected: false}` +* fixed `dateFormat` method (fixed wrong month name in Hungarian language) +* fixed second call of `onRenderCallback` +* fixed `_getCell()` throwing exception +* new language: + - `sk` thanks to [RobiNN1](https://github.com/RobiNN1) + + +### v2.1.0 +* added possibility to select single date when `{range: true}` +* added support of 12 hours mode in `altFieldDateFormat` +* improved work with minDate and maxDate when `{timepicker: true}` +* fixed wrong class adding when `{range: true}` +* new languages: + - `es` thanks to [MarioAraque](https://github.com/MarioAraque) + - `cs` thanks to [liborm85](https://github.com/liborm85) + - `hu` thanks to [gergo85](https://github.com/gergo85) + - `fi` thanks to [joonaskaskisolaphz](https://github.com/joonaskaskisolaphz) + - `pl` thanks to [xiio](https://github.com/xiio) + - `fr` thanks to [nicooprat](https://github.com/nicooprat) + +### v2.0.2 +* fixed dates array in `onSelect` callback + +### v2.0.1 +* fixed version for npm + +### v2.0.0 +* added timepicker (see [docs](http://t1m0n.name/air-datepicker/docs#timepicker) for more info) +* added possibility to set `Date` in `todayButton` +* global variable `Datepicker` has been removed, now all placed in `$.fn.datepicker` +* improved `selectDate` method, now one can pass an array of dates to select +* added `npm` package +* fixed issue caused by `placeholder` on `readonly` inputs in IE +* fixed issue when `range` is true and first selected date is bigger than second +* added new languages: + - `da` thanks to [bjarnef](https://github.com/bjarnef) + - `nl` thanks to [JaZo](https://github.com/JaZo) + - `pt` thanks to [cmpscabral](https://github.com/cmpscabral) + - `pt-BR` thanks to [dowglaz](https://github.com/dowglaz) + - `ro` thanks to [tourniquet](https://github.com/tourniquet) + +### v1.2.4 +* fixed '$ is not defined' problem. + +### v1.2.3 +* fixed `dateFormat` method. +* fixed typo in Russian docs, add ids in docs headers. + +### v1.2.2 +* fixed typo in `monthsField` +* added German language (thanks to [Ichag](https://github.com/Ichag)) + +### v1.2.1 +* tests added +* added Chinese language (thanks to [think2011](https://github.com/think2011)) +* fixed if '0' is passed to `firstDay` +* fixed `showOtherYears` option +* fixed `onSelect` event, when `range` is true +* fixed case when `range` and `multipleDates` both set to true + +### v1.2.0 +* add `range` feature +* improve keyboard navigation (fixed two focused cells) + +### v1.1.0 +* add keyboard navigation +* add `classes` option to add custom classes +* add `altField` option +* bug fixes diff --git a/dist/css/datepicker.css b/dist/css/datepicker.css new file mode 100644 index 0000000..d7d4de0 --- /dev/null +++ b/dist/css/datepicker.css @@ -0,0 +1,578 @@ +.datepicker--cell-day.-other-month-, .datepicker--cell-year.-other-decade- { + color: #dedede; } + .datepicker--cell-day.-other-month-:hover, .datepicker--cell-year.-other-decade-:hover { + color: #c5c5c5; } + .-disabled-.-focus-.datepicker--cell-day.-other-month-, .-disabled-.-focus-.datepicker--cell-year.-other-decade- { + color: #dedede; } + .-selected-.datepicker--cell-day.-other-month-, .-selected-.datepicker--cell-year.-other-decade- { + color: #fff; + background: #a2ddf6; } + .-selected-.-focus-.datepicker--cell-day.-other-month-, .-selected-.-focus-.datepicker--cell-year.-other-decade- { + background: #8ad5f4; } + .-in-range-.datepicker--cell-day.-other-month-, .-in-range-.datepicker--cell-year.-other-decade- { + background-color: rgba(92, 196, 239, 0.1); + color: #cccccc; } + .-in-range-.-focus-.datepicker--cell-day.-other-month-, .-in-range-.-focus-.datepicker--cell-year.-other-decade- { + background-color: rgba(92, 196, 239, 0.2); } + .datepicker--cell-day.-other-month-:empty, .datepicker--cell-year.-other-decade-:empty { + background: none; + border: none; } + +.datepicker--cell-day.-other-month-, .datepicker--cell-year.-other-decade- { + color: #dedede; } + .datepicker--cell-day.-other-month-:hover, .datepicker--cell-year.-other-decade-:hover { + color: #c5c5c5; } + .-disabled-.-focus-.datepicker--cell-day.-other-month-, .-disabled-.-focus-.datepicker--cell-year.-other-decade- { + color: #dedede; } + .-selected-.datepicker--cell-day.-other-month-, .-selected-.datepicker--cell-year.-other-decade- { + color: #fff; + background: #a2ddf6; } + .-selected-.-focus-.datepicker--cell-day.-other-month-, .-selected-.-focus-.datepicker--cell-year.-other-decade- { + background: #8ad5f4; } + .-in-range-.datepicker--cell-day.-other-month-, .-in-range-.datepicker--cell-year.-other-decade- { + background-color: rgba(92, 196, 239, 0.1); + color: #cccccc; } + .-in-range-.-focus-.datepicker--cell-day.-other-month-, .-in-range-.-focus-.datepicker--cell-year.-other-decade- { + background-color: rgba(92, 196, 239, 0.2); } + .datepicker--cell-day.-other-month-:empty, .datepicker--cell-year.-other-decade-:empty { + background: none; + border: none; } + +/* ------------------------------------------------- + Datepicker cells + ------------------------------------------------- */ +.datepicker--cells { + display: -ms-flexbox; + display: flex; + -ms-flex-wrap: wrap; + flex-wrap: wrap; } + +.datepicker--cell { + border-radius: 4px; + box-sizing: border-box; + cursor: pointer; + display: -ms-flexbox; + display: flex; + position: relative; + -ms-flex-align: center; + align-items: center; + -ms-flex-pack: center; + justify-content: center; + height: 32px; + z-index: 1; } + .datepicker--cell.-focus- { + background: #f0f0f0; } + .datepicker--cell.-current- { + color: #4EB5E6; } + .datepicker--cell.-current-.-focus- { + color: #4a4a4a; } + .datepicker--cell.-current-.-in-range- { + color: #4EB5E6; } + .datepicker--cell.-in-range- { + background: rgba(92, 196, 239, 0.1); + color: #4a4a4a; + border-radius: 0; } + .datepicker--cell.-in-range-.-focus- { + background-color: rgba(92, 196, 239, 0.2); } + .datepicker--cell.-disabled- { + cursor: default; + color: #aeaeae; } + .datepicker--cell.-disabled-.-focus- { + color: #aeaeae; } + .datepicker--cell.-disabled-.-in-range- { + color: #a1a1a1; } + .datepicker--cell.-disabled-.-current-.-focus- { + color: #aeaeae; } + .datepicker--cell.-range-from- { + border: 1px solid rgba(92, 196, 239, 0.5); + background-color: rgba(92, 196, 239, 0.1); + border-radius: 4px 0 0 4px; } + .datepicker--cell.-range-to- { + border: 1px solid rgba(92, 196, 239, 0.5); + background-color: rgba(92, 196, 239, 0.1); + border-radius: 0 4px 4px 0; } + .datepicker--cell.-range-from-.-range-to- { + border-radius: 4px; } + .datepicker--cell.-selected- { + color: #fff; + border: none; + background: #5cc4ef; } + .datepicker--cell.-selected-.-current- { + color: #fff; + background: #5cc4ef; } + .datepicker--cell.-selected-.-focus- { + background: #45bced; } + .datepicker--cell:empty { + cursor: default; } + +.datepicker--days-names { + display: -ms-flexbox; + display: flex; + -ms-flex-wrap: wrap; + flex-wrap: wrap; + margin: 8px 0 3px; } + +.datepicker--day-name { + color: #FF9A19; + display: -ms-flexbox; + display: flex; + -ms-flex-align: center; + align-items: center; + -ms-flex-pack: center; + justify-content: center; + -ms-flex: 1; + flex: 1; + text-align: center; + text-transform: uppercase; + font-size: .8em; } + +.datepicker--cell-day { + width: 14.28571%; } + +.datepicker--cells-months { + height: 170px; } + +.datepicker--cell-month { + width: 33.33%; + height: 25%; } + +.datepicker--years { + height: 170px; } + +.datepicker--cells-years { + height: 170px; } + +.datepicker--cell-year { + width: 25%; + height: 33.33%; } + +.datepicker--cell-day.-other-month-, .datepicker--cell-year.-other-decade- { + color: #dedede; } + .datepicker--cell-day.-other-month-:hover, .datepicker--cell-year.-other-decade-:hover { + color: #c5c5c5; } + .-disabled-.-focus-.datepicker--cell-day.-other-month-, .-disabled-.-focus-.datepicker--cell-year.-other-decade- { + color: #dedede; } + .-selected-.datepicker--cell-day.-other-month-, .-selected-.datepicker--cell-year.-other-decade- { + color: #fff; + background: #a2ddf6; } + .-selected-.-focus-.datepicker--cell-day.-other-month-, .-selected-.-focus-.datepicker--cell-year.-other-decade- { + background: #8ad5f4; } + .-in-range-.datepicker--cell-day.-other-month-, .-in-range-.datepicker--cell-year.-other-decade- { + background-color: rgba(92, 196, 239, 0.1); + color: #cccccc; } + .-in-range-.-focus-.datepicker--cell-day.-other-month-, .-in-range-.-focus-.datepicker--cell-year.-other-decade- { + background-color: rgba(92, 196, 239, 0.2); } + .datepicker--cell-day.-other-month-:empty, .datepicker--cell-year.-other-decade-:empty { + background: none; + border: none; } + +/* ------------------------------------------------- + Datepicker + ------------------------------------------------- */ +.datepickers-container { + position: absolute; + left: 0; + top: 0; } + @media print { + .datepickers-container { + display: none; } } + +.datepicker { + background: #fff; + border: 1px solid #dbdbdb; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); + border-radius: 4px; + box-sizing: content-box; + font-family: Tahoma, sans-serif; + font-size: 14px; + color: #4a4a4a; + width: 250px; + position: absolute; + left: -100000px; + opacity: 0; + transition: opacity 0.3s ease, transform 0.3s ease, left 0s 0.3s; + z-index: 100; } + .datepicker.-from-top- { + transform: translateY(-8px); } + .datepicker.-from-right- { + transform: translateX(8px); } + .datepicker.-from-bottom- { + transform: translateY(8px); } + .datepicker.-from-left- { + transform: translateX(-8px); } + .datepicker.active { + opacity: 1; + transform: translate(0); + transition: opacity 0.3s ease, transform 0.3s ease, left 0s 0s; } + +.datepicker-inline .datepicker { + border-color: #d7d7d7; + box-shadow: none; + position: static; + left: auto; + right: auto; + opacity: 1; + transform: none; } + +.datepicker-inline .datepicker--pointer { + display: none; } + +.datepicker--content { + box-sizing: content-box; + padding: 4px; } + .-only-timepicker- .datepicker--content { + display: none; } + +.datepicker--pointer { + position: absolute; + background: #fff; + border-top: 1px solid #dbdbdb; + border-right: 1px solid #dbdbdb; + width: 10px; + height: 10px; + z-index: -1; } + .-top-left- .datepicker--pointer, .-top-center- .datepicker--pointer, .-top-right- .datepicker--pointer { + top: calc(100% - 4px); + transform: rotate(135deg); } + .-right-top- .datepicker--pointer, .-right-center- .datepicker--pointer, .-right-bottom- .datepicker--pointer { + right: calc(100% - 4px); + transform: rotate(225deg); } + .-bottom-left- .datepicker--pointer, .-bottom-center- .datepicker--pointer, .-bottom-right- .datepicker--pointer { + bottom: calc(100% - 4px); + transform: rotate(315deg); } + .-left-top- .datepicker--pointer, .-left-center- .datepicker--pointer, .-left-bottom- .datepicker--pointer { + left: calc(100% - 4px); + transform: rotate(45deg); } + .-top-left- .datepicker--pointer, .-bottom-left- .datepicker--pointer { + left: 10px; } + .-top-right- .datepicker--pointer, .-bottom-right- .datepicker--pointer { + right: 10px; } + .-top-center- .datepicker--pointer, .-bottom-center- .datepicker--pointer { + left: calc(50% - 10px / 2); } + .-left-top- .datepicker--pointer, .-right-top- .datepicker--pointer { + top: 10px; } + .-left-bottom- .datepicker--pointer, .-right-bottom- .datepicker--pointer { + bottom: 10px; } + .-left-center- .datepicker--pointer, .-right-center- .datepicker--pointer { + top: calc(50% - 10px / 2); } + +.datepicker--body { + display: none; } + .datepicker--body.active { + display: block; } + +.datepicker--cell-day.-other-month-, .datepicker--cell-year.-other-decade- { + color: #dedede; } + .datepicker--cell-day.-other-month-:hover, .datepicker--cell-year.-other-decade-:hover { + color: #c5c5c5; } + .-disabled-.-focus-.datepicker--cell-day.-other-month-, .-disabled-.-focus-.datepicker--cell-year.-other-decade- { + color: #dedede; } + .-selected-.datepicker--cell-day.-other-month-, .-selected-.datepicker--cell-year.-other-decade- { + color: #fff; + background: #a2ddf6; } + .-selected-.-focus-.datepicker--cell-day.-other-month-, .-selected-.-focus-.datepicker--cell-year.-other-decade- { + background: #8ad5f4; } + .-in-range-.datepicker--cell-day.-other-month-, .-in-range-.datepicker--cell-year.-other-decade- { + background-color: rgba(92, 196, 239, 0.1); + color: #cccccc; } + .-in-range-.-focus-.datepicker--cell-day.-other-month-, .-in-range-.-focus-.datepicker--cell-year.-other-decade- { + background-color: rgba(92, 196, 239, 0.2); } + .datepicker--cell-day.-other-month-:empty, .datepicker--cell-year.-other-decade-:empty { + background: none; + border: none; } + +/* ------------------------------------------------- + Navigation + ------------------------------------------------- */ +.datepicker--nav { + display: -ms-flexbox; + display: flex; + -ms-flex-pack: justify; + justify-content: space-between; + border-bottom: 1px solid #efefef; + min-height: 32px; + padding: 4px; } + .-only-timepicker- .datepicker--nav { + display: none; } + +.datepicker--nav-title, +.datepicker--nav-action { + display: -ms-flexbox; + display: flex; + cursor: pointer; + -ms-flex-align: center; + align-items: center; + -ms-flex-pack: center; + justify-content: center; } + +.datepicker--nav-action { + width: 32px; + border-radius: 4px; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; } + .datepicker--nav-action:hover { + background: #f0f0f0; } + .datepicker--nav-action.-disabled- { + visibility: hidden; } + .datepicker--nav-action svg { + width: 32px; + height: 32px; } + .datepicker--nav-action path { + fill: none; + stroke: #9c9c9c; + stroke-width: 2px; } + +.datepicker--nav-title { + border-radius: 4px; + padding: 0 8px; } + .datepicker--nav-title i { + font-style: normal; + color: #9c9c9c; + margin-left: 5px; } + .datepicker--nav-title:hover { + background: #f0f0f0; } + .datepicker--nav-title.-disabled- { + cursor: default; + background: none; } + +.datepicker--buttons { + display: -ms-flexbox; + display: flex; + padding: 4px; + border-top: 1px solid #efefef; } + +.datepicker--button { + color: #4EB5E6; + cursor: pointer; + border-radius: 4px; + -ms-flex: 1; + flex: 1; + display: -ms-inline-flexbox; + display: inline-flex; + -ms-flex-pack: center; + justify-content: center; + -ms-flex-align: center; + align-items: center; + height: 32px; } + .datepicker--button:hover { + color: #4a4a4a; + background: #f0f0f0; } + +.datepicker--cell-day.-other-month-, .datepicker--cell-year.-other-decade- { + color: #dedede; } + .datepicker--cell-day.-other-month-:hover, .datepicker--cell-year.-other-decade-:hover { + color: #c5c5c5; } + .-disabled-.-focus-.datepicker--cell-day.-other-month-, .-disabled-.-focus-.datepicker--cell-year.-other-decade- { + color: #dedede; } + .-selected-.datepicker--cell-day.-other-month-, .-selected-.datepicker--cell-year.-other-decade- { + color: #fff; + background: #a2ddf6; } + .-selected-.-focus-.datepicker--cell-day.-other-month-, .-selected-.-focus-.datepicker--cell-year.-other-decade- { + background: #8ad5f4; } + .-in-range-.datepicker--cell-day.-other-month-, .-in-range-.datepicker--cell-year.-other-decade- { + background-color: rgba(92, 196, 239, 0.1); + color: #cccccc; } + .-in-range-.-focus-.datepicker--cell-day.-other-month-, .-in-range-.-focus-.datepicker--cell-year.-other-decade- { + background-color: rgba(92, 196, 239, 0.2); } + .datepicker--cell-day.-other-month-:empty, .datepicker--cell-year.-other-decade-:empty { + background: none; + border: none; } + +/* ------------------------------------------------- + Timepicker + ------------------------------------------------- */ +.datepicker--time { + border-top: 1px solid #efefef; + display: -ms-flexbox; + display: flex; + -ms-flex-align: center; + align-items: center; + padding: 4px; + position: relative; } + .datepicker--time.-am-pm- .datepicker--time-sliders { + -ms-flex: 0 1 138px; + flex: 0 1 138px; + max-width: 138px; } + .-only-timepicker- .datepicker--time { + border-top: none; } + +.datepicker--time-sliders { + -ms-flex: 0 1 153px; + flex: 0 1 153px; + margin-right: 10px; + max-width: 153px; } + +.datepicker--time-label { + display: none; + font-size: 12px; } + +.datepicker--time-current { + display: -ms-flexbox; + display: flex; + -ms-flex-align: center; + align-items: center; + -ms-flex: 1; + flex: 1; + font-size: 14px; + text-align: center; + margin: 0 10px; } + +.datepicker--time-current-colon { + margin: 0 2px 3px; + line-height: 1; } + +.datepicker--time-current-hours, +.datepicker--time-current-minutes, +.datepicker--time-current-seconds { + line-height: 1; + font-size: 14px; + font-family: "Century Gothic", CenturyGothic, AppleGothic, sans-serif; + position: relative; + z-index: 1; } + .datepicker--time-current-hours:after, + .datepicker--time-current-minutes:after, + .datepicker--time-current-seconds:after { + content: ''; + background: #f0f0f0; + border-radius: 4px; + position: absolute; + left: -2px; + top: -3px; + right: -2px; + bottom: -2px; + z-index: -1; + opacity: 0; } + .datepicker--time-current-hours.-focus-:after, + .datepicker--time-current-minutes.-focus-:after, + .datepicker--time-current-seconds.-focus-:after { + opacity: 1; } + +.datepicker--time-current-ampm { + text-transform: uppercase; + -ms-flex-item-align: start; + align-self: flex-start; + color: #9c9c9c; + margin-left: 6px; + font-size: 11px; + margin-bottom: 1px; } + +.datepicker--time-row { + display: -ms-flexbox; + display: flex; + -ms-flex-align: center; + align-items: center; + font-size: 11px; + height: 17px; + background: linear-gradient(to right, #dedede, #dedede) left 50%/100% 1px no-repeat; } + .datepicker--time-row:first-child { + margin-bottom: 4px; } + .datepicker--time-row input[type='range'] { + background: none; + cursor: pointer; + -ms-flex: 1; + flex: 1; + height: 100%; + padding: 0; + margin: 0; + -webkit-appearance: none; } + .datepicker--time-row input[type='range']::-webkit-slider-thumb { + -webkit-appearance: none; } + .datepicker--time-row input[type='range']::-ms-tooltip { + display: none; } + .datepicker--time-row input[type='range']:hover::-webkit-slider-thumb { + border-color: #b8b8b8; } + .datepicker--time-row input[type='range']:hover::-moz-range-thumb { + border-color: #b8b8b8; } + .datepicker--time-row input[type='range']:hover::-ms-thumb { + border-color: #b8b8b8; } + .datepicker--time-row input[type='range']:focus { + outline: none; } + .datepicker--time-row input[type='range']:focus::-webkit-slider-thumb { + background: #5cc4ef; + border-color: #5cc4ef; } + .datepicker--time-row input[type='range']:focus::-moz-range-thumb { + background: #5cc4ef; + border-color: #5cc4ef; } + .datepicker--time-row input[type='range']:focus::-ms-thumb { + background: #5cc4ef; + border-color: #5cc4ef; } + .datepicker--time-row input[type='range']::-webkit-slider-thumb { + box-sizing: border-box; + height: 12px; + width: 12px; + border-radius: 3px; + border: 1px solid #dedede; + background: #fff; + cursor: pointer; + transition: background .2s; } + .datepicker--time-row input[type='range']::-moz-range-thumb { + box-sizing: border-box; + height: 12px; + width: 12px; + border-radius: 3px; + border: 1px solid #dedede; + background: #fff; + cursor: pointer; + transition: background .2s; } + .datepicker--time-row input[type='range']::-ms-thumb { + box-sizing: border-box; + height: 12px; + width: 12px; + border-radius: 3px; + border: 1px solid #dedede; + background: #fff; + cursor: pointer; + transition: background .2s; } + .datepicker--time-row input[type='range']::-webkit-slider-thumb { + margin-top: -6px; } + .datepicker--time-row input[type='range']::-webkit-slider-runnable-track { + border: none; + height: 1px; + cursor: pointer; + color: transparent; + background: transparent; } + .datepicker--time-row input[type='range']::-moz-range-track { + border: none; + height: 1px; + cursor: pointer; + color: transparent; + background: transparent; } + .datepicker--time-row input[type='range']::-ms-track { + border: none; + height: 1px; + cursor: pointer; + color: transparent; + background: transparent; } + .datepicker--time-row input[type='range']::-ms-fill-lower { + background: transparent; } + .datepicker--time-row input[type='range']::-ms-fill-upper { + background: transparent; } + .datepicker--time-row span { + padding: 0 12px; } + +.datepicker--time-icon { + color: #9c9c9c; + border: 1px solid; + border-radius: 50%; + font-size: 16px; + position: relative; + margin: 0 5px -1px 0; + width: 1em; + height: 1em; } + .datepicker--time-icon:after, .datepicker--time-icon:before { + content: ''; + background: currentColor; + position: absolute; } + .datepicker--time-icon:after { + height: .4em; + width: 1px; + left: calc(50% - 1px); + top: calc(50% + 1px); + transform: translateY(-100%); } + .datepicker--time-icon:before { + width: .4em; + height: 1px; + top: calc(50% + 1px); + left: calc(50% - 1px); } diff --git a/dist/css/datepicker.min.css b/dist/css/datepicker.min.css new file mode 100644 index 0000000..8b6cd1b --- /dev/null +++ b/dist/css/datepicker.min.css @@ -0,0 +1 @@ +.datepicker--cells{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap}.datepicker--cell{border-radius:4px;box-sizing:border-box;cursor:pointer;display:-ms-flexbox;display:flex;position:relative;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;height:32px;z-index:1}.datepicker--cell.-focus-{background:#f0f0f0}.datepicker--cell.-current-{color:#4EB5E6}.datepicker--cell.-current-.-focus-{color:#4a4a4a}.datepicker--cell.-current-.-in-range-{color:#4EB5E6}.datepicker--cell.-in-range-{background:rgba(92,196,239,.1);color:#4a4a4a;border-radius:0}.datepicker--cell.-in-range-.-focus-{background-color:rgba(92,196,239,.2)}.datepicker--cell.-disabled-{cursor:default;color:#aeaeae}.datepicker--cell.-disabled-.-focus-{color:#aeaeae}.datepicker--cell.-disabled-.-in-range-{color:#a1a1a1}.datepicker--cell.-disabled-.-current-.-focus-{color:#aeaeae}.datepicker--cell.-range-from-{border:1px solid rgba(92,196,239,.5);background-color:rgba(92,196,239,.1);border-radius:4px 0 0 4px}.datepicker--cell.-range-to-{border:1px solid rgba(92,196,239,.5);background-color:rgba(92,196,239,.1);border-radius:0 4px 4px 0}.datepicker--cell.-selected-,.datepicker--cell.-selected-.-current-{color:#fff;background:#5cc4ef}.datepicker--cell.-range-from-.-range-to-{border-radius:4px}.datepicker--cell.-selected-{border:none}.datepicker--cell.-selected-.-focus-{background:#45bced}.datepicker--cell:empty{cursor:default}.datepicker--days-names{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;margin:8px 0 3px}.datepicker--day-name{color:#FF9A19;display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;-ms-flex:1;flex:1;text-align:center;text-transform:uppercase;font-size:.8em}.-only-timepicker- .datepicker--content,.datepicker--body,.datepicker-inline .datepicker--pointer{display:none}.datepicker--cell-day{width:14.28571%}.datepicker--cells-months{height:170px}.datepicker--cell-month{width:33.33%;height:25%}.datepicker--cells-years,.datepicker--years{height:170px}.datepicker--cell-year{width:25%;height:33.33%}.datepickers-container{position:absolute;left:0;top:0}@media print{.datepickers-container{display:none}}.datepicker{background:#fff;border:1px solid #dbdbdb;box-shadow:0 4px 12px rgba(0,0,0,.15);border-radius:4px;box-sizing:content-box;font-family:Tahoma,sans-serif;font-size:14px;color:#4a4a4a;width:250px;position:absolute;left:-100000px;opacity:0;transition:opacity .3s ease,transform .3s ease,left 0s .3s;z-index:100}.datepicker.-from-top-{transform:translateY(-8px)}.datepicker.-from-right-{transform:translateX(8px)}.datepicker.-from-bottom-{transform:translateY(8px)}.datepicker.-from-left-{transform:translateX(-8px)}.datepicker.active{opacity:1;transform:translate(0);transition:opacity .3s ease,transform .3s ease,left 0s 0s}.datepicker-inline .datepicker{border-color:#d7d7d7;box-shadow:none;position:static;left:auto;right:auto;opacity:1;transform:none}.datepicker--content{box-sizing:content-box;padding:4px}.datepicker--pointer{position:absolute;background:#fff;border-top:1px solid #dbdbdb;border-right:1px solid #dbdbdb;width:10px;height:10px;z-index:-1}.datepicker--nav-action:hover,.datepicker--nav-title:hover{background:#f0f0f0}.-top-center- .datepicker--pointer,.-top-left- .datepicker--pointer,.-top-right- .datepicker--pointer{top:calc(100% - 4px);transform:rotate(135deg)}.-right-bottom- .datepicker--pointer,.-right-center- .datepicker--pointer,.-right-top- .datepicker--pointer{right:calc(100% - 4px);transform:rotate(225deg)}.-bottom-center- .datepicker--pointer,.-bottom-left- .datepicker--pointer,.-bottom-right- .datepicker--pointer{bottom:calc(100% - 4px);transform:rotate(315deg)}.-left-bottom- .datepicker--pointer,.-left-center- .datepicker--pointer,.-left-top- .datepicker--pointer{left:calc(100% - 4px);transform:rotate(45deg)}.-bottom-left- .datepicker--pointer,.-top-left- .datepicker--pointer{left:10px}.-bottom-right- .datepicker--pointer,.-top-right- .datepicker--pointer{right:10px}.-bottom-center- .datepicker--pointer,.-top-center- .datepicker--pointer{left:calc(50% - 10px / 2)}.-left-top- .datepicker--pointer,.-right-top- .datepicker--pointer{top:10px}.-left-bottom- .datepicker--pointer,.-right-bottom- .datepicker--pointer{bottom:10px}.-left-center- .datepicker--pointer,.-right-center- .datepicker--pointer{top:calc(50% - 10px / 2)}.datepicker--body.active{display:block}.datepicker--nav{display:-ms-flexbox;display:flex;-ms-flex-pack:justify;justify-content:space-between;border-bottom:1px solid #efefef;min-height:32px;padding:4px}.-only-timepicker- .datepicker--nav{display:none}.datepicker--nav-action,.datepicker--nav-title{display:-ms-flexbox;display:flex;cursor:pointer;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center}.datepicker--nav-action{width:32px;border-radius:4px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.datepicker--nav-action.-disabled-{visibility:hidden}.datepicker--nav-action svg{width:32px;height:32px}.datepicker--nav-action path{fill:none;stroke:#9c9c9c;stroke-width:2px}.datepicker--nav-title{border-radius:4px;padding:0 8px}.datepicker--nav-title i{font-style:normal;color:#9c9c9c;margin-left:5px}.datepicker--nav-title.-disabled-{cursor:default;background:0 0}.datepicker--buttons{display:-ms-flexbox;display:flex;padding:4px;border-top:1px solid #efefef}.datepicker--button{color:#4EB5E6;cursor:pointer;border-radius:4px;-ms-flex:1;flex:1;display:-ms-inline-flexbox;display:inline-flex;-ms-flex-pack:center;justify-content:center;-ms-flex-align:center;align-items:center;height:32px}.datepicker--button:hover{color:#4a4a4a;background:#f0f0f0}.datepicker--cell-day.-other-month-,.datepicker--cell-year.-other-decade-{color:#dedede}.datepicker--cell-day.-other-month-:hover,.datepicker--cell-year.-other-decade-:hover{color:#c5c5c5}.-disabled-.-focus-.datepicker--cell-day.-other-month-,.-disabled-.-focus-.datepicker--cell-year.-other-decade-{color:#dedede}.-selected-.datepicker--cell-day.-other-month-,.-selected-.datepicker--cell-year.-other-decade-{color:#fff;background:#a2ddf6}.-selected-.-focus-.datepicker--cell-day.-other-month-,.-selected-.-focus-.datepicker--cell-year.-other-decade-{background:#8ad5f4}.-in-range-.datepicker--cell-day.-other-month-,.-in-range-.datepicker--cell-year.-other-decade-{background-color:rgba(92,196,239,.1);color:#ccc}.-in-range-.-focus-.datepicker--cell-day.-other-month-,.-in-range-.-focus-.datepicker--cell-year.-other-decade-{background-color:rgba(92,196,239,.2)}.datepicker--cell-day.-other-month-:empty,.datepicker--cell-year.-other-decade-:empty{background:0 0;border:none}.datepicker--time{border-top:1px solid #efefef;display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;padding:4px;position:relative}.datepicker--time.-am-pm- .datepicker--time-sliders{-ms-flex:0 1 138px;flex:0 1 138px;max-width:138px}.-only-timepicker- .datepicker--time{border-top:none}.datepicker--time-sliders{-ms-flex:0 1 153px;flex:0 1 153px;margin-right:10px;max-width:153px}.datepicker--time-label{display:none;font-size:12px}.datepicker--time-current{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex:1;flex:1;font-size:14px;text-align:center;margin:0 10px}.datepicker--time-current-colon{margin:0 2px 3px;line-height:1}.datepicker--time-current-hours,.datepicker--time-current-minutes,.datepicker--time-current-seconds{line-height:1;font-size:14px;font-family:"Century Gothic",CenturyGothic,AppleGothic,sans-serif;position:relative;z-index:1}.datepicker--time-current-hours:after,.datepicker--time-current-minutes:after,.datepicker--time-current-seconds:after{content:'';background:#f0f0f0;border-radius:4px;position:absolute;left:-2px;top:-3px;right:-2px;bottom:-2px;z-index:-1;opacity:0}.datepicker--time-current-hours.-focus-:after,.datepicker--time-current-minutes.-focus-:after,.datepicker--time-current-seconds.-focus-:after{opacity:1}.datepicker--time-current-ampm{text-transform:uppercase;-ms-flex-item-align:start;align-self:flex-start;color:#9c9c9c;margin-left:6px;font-size:11px;margin-bottom:1px}.datepicker--time-row{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;font-size:11px;height:17px;background:linear-gradient(to right,#dedede,#dedede) left 50%/100% 1px no-repeat}.datepicker--time-row:first-child{margin-bottom:4px}.datepicker--time-row input[type=range]{background:0 0;cursor:pointer;-ms-flex:1;flex:1;height:100%;padding:0;margin:0;-webkit-appearance:none}.datepicker--time-row input[type=range]::-ms-tooltip{display:none}.datepicker--time-row input[type=range]:hover::-webkit-slider-thumb{border-color:#b8b8b8}.datepicker--time-row input[type=range]:hover::-moz-range-thumb{border-color:#b8b8b8}.datepicker--time-row input[type=range]:hover::-ms-thumb{border-color:#b8b8b8}.datepicker--time-row input[type=range]:focus{outline:0}.datepicker--time-row input[type=range]:focus::-webkit-slider-thumb{background:#5cc4ef;border-color:#5cc4ef}.datepicker--time-row input[type=range]:focus::-moz-range-thumb{background:#5cc4ef;border-color:#5cc4ef}.datepicker--time-row input[type=range]:focus::-ms-thumb{background:#5cc4ef;border-color:#5cc4ef}.datepicker--time-row input[type=range]::-webkit-slider-thumb{-webkit-appearance:none;box-sizing:border-box;height:12px;width:12px;border-radius:3px;border:1px solid #dedede;background:#fff;cursor:pointer;transition:background .2s;margin-top:-6px}.datepicker--time-row input[type=range]::-moz-range-thumb{box-sizing:border-box;height:12px;width:12px;border-radius:3px;border:1px solid #dedede;background:#fff;cursor:pointer;transition:background .2s}.datepicker--time-row input[type=range]::-ms-thumb{box-sizing:border-box;height:12px;width:12px;border-radius:3px;border:1px solid #dedede;background:#fff;cursor:pointer;transition:background .2s}.datepicker--time-row input[type=range]::-webkit-slider-runnable-track{border:none;height:1px;cursor:pointer;color:transparent;background:0 0}.datepicker--time-row input[type=range]::-moz-range-track{border:none;height:1px;cursor:pointer;color:transparent;background:0 0}.datepicker--time-row input[type=range]::-ms-track{border:none;height:1px;cursor:pointer;color:transparent;background:0 0}.datepicker--time-row input[type=range]::-ms-fill-lower{background:0 0}.datepicker--time-row input[type=range]::-ms-fill-upper{background:0 0}.datepicker--time-row span{padding:0 12px}.datepicker--time-icon{color:#9c9c9c;border:1px solid;border-radius:50%;font-size:16px;position:relative;margin:0 5px -1px 0;width:1em;height:1em}.datepicker--time-icon:after,.datepicker--time-icon:before{content:'';background:currentColor;position:absolute}.datepicker--time-icon:after{height:.4em;width:1px;left:calc(50% - 1px);top:calc(50% + 1px);transform:translateY(-100%)}.datepicker--time-icon:before{width:.4em;height:1px;top:calc(50% + 1px);left:calc(50% - 1px)} \ No newline at end of file diff --git a/dist/js/datepicker.js b/dist/js/datepicker.js new file mode 100644 index 0000000..5484065 --- /dev/null +++ b/dist/js/datepicker.js @@ -0,0 +1,2281 @@ +;(function (window, $, undefined) { ;(function () { + var VERSION = '2.2.3', + pluginName = 'datepicker', + autoInitSelector = '.datepicker-here', + $body, $datepickersContainer, + containerBuilt = false, + baseTemplate = '' + + '
' + + '' + + '' + + '
' + + '
', + defaults = { + classes: '', + inline: false, + language: 'ru', + startDate: new Date(), + firstDay: '', + weekends: [6, 0], + dateFormat: '', + altField: '', + altFieldDateFormat: '@', + toggleSelected: true, + keyboardNav: true, + + position: 'bottom left', + offset: 12, + + view: 'days', + minView: 'days', + + showOtherMonths: true, + selectOtherMonths: true, + moveToOtherMonthsOnSelect: true, + + showOtherYears: true, + selectOtherYears: true, + moveToOtherYearsOnSelect: true, + + minDate: '', + maxDate: '', + disableNavWhenOutOfRange: true, + + multipleDates: false, // Boolean or Number + multipleDatesSeparator: ',', + range: false, + + todayButton: false, + clearButton: false, + + showEvent: 'focus', + autoClose: false, + + // navigation + monthsField: 'monthsShort', + prevHtml: '', + nextHtml: '', + navTitles: { + days: 'MM, yyyy', + months: 'yyyy', + years: 'yyyy1 - yyyy2' + }, + + // timepicker + timepicker: false, + onlyTimepicker: false, + dateTimeSeparator: ' ', + timeFormat: '', + minHours: 0, + maxHours: 24, + minMinutes: 0, + maxMinutes: 59, + minSeconds: 0, + maxSeconds: 59, + hoursStep: 1, + minutesStep: 1, + secondsStep: 1, + + // events + onSelect: '', + onShow: '', + onHide: '', + onChangeMonth: '', + onChangeYear: '', + onChangeDecade: '', + onChangeView: '', + onRenderCell: '' + }, + hotKeys = { + 'ctrlRight': [17, 39], + 'ctrlUp': [17, 38], + 'ctrlLeft': [17, 37], + 'ctrlDown': [17, 40], + 'shiftRight': [16, 39], + 'shiftUp': [16, 38], + 'shiftLeft': [16, 37], + 'shiftDown': [16, 40], + 'altUp': [18, 38], + 'altRight': [18, 39], + 'altLeft': [18, 37], + 'altDown': [18, 40], + 'ctrlShiftUp': [16, 17, 38] + }, + datepicker; + + var Datepicker = function (el, options) { + this.el = el; + this.$el = $(el); + + this.opts = $.extend(true, {}, defaults, options, this.$el.data()); + + if ($body == undefined) { + $body = $('body'); + } + + if (!this.opts.startDate) { + this.opts.startDate = new Date(); + } + + if (this.el.nodeName == 'INPUT') { + this.elIsInput = true; + } + + if (this.opts.altField) { + this.$altField = typeof this.opts.altField == 'string' ? $(this.opts.altField) : this.opts.altField; + } + + this.inited = false; + this.visible = false; + this.silent = false; // Need to prevent unnecessary rendering + + this.currentDate = this.opts.startDate; + this.currentView = this.opts.view; + this._createShortCuts(); + this.selectedDates = []; + this.views = {}; + this.keys = []; + this.minRange = ''; + this.maxRange = ''; + this._prevOnSelectValue = ''; + + this.init() + }; + + datepicker = Datepicker; + + datepicker.prototype = { + VERSION: VERSION, + viewIndexes: ['days', 'months', 'years'], + + init: function () { + if (!containerBuilt && !this.opts.inline && this.elIsInput) { + this._buildDatepickersContainer(); + } + this._buildBaseHtml(); + this._defineLocale(this.opts.language); + this._syncWithMinMaxDates(); + + if (this.elIsInput) { + if (!this.opts.inline) { + // Set extra classes for proper transitions + this._setPositionClasses(this.opts.position); + this._bindEvents() + } + if (this.opts.keyboardNav && !this.opts.onlyTimepicker) { + this._bindKeyboardEvents(); + } + this.$datepicker.on('mousedown', this._onMouseDownDatepicker.bind(this)); + this.$datepicker.on('mouseup', this._onMouseUpDatepicker.bind(this)); + } + + if (this.opts.classes) { + this.$datepicker.addClass(this.opts.classes) + } + + if (this.opts.timepicker) { + this.timepicker = new $.fn.datepicker.Timepicker(this, this.opts); + this._bindTimepickerEvents(); + } + + if (this.opts.onlyTimepicker) { + this.$datepicker.addClass('-only-timepicker-'); + } + + this.views[this.currentView] = new $.fn.datepicker.Body(this, this.currentView, this.opts); + this.views[this.currentView].show(); + this.nav = new $.fn.datepicker.Navigation(this, this.opts); + this.view = this.currentView; + + this.$el.on('clickCell.adp', this._onClickCell.bind(this)); + this.$datepicker.on('mouseenter', '.datepicker--cell', this._onMouseEnterCell.bind(this)); + this.$datepicker.on('mouseleave', '.datepicker--cell', this._onMouseLeaveCell.bind(this)); + + this.inited = true; + }, + + _createShortCuts: function () { + this.minDate = this.opts.minDate ? this.opts.minDate : new Date(-8639999913600000); + this.maxDate = this.opts.maxDate ? this.opts.maxDate : new Date(8639999913600000); + }, + + _bindEvents : function () { + this.$el.on(this.opts.showEvent + '.adp', this._onShowEvent.bind(this)); + this.$el.on('mouseup.adp', this._onMouseUpEl.bind(this)); + this.$el.on('blur.adp', this._onBlur.bind(this)); + this.$el.on('keyup.adp', this._onKeyUpGeneral.bind(this)); + $(window).on('resize.adp', this._onResize.bind(this)); + $('body').on('mouseup.adp', this._onMouseUpBody.bind(this)); + }, + + _bindKeyboardEvents: function () { + this.$el.on('keydown.adp', this._onKeyDown.bind(this)); + this.$el.on('keyup.adp', this._onKeyUp.bind(this)); + this.$el.on('hotKey.adp', this._onHotKey.bind(this)); + }, + + _bindTimepickerEvents: function () { + this.$el.on('timeChange.adp', this._onTimeChange.bind(this)); + }, + + isWeekend: function (day) { + return this.opts.weekends.indexOf(day) !== -1; + }, + + _defineLocale: function (lang) { + if (typeof lang == 'string') { + this.loc = $.fn.datepicker.language[lang]; + if (!this.loc) { + console.warn('Can\'t find language "' + lang + '" in Datepicker.language, will use "ru" instead'); + this.loc = $.extend(true, {}, $.fn.datepicker.language.ru) + } + + this.loc = $.extend(true, {}, $.fn.datepicker.language.ru, $.fn.datepicker.language[lang]) + } else { + this.loc = $.extend(true, {}, $.fn.datepicker.language.ru, lang) + } + + if (this.opts.dateFormat) { + this.loc.dateFormat = this.opts.dateFormat + } + + if (this.opts.timeFormat) { + this.loc.timeFormat = this.opts.timeFormat + } + + if (this.opts.firstDay !== '') { + this.loc.firstDay = this.opts.firstDay + } + + if (this.opts.timepicker) { + this.loc.dateFormat = [this.loc.dateFormat, this.loc.timeFormat].join(this.opts.dateTimeSeparator); + } + + if (this.opts.onlyTimepicker) { + this.loc.dateFormat = this.loc.timeFormat; + } + + var boundary = this._getWordBoundaryRegExp; + if (this.loc.timeFormat.match(boundary('aa')) || + this.loc.timeFormat.match(boundary('AA')) + ) { + this.ampm = true; + } + }, + + _buildDatepickersContainer: function () { + containerBuilt = true; + $body.append('
'); + $datepickersContainer = $('#datepickers-container'); + }, + + _buildBaseHtml: function () { + var $appendTarget, + $inline = $('
'); + + if(this.el.nodeName == 'INPUT') { + if (!this.opts.inline) { + $appendTarget = $datepickersContainer; + } else { + $appendTarget = $inline.insertAfter(this.$el) + } + } else { + $appendTarget = $inline.appendTo(this.$el) + } + + this.$datepicker = $(baseTemplate).appendTo($appendTarget); + this.$content = $('.datepicker--content', this.$datepicker); + this.$nav = $('.datepicker--nav', this.$datepicker); + }, + + _triggerOnChange: function () { + if (!this.selectedDates.length) { + // Prevent from triggering multiple onSelect callback with same argument (empty string) in IE10-11 + if (this._prevOnSelectValue === '') return; + this._prevOnSelectValue = ''; + return this.opts.onSelect('', '', this); + } + + var selectedDates = this.selectedDates, + parsedSelected = datepicker.getParsedDate(selectedDates[0]), + formattedDates, + _this = this, + dates = new Date( + parsedSelected.year, + parsedSelected.month, + parsedSelected.date, + parsedSelected.hours, + parsedSelected.minutes, + parsedSelected.seconds + ); + + formattedDates = selectedDates.map(function (date) { + return _this.formatDate(_this.loc.dateFormat, date) + }).join(this.opts.multipleDatesSeparator); + + // Create new dates array, to separate it from original selectedDates + if (this.opts.multipleDates || this.opts.range) { + dates = selectedDates.map(function(date) { + var parsedDate = datepicker.getParsedDate(date); + return new Date( + parsedDate.year, + parsedDate.month, + parsedDate.date, + parsedDate.hours, + parsedDate.minutes, + parsedDate.seconds + ); + }) + } + this._prevOnSelectValue = formattedDates; + this.opts.onSelect(formattedDates, dates, this); + }, + + next: function () { + var d = this.parsedDate, + o = this.opts; + switch (this.view) { + case 'days': + this.date = new Date(d.year, d.month + 1, 1); + if (o.onChangeMonth) o.onChangeMonth(this.parsedDate.month, this.parsedDate.year); + break; + case 'months': + this.date = new Date(d.year + 1, d.month, 1); + if (o.onChangeYear) o.onChangeYear(this.parsedDate.year); + break; + case 'years': + this.date = new Date(d.year + 10, 0, 1); + if (o.onChangeDecade) o.onChangeDecade(this.curDecade); + break; + } + }, + + prev: function () { + var d = this.parsedDate, + o = this.opts; + switch (this.view) { + case 'days': + this.date = new Date(d.year, d.month - 1, 1); + if (o.onChangeMonth) o.onChangeMonth(this.parsedDate.month, this.parsedDate.year); + break; + case 'months': + this.date = new Date(d.year - 1, d.month, 1); + if (o.onChangeYear) o.onChangeYear(this.parsedDate.year); + break; + case 'years': + this.date = new Date(d.year - 10, 0, 1); + if (o.onChangeDecade) o.onChangeDecade(this.curDecade); + break; + } + }, + + formatDate: function (string, date) { + date = date || this.date; + var result = string, + boundary = this._getWordBoundaryRegExp, + locale = this.loc, + leadingZero = datepicker.getLeadingZeroNum, + decade = datepicker.getDecade(date), + d = datepicker.getParsedDate(date), + fullHours = d.fullHours, + hours = d.hours, + ampm = string.match(boundary('aa')) || string.match(boundary('AA')), + dayPeriod = 'am', + replacer = this._replacer, + validHours; + + if (this.opts.timepicker && this.timepicker && ampm) { + validHours = this.timepicker._getValidHoursFromDate(date, ampm); + fullHours = leadingZero(validHours.hours); + hours = validHours.hours; + dayPeriod = validHours.dayPeriod; + } + + switch (true) { + case /@/.test(result): + result = result.replace(/@/, date.getTime()); + case /aa/.test(result): + result = replacer(result, boundary('aa'), dayPeriod); + case /AA/.test(result): + result = replacer(result, boundary('AA'), dayPeriod.toUpperCase()); + case /dd/.test(result): + result = replacer(result, boundary('dd'), d.fullDate); + case /d/.test(result): + result = replacer(result, boundary('d'), d.date); + case /DD/.test(result): + result = replacer(result, boundary('DD'), locale.days[d.day]); + case /D/.test(result): + result = replacer(result, boundary('D'), locale.daysShort[d.day]); + case /mm/.test(result): + result = replacer(result, boundary('mm'), d.fullMonth); + case /m/.test(result): + result = replacer(result, boundary('m'), d.month + 1); + case /MM/.test(result): + result = replacer(result, boundary('MM'), this.loc.months[d.month]); + case /M/.test(result): + result = replacer(result, boundary('M'), locale.monthsShort[d.month]); + case /ss/.test(result): + result = replacer(result, boundary('ss'), d.fullSeconds); + case /s/.test(result): + result = replacer(result, boundary('s'), d.seconds); + case /ii/.test(result): + result = replacer(result, boundary('ii'), d.fullMinutes); + case /i/.test(result): + result = replacer(result, boundary('i'), d.minutes); + case /hh/.test(result): + result = replacer(result, boundary('hh'), fullHours); + case /h/.test(result): + result = replacer(result, boundary('h'), hours); + case /yyyy/.test(result): + result = replacer(result, boundary('yyyy'), d.year); + case /yyyy1/.test(result): + result = replacer(result, boundary('yyyy1'), decade[0]); + case /yyyy2/.test(result): + result = replacer(result, boundary('yyyy2'), decade[1]); + case /yy/.test(result): + result = replacer(result, boundary('yy'), d.year.toString().slice(-2)); + } + + return result; + }, + + _replacer: function (str, reg, data) { + return str.replace(reg, function (match, p1,p2,p3) { + return p1 + data + p3; + }) + }, + + _getWordBoundaryRegExp: function (sign) { + var symbols = '\\s|\\.|-|/|\\\\|,|\\$|\\!|\\?|:|;'; + + return new RegExp('(^|>|' + symbols + ')(' + sign + ')($|<|' + symbols + ')', 'g'); + }, + + + selectDate: function (date) { + var _this = this, + opts = _this.opts, + d = _this.parsedDate, + selectedDates = _this.selectedDates, + len = selectedDates.length, + newDate = ''; + + if (Array.isArray(date)) { + date.forEach(function (d) { + _this.selectDate(d) + }); + return; + } + + if (!(date instanceof Date)) return; + + this.lastSelectedDate = date; + + // Set new time values from Date + if (this.timepicker) { + this.timepicker._setTime(date); + } + + // On this step timepicker will set valid values in it's instance + _this._trigger('selectDate', date); + + // Set correct time values after timepicker's validation + // Prevent from setting hours or minutes which values are lesser then `min` value or + // greater then `max` value + if (this.timepicker) { + date.setHours(this.timepicker.hours); + date.setMinutes(this.timepicker.minutes) + date.setSeconds(this.timepicker.seconds) + } + + if (_this.view == 'days') { + if (date.getMonth() != d.month && opts.moveToOtherMonthsOnSelect) { + newDate = new Date(date.getFullYear(), date.getMonth(), 1); + } + } + + if (_this.view == 'years') { + if (date.getFullYear() != d.year && opts.moveToOtherYearsOnSelect) { + newDate = new Date(date.getFullYear(), 0, 1); + } + } + + if (newDate) { + _this.silent = true; + _this.date = newDate; + _this.silent = false; + _this.nav._render() + } + + if (opts.multipleDates && !opts.range) { // Set priority to range functionality + if (len === opts.multipleDates) return; + if (!_this._isSelected(date)) { + _this.selectedDates.push(date); + } + } else if (opts.range) { + if (len == 2) { + _this.selectedDates = [date]; + _this.minRange = date; + _this.maxRange = ''; + } else if (len == 1) { + _this.selectedDates.push(date); + if (!_this.maxRange){ + _this.maxRange = date; + } else { + _this.minRange = date; + } + // Swap dates if they were selected via dp.selectDate() and second date was smaller then first + if (datepicker.bigger(_this.maxRange, _this.minRange)) { + _this.maxRange = _this.minRange; + _this.minRange = date; + } + _this.selectedDates = [_this.minRange, _this.maxRange] + + } else { + _this.selectedDates = [date]; + _this.minRange = date; + } + } else { + _this.selectedDates = [date]; + } + + _this._setInputValue(); + + if (opts.onSelect) { + _this._triggerOnChange(); + } + + if (opts.autoClose && !this.timepickerIsActive) { + if (!opts.multipleDates && !opts.range) { + _this.hide(); + } else if (opts.range && _this.selectedDates.length == 2) { + _this.hide(); + } + } + + _this.views[this.currentView]._render() + }, + + removeDate: function (date) { + var selected = this.selectedDates, + _this = this; + + if (!(date instanceof Date)) return; + + return selected.some(function (curDate, i) { + if (datepicker.isSame(curDate, date)) { + selected.splice(i, 1); + + if (!_this.selectedDates.length) { + _this.minRange = ''; + _this.maxRange = ''; + _this.lastSelectedDate = ''; + } else { + _this.lastSelectedDate = _this.selectedDates[_this.selectedDates.length - 1]; + } + + _this.views[_this.currentView]._render(); + _this._setInputValue(); + + if (_this.opts.onSelect) { + _this._triggerOnChange(); + } + + return true + } + }) + }, + + today: function () { + this.silent = true; + this.view = this.opts.minView; + this.silent = false; + this.date = new Date(); + + if (this.opts.todayButton instanceof Date) { + this.selectDate(this.opts.todayButton) + } + }, + + clear: function () { + this.selectedDates = []; + this.minRange = ''; + this.maxRange = ''; + this.views[this.currentView]._render(); + this._setInputValue(); + if (this.opts.onSelect) { + this._triggerOnChange() + } + }, + + /** + * Updates datepicker options + * @param {String|Object} param - parameter's name to update. If object then it will extend current options + * @param {String|Number|Object} [value] - new param value + */ + update: function (param, value) { + var len = arguments.length, + lastSelectedDate = this.lastSelectedDate; + + if (len == 2) { + this.opts[param] = value; + } else if (len == 1 && typeof param == 'object') { + this.opts = $.extend(true, this.opts, param) + } + + this._createShortCuts(); + this._syncWithMinMaxDates(); + this._defineLocale(this.opts.language); + this.nav._addButtonsIfNeed(); + if (!this.opts.onlyTimepicker) this.nav._render(); + this.views[this.currentView]._render(); + + if (this.elIsInput && !this.opts.inline) { + this._setPositionClasses(this.opts.position); + if (this.visible) { + this.setPosition(this.opts.position) + } + } + + if (this.opts.classes) { + this.$datepicker.addClass(this.opts.classes) + } + + if (this.opts.onlyTimepicker) { + this.$datepicker.addClass('-only-timepicker-'); + } + + if (this.opts.timepicker) { + if (lastSelectedDate) this.timepicker._handleDate(lastSelectedDate); + this.timepicker._updateRanges(); + this.timepicker._updateCurrentTime(); + // Change hours and minutes if it's values have been changed through min/max hours/minutes + if (lastSelectedDate) { + lastSelectedDate.setHours(this.timepicker.hours); + lastSelectedDate.setMinutes(this.timepicker.minutes); + lastSelectedDate.setSeconds(this.timepicker.seconds); + } + } + + this._setInputValue(); + + return this; + }, + + _syncWithMinMaxDates: function () { + var curTime = this.date.getTime(); + this.silent = true; + if (this.minTime > curTime) { + this.date = this.minDate; + } + + if (this.maxTime < curTime) { + this.date = this.maxDate; + } + this.silent = false; + }, + + _isSelected: function (checkDate, cellType) { + var res = false; + this.selectedDates.some(function (date) { + if (datepicker.isSame(date, checkDate, cellType)) { + res = date; + return true; + } + }); + return res; + }, + + _setInputValue: function () { + var _this = this, + opts = _this.opts, + format = _this.loc.dateFormat, + altFormat = opts.altFieldDateFormat, + value = _this.selectedDates.map(function (date) { + return _this.formatDate(format, date) + }), + altValues; + + if (opts.altField && _this.$altField.length) { + altValues = this.selectedDates.map(function (date) { + return _this.formatDate(altFormat, date) + }); + altValues = altValues.join(this.opts.multipleDatesSeparator); + this.$altField.val(altValues); + } + + value = value.join(this.opts.multipleDatesSeparator); + + this.$el.val(value) + }, + + /** + * Check if date is between minDate and maxDate + * @param date {object} - date object + * @param type {string} - cell type + * @returns {boolean} + * @private + */ + _isInRange: function (date, type) { + var time = date.getTime(), + d = datepicker.getParsedDate(date), + min = datepicker.getParsedDate(this.minDate), + max = datepicker.getParsedDate(this.maxDate), + dMinTime = new Date(d.year, d.month, min.date).getTime(), + dMaxTime = new Date(d.year, d.month, max.date).getTime(), + types = { + day: time >= this.minTime && time <= this.maxTime, + month: dMinTime >= this.minTime && dMaxTime <= this.maxTime, + year: d.year >= min.year && d.year <= max.year + }; + return type ? types[type] : types.day + }, + + _getDimensions: function ($el) { + var offset = $el.offset(); + + return { + width: $el.outerWidth(), + height: $el.outerHeight(), + left: offset.left, + top: offset.top + } + }, + + _getDateFromCell: function (cell) { + var curDate = this.parsedDate, + year = cell.data('year') || curDate.year, + month = cell.data('month') == undefined ? curDate.month : cell.data('month'), + date = cell.data('date') || 1; + + return new Date(year, month, date); + }, + + _setPositionClasses: function (pos) { + pos = pos.split(' '); + var main = pos[0], + sec = pos[1], + classes = 'datepicker -' + main + '-' + sec + '- -from-' + main + '-'; + + if (this.visible) classes += ' active'; + + this.$datepicker + .removeAttr('class') + .addClass(classes); + }, + + setPosition: function (position) { + position = position || this.opts.position; + + var dims = this._getDimensions(this.$el), + selfDims = this._getDimensions(this.$datepicker), + pos = position.split(' '), + top, left, + offset = this.opts.offset, + main = pos[0], + secondary = pos[1]; + + switch (main) { + case 'top': + top = dims.top - selfDims.height - offset; + break; + case 'right': + left = dims.left + dims.width + offset; + break; + case 'bottom': + top = dims.top + dims.height + offset; + break; + case 'left': + left = dims.left - selfDims.width - offset; + break; + } + + switch(secondary) { + case 'top': + top = dims.top; + break; + case 'right': + left = dims.left + dims.width - selfDims.width; + break; + case 'bottom': + top = dims.top + dims.height - selfDims.height; + break; + case 'left': + left = dims.left; + break; + case 'center': + if (/left|right/.test(main)) { + top = dims.top + dims.height/2 - selfDims.height/2; + } else { + left = dims.left + dims.width/2 - selfDims.width/2; + } + } + + this.$datepicker + .css({ + left: left, + top: top + }) + }, + + show: function () { + var onShow = this.opts.onShow; + + this.setPosition(this.opts.position); + this.$datepicker.addClass('active'); + this.visible = true; + + if (onShow) { + this._bindVisionEvents(onShow) + } + }, + + hide: function () { + var onHide = this.opts.onHide; + + this.$datepicker + .removeClass('active') + .css({ + left: '-100000px' + }); + + this.focused = ''; + this.keys = []; + + this.inFocus = false; + this.visible = false; + this.$el.blur(); + + if (onHide) { + this._bindVisionEvents(onHide) + } + }, + + down: function (date) { + this._changeView(date, 'down'); + }, + + up: function (date) { + this._changeView(date, 'up'); + }, + + _bindVisionEvents: function (event) { + this.$datepicker.off('transitionend.dp'); + event(this, false); + this.$datepicker.one('transitionend.dp', event.bind(this, this, true)) + }, + + _changeView: function (date, dir) { + date = date || this.focused || this.date; + + var nextView = dir == 'up' ? this.viewIndex + 1 : this.viewIndex - 1; + if (nextView > 2) nextView = 2; + if (nextView < 0) nextView = 0; + + this.silent = true; + this.date = new Date(date.getFullYear(), date.getMonth(), 1); + this.silent = false; + this.view = this.viewIndexes[nextView]; + + }, + + _handleHotKey: function (key) { + var date = datepicker.getParsedDate(this._getFocusedDate()), + focusedParsed, + o = this.opts, + newDate, + totalDaysInNextMonth, + monthChanged = false, + yearChanged = false, + decadeChanged = false, + y = date.year, + m = date.month, + d = date.date; + + switch (key) { + case 'ctrlRight': + case 'ctrlUp': + m += 1; + monthChanged = true; + break; + case 'ctrlLeft': + case 'ctrlDown': + m -= 1; + monthChanged = true; + break; + case 'shiftRight': + case 'shiftUp': + yearChanged = true; + y += 1; + break; + case 'shiftLeft': + case 'shiftDown': + yearChanged = true; + y -= 1; + break; + case 'altRight': + case 'altUp': + decadeChanged = true; + y += 10; + break; + case 'altLeft': + case 'altDown': + decadeChanged = true; + y -= 10; + break; + case 'ctrlShiftUp': + this.up(); + break; + } + + totalDaysInNextMonth = datepicker.getDaysCount(new Date(y,m)); + newDate = new Date(y,m,d); + + // If next month has less days than current, set date to total days in that month + if (totalDaysInNextMonth < d) d = totalDaysInNextMonth; + + // Check if newDate is in valid range + if (newDate.getTime() < this.minTime) { + newDate = this.minDate; + } else if (newDate.getTime() > this.maxTime) { + newDate = this.maxDate; + } + + this.focused = newDate; + + focusedParsed = datepicker.getParsedDate(newDate); + if (monthChanged && o.onChangeMonth) { + o.onChangeMonth(focusedParsed.month, focusedParsed.year) + } + if (yearChanged && o.onChangeYear) { + o.onChangeYear(focusedParsed.year) + } + if (decadeChanged && o.onChangeDecade) { + o.onChangeDecade(this.curDecade) + } + }, + + _registerKey: function (key) { + var exists = this.keys.some(function (curKey) { + return curKey == key; + }); + + if (!exists) { + this.keys.push(key) + } + }, + + _unRegisterKey: function (key) { + var index = this.keys.indexOf(key); + + this.keys.splice(index, 1); + }, + + _isHotKeyPressed: function () { + var currentHotKey, + found = false, + _this = this, + pressedKeys = this.keys.sort(); + + for (var hotKey in hotKeys) { + currentHotKey = hotKeys[hotKey]; + if (pressedKeys.length != currentHotKey.length) continue; + + if (currentHotKey.every(function (key, i) { return key == pressedKeys[i]})) { + _this._trigger('hotKey', hotKey); + found = true; + } + } + + return found; + }, + + _trigger: function (event, args) { + this.$el.trigger(event, args) + }, + + _focusNextCell: function (keyCode, type) { + type = type || this.cellType; + + var date = datepicker.getParsedDate(this._getFocusedDate()), + y = date.year, + m = date.month, + d = date.date; + + if (this._isHotKeyPressed()){ + return; + } + + switch(keyCode) { + case 37: // left + type == 'day' ? (d -= 1) : ''; + type == 'month' ? (m -= 1) : ''; + type == 'year' ? (y -= 1) : ''; + break; + case 38: // up + type == 'day' ? (d -= 7) : ''; + type == 'month' ? (m -= 3) : ''; + type == 'year' ? (y -= 4) : ''; + break; + case 39: // right + type == 'day' ? (d += 1) : ''; + type == 'month' ? (m += 1) : ''; + type == 'year' ? (y += 1) : ''; + break; + case 40: // down + type == 'day' ? (d += 7) : ''; + type == 'month' ? (m += 3) : ''; + type == 'year' ? (y += 4) : ''; + break; + } + + var nd = new Date(y,m,d); + if (nd.getTime() < this.minTime) { + nd = this.minDate; + } else if (nd.getTime() > this.maxTime) { + nd = this.maxDate; + } + + this.focused = nd; + + }, + + _getFocusedDate: function () { + var focused = this.focused || this.selectedDates[this.selectedDates.length - 1], + d = this.parsedDate; + + if (!focused) { + switch (this.view) { + case 'days': + focused = new Date(d.year, d.month, new Date().getDate()); + break; + case 'months': + focused = new Date(d.year, d.month, 1); + break; + case 'years': + focused = new Date(d.year, 0, 1); + break; + } + } + + return focused; + }, + + _getCell: function (date, type) { + type = type || this.cellType; + + var d = datepicker.getParsedDate(date), + selector = '.datepicker--cell[data-year="' + d.year + '"]', + $cell; + + switch (type) { + case 'month': + selector = '[data-month="' + d.month + '"]'; + break; + case 'day': + selector += '[data-month="' + d.month + '"][data-date="' + d.date + '"]'; + break; + } + $cell = this.views[this.currentView].$el.find(selector); + + return $cell.length ? $cell : $(''); + }, + + destroy: function () { + var _this = this; + _this.$el + .off('.adp') + .data('datepicker', ''); + + _this.selectedDates = []; + _this.focused = ''; + _this.views = {}; + _this.keys = []; + _this.minRange = ''; + _this.maxRange = ''; + + if (_this.opts.inline || !_this.elIsInput) { + _this.$datepicker.closest('.datepicker-inline').remove(); + } else { + _this.$datepicker.remove(); + } + }, + + _handleAlreadySelectedDates: function (alreadySelected, selectedDate) { + if (this.opts.range) { + if (!this.opts.toggleSelected) { + // Add possibility to select same date when range is true + if (this.selectedDates.length != 2) { + this._trigger('clickCell', selectedDate); + } + } else { + this.removeDate(selectedDate); + } + } else if (this.opts.toggleSelected){ + this.removeDate(selectedDate); + } + + // Change last selected date to be able to change time when clicking on this cell + if (!this.opts.toggleSelected) { + this.lastSelectedDate = alreadySelected; + if (this.opts.timepicker) { + this.timepicker._setTime(alreadySelected); + this.timepicker.update(); + } + } + }, + + _onShowEvent: function (e) { + if (!this.visible) { + this.show(); + } + }, + + _onBlur: function () { + if (!this.inFocus && this.visible) { + this.hide(); + } + }, + + _onMouseDownDatepicker: function (e) { + this.inFocus = true; + }, + + _onMouseUpDatepicker: function (e) { + this.inFocus = false; + e.originalEvent.inFocus = true; + if (!e.originalEvent.timepickerFocus) this.$el.focus(); + }, + + _onKeyUpGeneral: function (e) { + var val = this.$el.val(); + + if (!val) { + this.clear(); + } + }, + + _onResize: function () { + if (this.visible) { + this.setPosition(); + } + }, + + _onMouseUpBody: function (e) { + if (e.originalEvent.inFocus) return; + + if (this.visible && !this.inFocus) { + this.hide(); + } + }, + + _onMouseUpEl: function (e) { + e.originalEvent.inFocus = true; + setTimeout(this._onKeyUpGeneral.bind(this),4); + }, + + _onKeyDown: function (e) { + var code = e.which; + this._registerKey(code); + + // Arrows + if (code >= 37 && code <= 40) { + e.preventDefault(); + this._focusNextCell(code); + } + + // Enter + if (code == 13) { + if (this.focused) { + if (this._getCell(this.focused).hasClass('-disabled-')) return; + if (this.view != this.opts.minView) { + this.down() + } else { + var alreadySelected = this._isSelected(this.focused, this.cellType); + + if (!alreadySelected) { + if (this.timepicker) { + this.focused.setHours(this.timepicker.hours); + this.focused.setMinutes(this.timepicker.minutes); + this.focused.setSeconds(this.timepicker.seconds); + } + this.selectDate(this.focused); + return; + } + this._handleAlreadySelectedDates(alreadySelected, this.focused) + } + } + } + + // Esc + if (code == 27) { + this.hide(); + } + }, + + _onKeyUp: function (e) { + var code = e.which; + this._unRegisterKey(code); + }, + + _onHotKey: function (e, hotKey) { + this._handleHotKey(hotKey); + }, + + _onMouseEnterCell: function (e) { + var $cell = $(e.target).closest('.datepicker--cell'), + date = this._getDateFromCell($cell); + + // Prevent from unnecessary rendering and setting new currentDate + this.silent = true; + + if (this.focused) { + this.focused = '' + } + + $cell.addClass('-focus-'); + + this.focused = date; + this.silent = false; + + if (this.opts.range && this.selectedDates.length == 1) { + this.minRange = this.selectedDates[0]; + this.maxRange = ''; + if (datepicker.less(this.minRange, this.focused)) { + this.maxRange = this.minRange; + this.minRange = ''; + } + this.views[this.currentView]._update(); + } + }, + + _onMouseLeaveCell: function (e) { + var $cell = $(e.target).closest('.datepicker--cell'); + + $cell.removeClass('-focus-'); + + this.silent = true; + this.focused = ''; + this.silent = false; + }, + + _onTimeChange: function (e, h, m, s) { + var date = new Date(), + selectedDates = this.selectedDates, + selected = false; + + if (selectedDates.length) { + selected = true; + date = this.lastSelectedDate; + } + + date.setHours(h); + date.setMinutes(m); + date.setSeconds(s); + + if (!selected && !this._getCell(date).hasClass('-disabled-')) { + this.selectDate(date); + } else { + this._setInputValue(); + if (this.opts.onSelect) { + this._triggerOnChange(); + } + } + }, + + _onClickCell: function (e, date) { + if (this.timepicker) { + date.setHours(this.timepicker.hours); + date.setMinutes(this.timepicker.minutes); + date.setSeconds(this.timepicker.seconds) + } + this.selectDate(date); + }, + + set focused(val) { + if (!val && this.focused) { + var $cell = this._getCell(this.focused); + + if ($cell.length) { + $cell.removeClass('-focus-') + } + } + this._focused = val; + if (this.opts.range && this.selectedDates.length == 1) { + this.minRange = this.selectedDates[0]; + this.maxRange = ''; + if (datepicker.less(this.minRange, this._focused)) { + this.maxRange = this.minRange; + this.minRange = ''; + } + } + if (this.silent) return; + this.date = val; + }, + + get focused() { + return this._focused; + }, + + get parsedDate() { + return datepicker.getParsedDate(this.date); + }, + + set date (val) { + if (!(val instanceof Date)) return; + + this.currentDate = val; + + if (this.inited && !this.silent) { + this.views[this.view]._render(); + this.nav._render(); + if (this.visible && this.elIsInput) { + this.setPosition(); + } + } + return val; + }, + + get date () { + return this.currentDate + }, + + set view (val) { + this.viewIndex = this.viewIndexes.indexOf(val); + + if (this.viewIndex < 0) { + return; + } + + this.prevView = this.currentView; + this.currentView = val; + + if (this.inited) { + if (!this.views[val]) { + this.views[val] = new $.fn.datepicker.Body(this, val, this.opts) + } else { + this.views[val]._render(); + } + + this.views[this.prevView].hide(); + this.views[val].show(); + this.nav._render(); + + if (this.opts.onChangeView) { + this.opts.onChangeView(val) + } + if (this.elIsInput && this.visible) this.setPosition(); + } + + return val + }, + + get view() { + return this.currentView; + }, + + get cellType() { + return this.view.substring(0, this.view.length - 1) + }, + + get minTime() { + var min = datepicker.getParsedDate(this.minDate); + return new Date(min.year, min.month, min.date).getTime() + }, + + get maxTime() { + var max = datepicker.getParsedDate(this.maxDate); + return new Date(max.year, max.month, max.date).getTime() + }, + + get curDecade() { + return datepicker.getDecade(this.date) + } + }; + + // Utils + // ------------------------------------------------- + + datepicker.getDaysCount = function (date) { + return new Date(date.getFullYear(), date.getMonth() + 1, 0).getDate(); + }; + + datepicker.getParsedDate = function (date) { + return { + year: date.getFullYear(), + month: date.getMonth(), + fullMonth: (date.getMonth() + 1) < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1, // One based + date: date.getDate(), + fullDate: date.getDate() < 10 ? '0' + date.getDate() : date.getDate(), + day: date.getDay(), + hours: date.getHours(), + fullHours: date.getHours() < 10 ? '0' + date.getHours() : date.getHours() , + minutes: date.getMinutes(), + fullMinutes: date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes(), + seconds: date.getSeconds(), + fullSeconds: date.getSeconds() < 10 ? '0' + date.getSeconds() : date.getSeconds() + } + }; + + datepicker.getDecade = function (date) { + var firstYear = Math.floor(date.getFullYear() / 10) * 10; + + return [firstYear, firstYear + 9]; + }; + + datepicker.template = function (str, data) { + return str.replace(/#\{([\w]+)\}/g, function (source, match) { + if (data[match] || data[match] === 0) { + return data[match] + } + }); + }; + + datepicker.isSame = function (date1, date2, type) { + if (!date1 || !date2) return false; + var d1 = datepicker.getParsedDate(date1), + d2 = datepicker.getParsedDate(date2), + _type = type ? type : 'day', + + conditions = { + day: d1.date == d2.date && d1.month == d2.month && d1.year == d2.year, + month: d1.month == d2.month && d1.year == d2.year, + year: d1.year == d2.year + }; + + return conditions[_type]; + }; + + datepicker.less = function (dateCompareTo, date, type) { + if (!dateCompareTo || !date) return false; + return date.getTime() < dateCompareTo.getTime(); + }; + + datepicker.bigger = function (dateCompareTo, date, type) { + if (!dateCompareTo || !date) return false; + return date.getTime() > dateCompareTo.getTime(); + }; + + datepicker.getLeadingZeroNum = function (num) { + return parseInt(num) < 10 ? '0' + num : num; + }; + + /** + * Returns copy of date with hours and minutes equals to 0 + * @param date {Date} + */ + datepicker.resetTime = function (date) { + if (typeof date != 'object') return; + date = datepicker.getParsedDate(date); + return new Date(date.year, date.month, date.date) + }; + + $.fn.datepicker = function ( options ) { + return this.each(function () { + if (!$.data(this, pluginName)) { + $.data(this, pluginName, + new Datepicker( this, options )); + } else { + var _this = $.data(this, pluginName); + + _this.opts = $.extend(true, _this.opts, options); + _this.update(); + } + }); + }; + + $.fn.datepicker.Constructor = Datepicker; + + $.fn.datepicker.language = { + ru: { + days: ['Воскресенье', 'Понедельник', 'Вторник', 'Среда', 'Четверг', 'Пятница', 'Суббота'], + daysShort: ['Вос','Пон','Вто','Сре','Чет','Пят','Суб'], + daysMin: ['Вс','Пн','Вт','Ср','Чт','Пт','Сб'], + months: ['Январь', 'Февраль', 'Март', 'Апрель', 'Май', 'Июнь', 'Июль', 'Август', 'Сентябрь', 'Октябрь', 'Ноябрь', 'Декабрь'], + monthsShort: ['Янв', 'Фев', 'Мар', 'Апр', 'Май', 'Июн', 'Июл', 'Авг', 'Сен', 'Окт', 'Ноя', 'Дек'], + today: 'Сегодня', + clear: 'Очистить', + dateFormat: 'dd.mm.yyyy', + timeFormat: 'hh:ii', + firstDay: 1 + } + }; + + $(function () { + $(autoInitSelector).datepicker(); + }) + +})(); + +;(function () { + var templates = { + days:'' + + '
' + + '
' + + '
' + + '
', + months: '' + + '
' + + '
' + + '
', + years: '' + + '
' + + '
' + + '
' + }, + datepicker = $.fn.datepicker, + dp = datepicker.Constructor; + + datepicker.Body = function (d, type, opts) { + this.d = d; + this.type = type; + this.opts = opts; + this.$el = $(''); + + if (this.opts.onlyTimepicker) return; + this.init(); + }; + + datepicker.Body.prototype = { + init: function () { + this._buildBaseHtml(); + this._render(); + + this._bindEvents(); + }, + + _bindEvents: function () { + this.$el.on('click', '.datepicker--cell', $.proxy(this._onClickCell, this)); + }, + + _buildBaseHtml: function () { + this.$el = $(templates[this.type]).appendTo(this.d.$content); + this.$names = $('.datepicker--days-names', this.$el); + this.$cells = $('.datepicker--cells', this.$el); + }, + + _getDayNamesHtml: function (firstDay, curDay, html, i) { + curDay = curDay != undefined ? curDay : firstDay; + html = html ? html : ''; + i = i != undefined ? i : 0; + + if (i > 7) return html; + if (curDay == 7) return this._getDayNamesHtml(firstDay, 0, html, ++i); + + html += '
' + this.d.loc.daysMin[curDay] + '
'; + + return this._getDayNamesHtml(firstDay, ++curDay, html, ++i); + }, + + _getCellContents: function (date, type) { + var classes = "datepicker--cell datepicker--cell-" + type, + currentDate = new Date(), + parent = this.d, + minRange = dp.resetTime(parent.minRange), + maxRange = dp.resetTime(parent.maxRange), + opts = parent.opts, + d = dp.getParsedDate(date), + render = {}, + html = d.date; + + switch (type) { + case 'day': + if (parent.isWeekend(d.day)) classes += " -weekend-"; + if (d.month != this.d.parsedDate.month) { + classes += " -other-month-"; + if (!opts.selectOtherMonths) { + classes += " -disabled-"; + } + if (!opts.showOtherMonths) html = ''; + } + break; + case 'month': + html = parent.loc[parent.opts.monthsField][d.month]; + break; + case 'year': + var decade = parent.curDecade; + html = d.year; + if (d.year < decade[0] || d.year > decade[1]) { + classes += ' -other-decade-'; + if (!opts.selectOtherYears) { + classes += " -disabled-"; + } + if (!opts.showOtherYears) html = ''; + } + break; + } + + if (opts.onRenderCell) { + render = opts.onRenderCell(date, type) || {}; + html = render.html ? render.html : html; + classes += render.classes ? ' ' + render.classes : ''; + } + + if (opts.range) { + if (dp.isSame(minRange, date, type)) classes += ' -range-from-'; + if (dp.isSame(maxRange, date, type)) classes += ' -range-to-'; + + if (parent.selectedDates.length == 1 && parent.focused) { + if ( + (dp.bigger(minRange, date) && dp.less(parent.focused, date)) || + (dp.less(maxRange, date) && dp.bigger(parent.focused, date))) + { + classes += ' -in-range-' + } + + if (dp.less(maxRange, date) && dp.isSame(parent.focused, date)) { + classes += ' -range-from-' + } + if (dp.bigger(minRange, date) && dp.isSame(parent.focused, date)) { + classes += ' -range-to-' + } + + } else if (parent.selectedDates.length == 2) { + if (dp.bigger(minRange, date) && dp.less(maxRange, date)) { + classes += ' -in-range-' + } + } + } + + + if (dp.isSame(currentDate, date, type)) classes += ' -current-'; + if (parent.focused && dp.isSame(date, parent.focused, type)) classes += ' -focus-'; + if (parent._isSelected(date, type)) classes += ' -selected-'; + if (!parent._isInRange(date, type) || render.disabled) classes += ' -disabled-'; + + return { + html: html, + classes: classes + } + }, + + /** + * Calculates days number to render. Generates days html and returns it. + * @param {object} date - Date object + * @returns {string} + * @private + */ + _getDaysHtml: function (date) { + var totalMonthDays = dp.getDaysCount(date), + firstMonthDay = new Date(date.getFullYear(), date.getMonth(), 1).getDay(), + lastMonthDay = new Date(date.getFullYear(), date.getMonth(), totalMonthDays).getDay(), + daysFromPevMonth = firstMonthDay - this.d.loc.firstDay, + daysFromNextMonth = 6 - lastMonthDay + this.d.loc.firstDay; + + daysFromPevMonth = daysFromPevMonth < 0 ? daysFromPevMonth + 7 : daysFromPevMonth; + daysFromNextMonth = daysFromNextMonth > 6 ? daysFromNextMonth - 7 : daysFromNextMonth; + + var startDayIndex = -daysFromPevMonth + 1, + m, y, + html = ''; + + for (var i = startDayIndex, max = totalMonthDays + daysFromNextMonth; i <= max; i++) { + y = date.getFullYear(); + m = date.getMonth(); + + html += this._getDayHtml(new Date(y, m, i)) + } + + return html; + }, + + _getDayHtml: function (date) { + var content = this._getCellContents(date, 'day'); + + return '
' + content.html + '
'; + }, + + /** + * Generates months html + * @param {object} date - date instance + * @returns {string} + * @private + */ + _getMonthsHtml: function (date) { + var html = '', + d = dp.getParsedDate(date), + i = 0; + + while(i < 12) { + html += this._getMonthHtml(new Date(d.year, i)); + i++ + } + + return html; + }, + + _getMonthHtml: function (date) { + var content = this._getCellContents(date, 'month'); + + return '
' + content.html + '
' + }, + + _getYearsHtml: function (date) { + var d = dp.getParsedDate(date), + decade = dp.getDecade(date), + firstYear = decade[0] - 1, + html = '', + i = firstYear; + + for (i; i <= decade[1] + 1; i++) { + html += this._getYearHtml(new Date(i , 0)); + } + + return html; + }, + + _getYearHtml: function (date) { + var content = this._getCellContents(date, 'year'); + + return '
' + content.html + '
' + }, + + _renderTypes: { + days: function () { + var dayNames = this._getDayNamesHtml(this.d.loc.firstDay), + days = this._getDaysHtml(this.d.currentDate); + + this.$cells.html(days); + this.$names.html(dayNames) + }, + months: function () { + var html = this._getMonthsHtml(this.d.currentDate); + + this.$cells.html(html) + }, + years: function () { + var html = this._getYearsHtml(this.d.currentDate); + + this.$cells.html(html) + } + }, + + _render: function () { + if (this.opts.onlyTimepicker) return; + this._renderTypes[this.type].bind(this)(); + }, + + _update: function () { + var $cells = $('.datepicker--cell', this.$cells), + _this = this, + classes, + $cell, + date; + $cells.each(function (cell, i) { + $cell = $(this); + date = _this.d._getDateFromCell($(this)); + classes = _this._getCellContents(date, _this.d.cellType); + $cell.attr('class',classes.classes) + }); + }, + + show: function () { + if (this.opts.onlyTimepicker) return; + this.$el.addClass('active'); + this.acitve = true; + }, + + hide: function () { + this.$el.removeClass('active'); + this.active = false; + }, + + // Events + // ------------------------------------------------- + + _handleClick: function (el) { + var date = el.data('date') || 1, + month = el.data('month') || 0, + year = el.data('year') || this.d.parsedDate.year, + dp = this.d; + // Change view if min view does not reach yet + if (dp.view != this.opts.minView) { + dp.down(new Date(year, month, date)); + return; + } + // Select date if min view is reached + var selectedDate = new Date(year, month, date), + alreadySelected = this.d._isSelected(selectedDate, this.d.cellType); + + if (!alreadySelected) { + dp._trigger('clickCell', selectedDate); + return; + } + + dp._handleAlreadySelectedDates.bind(dp, alreadySelected, selectedDate)(); + + }, + + _onClickCell: function (e) { + var $el = $(e.target).closest('.datepicker--cell'); + + if ($el.hasClass('-disabled-')) return; + + this._handleClick.bind(this)($el); + } + }; +})(); + +;(function () { + var template = '' + + '
#{prevHtml}
' + + '
#{title}
' + + '
#{nextHtml}
', + buttonsContainerTemplate = '
', + button = '#{label}', + datepicker = $.fn.datepicker, + dp = datepicker.Constructor; + + datepicker.Navigation = function (d, opts) { + this.d = d; + this.opts = opts; + + this.$buttonsContainer = ''; + + this.init(); + }; + + datepicker.Navigation.prototype = { + init: function () { + this._buildBaseHtml(); + this._bindEvents(); + }, + + _bindEvents: function () { + this.d.$nav.on('click', '.datepicker--nav-action', $.proxy(this._onClickNavButton, this)); + this.d.$nav.on('click', '.datepicker--nav-title', $.proxy(this._onClickNavTitle, this)); + this.d.$datepicker.on('click', '.datepicker--button', $.proxy(this._onClickNavButton, this)); + }, + + _buildBaseHtml: function () { + if (!this.opts.onlyTimepicker) { + this._render(); + } + this._addButtonsIfNeed(); + }, + + _addButtonsIfNeed: function () { + if (this.opts.todayButton) { + this._addButton('today') + } + if (this.opts.clearButton) { + this._addButton('clear') + } + }, + + _render: function () { + var title = this._getTitle(this.d.currentDate), + html = dp.template(template, $.extend({title: title}, this.opts)); + this.d.$nav.html(html); + if (this.d.view == 'years') { + $('.datepicker--nav-title', this.d.$nav).addClass('-disabled-'); + } + this.setNavStatus(); + }, + + _getTitle: function (date) { + return this.d.formatDate(this.opts.navTitles[this.d.view], date) + }, + + _addButton: function (type) { + if (!this.$buttonsContainer.length) { + this._addButtonsContainer(); + } + + var data = { + action: type, + label: this.d.loc[type] + }, + html = dp.template(button, data); + + if ($('[data-action=' + type + ']', this.$buttonsContainer).length) return; + this.$buttonsContainer.append(html); + }, + + _addButtonsContainer: function () { + this.d.$datepicker.append(buttonsContainerTemplate); + this.$buttonsContainer = $('.datepicker--buttons', this.d.$datepicker); + }, + + setNavStatus: function () { + if (!(this.opts.minDate || this.opts.maxDate) || !this.opts.disableNavWhenOutOfRange) return; + + var date = this.d.parsedDate, + m = date.month, + y = date.year, + d = date.date; + + switch (this.d.view) { + case 'days': + if (!this.d._isInRange(new Date(y, m-1, 1), 'month')) { + this._disableNav('prev') + } + if (!this.d._isInRange(new Date(y, m+1, 1), 'month')) { + this._disableNav('next') + } + break; + case 'months': + if (!this.d._isInRange(new Date(y-1, m, d), 'year')) { + this._disableNav('prev') + } + if (!this.d._isInRange(new Date(y+1, m, d), 'year')) { + this._disableNav('next') + } + break; + case 'years': + var decade = dp.getDecade(this.d.date); + if (!this.d._isInRange(new Date(decade[0] - 1, 0, 1), 'year')) { + this._disableNav('prev') + } + if (!this.d._isInRange(new Date(decade[1] + 1, 0, 1), 'year')) { + this._disableNav('next') + } + break; + } + }, + + _disableNav: function (nav) { + $('[data-action="' + nav + '"]', this.d.$nav).addClass('-disabled-') + }, + + _activateNav: function (nav) { + $('[data-action="' + nav + '"]', this.d.$nav).removeClass('-disabled-') + }, + + _onClickNavButton: function (e) { + var $el = $(e.target).closest('[data-action]'), + action = $el.data('action'); + + this.d[action](); + }, + + _onClickNavTitle: function (e) { + if ($(e.target).hasClass('-disabled-')) return; + + if (this.d.view == 'days') { + return this.d.view = 'months' + } + + this.d.view = 'years'; + } + } + +})(); + +;(function () { + var template = '
' + + '
' + + ' #{hourVisible}' + + ' :' + + ' #{minValue}' + + ' :' + + ' #{secValue}' + + '
' + + '
' + + '
' + + ' ' + + '
' + + '
' + + ' ' + + '
' + + '
' + + ' ' + + '
' + + '
' + + '
', + datepicker = $.fn.datepicker, + dp = datepicker.Constructor; + + datepicker.Timepicker = function (inst, opts) { + this.d = inst; + this.opts = opts; + + this.init(); + }; + + datepicker.Timepicker.prototype = { + init: function () { + var input = 'input'; + this._setTime(this.d.date); + this._buildHTML(); + + if (navigator.userAgent.match(/trident/gi)) { + input = 'change'; + } + + this.d.$el.on('selectDate', this._onSelectDate.bind(this)); + this.$ranges.on(input, this._onChangeRange.bind(this)); + this.$ranges.on('mouseup', this._onMouseUpRange.bind(this)); + this.$ranges.on('mousemove focus ', this._onMouseEnterRange.bind(this)); + this.$ranges.on('mouseout blur', this._onMouseOutRange.bind(this)); + }, + + _setTime: function (date) { + var _date = dp.getParsedDate(date); + + this._handleDate(date); + this.hours = _date.hours < this.minHours ? this.minHours : _date.hours; + this.minutes = _date.minutes < this.minMinutes ? this.minMinutes : _date.minutes; + this.seconds = _date.seconds < this.minSeconds ? this.minSeconds : _date.seconds; + }, + + /** + * Sets minHours and minMinutes from date (usually it's a minDate) + * Also changes minMinutes if current hours are bigger then @date hours + * @param date {Date} + * @private + */ + _setMinTimeFromDate: function (date) { + this.minHours = date.getHours(); + this.minMinutes = date.getMinutes(); + this.minSeconds = date.getSeconds(); + + // If, for example, min hours are 10, and current hours are 12, + // update minMinutes to default value, to be able to choose whole range of values + if (this.d.lastSelectedDate) { + if (this.d.lastSelectedDate.getHours() > date.getHours()) { + this.minMinutes = this.opts.minMinutes; + } + } + }, + + _setMaxTimeFromDate: function (date) { + this.maxHours = date.getHours(); + this.maxMinutes = date.getMinutes(); + this.maxSeconds = date.getSeconds(); + + if (this.d.lastSelectedDate) { + if (this.d.lastSelectedDate.getHours() < date.getHours()) { + this.maxMinutes = this.opts.maxMinutes; + } + } + }, + + _setDefaultMinMaxTime: function () { + var maxHours = 23, + maxMinutes = 59, + maxSeconds = 59, + opts = this.opts; + + this.minHours = opts.minHours < 0 || opts.minHours > maxHours ? 0 : opts.minHours; + this.minMinutes = opts.minMinutes < 0 || opts.minMinutes > maxMinutes ? 0 : opts.minMinutes; + this.maxHours = opts.maxHours < 0 || opts.maxHours > maxHours ? maxHours : opts.maxHours; + this.maxMinutes = opts.maxMinutes < 0 || opts.maxMinutes > maxMinutes ? maxMinutes : opts.maxMinutes; + this.minSeconds = opts.minSeconds < 0 || opts.minSeconds > maxSeconds ? 0 : opts.minSeconds; + this.maxSeconds = opts.maxSeconds < 0 || opts.maxSeconds > maxSeconds ? maxSeconds : opts.maxSeconds; + }, + + /** + * Looks for min/max hours/minutes and if current values + * are out of range sets valid values. + * @private + */ + _validateHoursMinutes: function (date) { + if (this.hours < this.minHours) { + this.hours = this.minHours; + } else if (this.hours > this.maxHours) { + this.hours = this.maxHours; + } + + if (this.minutes < this.minMinutes) { + this.minutes = this.minMinutes; + } else if (this.minutes > this.maxMinutes) { + this.minutes = this.maxMinutes; + } + + if (this.seconds < this.minSeconds) { + this.seconds = this.minSeconds; + } else if (this.seconds > this.maxSeconds) { + this.seconds = this.maxSeconds; + } + }, + + _buildHTML: function () { + var lz = dp.getLeadingZeroNum, + data = { + hourMin: this.minHours, + hourMax: lz(this.maxHours), + hourStep: this.opts.hoursStep, + hourValue: this.hours, + hourVisible: lz(this.displayHours), + minMin: this.minMinutes, + minMax: lz(this.maxMinutes), + minStep: this.opts.minutesStep, + minValue: lz(this.minutes), + secMin: this.minSeconds, + secMax: lz(this.maxSeconds), + secStep: this.opts.secondsStep, + secValue: lz(this.seconds) + }, + _template = dp.template(template, data); + + this.$timepicker = $(_template).appendTo(this.d.$datepicker); + this.$ranges = $('[type="range"]', this.$timepicker); + this.$hours = $('[name="hours"]', this.$timepicker); + this.$minutes = $('[name="minutes"]', this.$timepicker); + this.$seconds = $('[name="seconds"]', this.$timepicker); + this.$hoursText = $('.datepicker--time-current-hours', this.$timepicker); + this.$minutesText = $('.datepicker--time-current-minutes', this.$timepicker); + this.$secondsText = $('.datepicker--time-current-seconds', this.$timepicker); + + if (this.d.ampm) { + this.$ampm = $('') + .appendTo($('.datepicker--time-current', this.$timepicker)) + .html(this.dayPeriod); + + this.$timepicker.addClass('-am-pm-'); + } + }, + + _updateCurrentTime: function () { + var h = dp.getLeadingZeroNum(this.displayHours), + m = dp.getLeadingZeroNum(this.minutes), + s = dp.getLeadingZeroNum(this.seconds); + + this.$hoursText.html(h); + this.$minutesText.html(m); + this.$secondsText.html(s); + + if (this.d.ampm) { + this.$ampm.html(this.dayPeriod); + } + }, + + _updateRanges: function () { + this.$hours.attr({ + min: this.minHours, + max: this.maxHours + }).val(this.hours); + + this.$minutes.attr({ + min: this.minMinutes, + max: this.maxMinutes + }).val(this.minutes); + + this.$seconds.attr({ + min: this.minSeconds, + max: this.maxSeconds + }).val(this.seconds); + }, + + /** + * Sets minHours, minMinutes etc. from date. If date is not passed, than sets + * values from options + * @param [date] {object} - Date object, to get values from + * @private + */ + _handleDate: function (date) { + this._setDefaultMinMaxTime(); + if (date) { + if (dp.isSame(date, this.d.opts.minDate)) { + this._setMinTimeFromDate(this.d.opts.minDate); + } else if (dp.isSame(date, this.d.opts.maxDate)) { + this._setMaxTimeFromDate(this.d.opts.maxDate); + } + } + + this._validateHoursMinutes(date); + }, + + update: function () { + this._updateRanges(); + this._updateCurrentTime(); + }, + + /** + * Calculates valid hour value to display in text input and datepicker's body. + * @param date {Date|Number} - date or hours + * @param [ampm] {Boolean} - 12 hours mode + * @returns {{hours: *, dayPeriod: string}} + * @private + */ + _getValidHoursFromDate: function (date, ampm) { + var d = date, + hours = date; + + if (date instanceof Date) { + d = dp.getParsedDate(date); + hours = d.hours; + } + + var _ampm = ampm || this.d.ampm, + dayPeriod = 'am'; + + if (_ampm) { + switch(true) { + case hours == 0: + hours = 12; + break; + case hours == 12: + dayPeriod = 'pm'; + break; + case hours > 11: + hours = hours - 12; + dayPeriod = 'pm'; + break; + default: + break; + } + } + + return { + hours: hours, + dayPeriod: dayPeriod + } + }, + + set hours (val) { + this._hours = val; + + var displayHours = this._getValidHoursFromDate(val); + + this.displayHours = displayHours.hours; + this.dayPeriod = displayHours.dayPeriod; + }, + + get hours() { + return this._hours; + }, + + // Events + // ------------------------------------------------- + + _onChangeRange: function (e) { + var $target = $(e.target), + name = $target.attr('name'); + + this.d.timepickerIsActive = true; + + this[name] = $target.val(); + this._updateCurrentTime(); + this.d._trigger('timeChange', [this.hours, this.minutes, this.seconds]); + + this._handleDate(this.d.lastSelectedDate); + this.update() + }, + + _onSelectDate: function (e, data) { + this._handleDate(data); + this.update(); + }, + + _onMouseEnterRange: function (e) { + var name = $(e.target).attr('name'); + $('.datepicker--time-current-' + name, this.$timepicker).addClass('-focus-'); + }, + + _onMouseOutRange: function (e) { + var name = $(e.target).attr('name'); + if (this.d.inFocus) return; // Prevent removing focus when mouse out of range slider + $('.datepicker--time-current-' + name, this.$timepicker).removeClass('-focus-'); + }, + + _onMouseUpRange: function (e) { + this.d.timepickerIsActive = false; + } + }; +})(); + })(window, jQuery); \ No newline at end of file diff --git a/dist/js/datepicker.min.js b/dist/js/datepicker.min.js new file mode 100644 index 0000000..c612ede --- /dev/null +++ b/dist/js/datepicker.min.js @@ -0,0 +1,2 @@ +!function(t,e,s){!function(){var i,a,n,h="2.2.3",o="datepicker",r=".datepicker-here",c=!1,d='
',l={classes:"",inline:!1,language:"ru",startDate:new Date,firstDay:"",weekends:[6,0],dateFormat:"",altField:"",altFieldDateFormat:"@",toggleSelected:!0,keyboardNav:!0,position:"bottom left",offset:12,view:"days",minView:"days",showOtherMonths:!0,selectOtherMonths:!0,moveToOtherMonthsOnSelect:!0,showOtherYears:!0,selectOtherYears:!0,moveToOtherYearsOnSelect:!0,minDate:"",maxDate:"",disableNavWhenOutOfRange:!0,multipleDates:!1,multipleDatesSeparator:",",range:!1,todayButton:!1,clearButton:!1,showEvent:"focus",autoClose:!1,monthsField:"monthsShort",prevHtml:'',nextHtml:'',navTitles:{days:"MM, yyyy",months:"yyyy",years:"yyyy1 - yyyy2"},timepicker:!1,onlyTimepicker:!1,dateTimeSeparator:" ",timeFormat:"",minHours:0,maxHours:24,minMinutes:0,maxMinutes:59,minSeconds:0,maxSeconds:59,hoursStep:1,minutesStep:1,secondsStep:1,onSelect:"",onShow:"",onHide:"",onChangeMonth:"",onChangeYear:"",onChangeDecade:"",onChangeView:"",onRenderCell:""},u={ctrlRight:[17,39],ctrlUp:[17,38],ctrlLeft:[17,37],ctrlDown:[17,40],shiftRight:[16,39],shiftUp:[16,38],shiftLeft:[16,37],shiftDown:[16,40],altUp:[18,38],altRight:[18,39],altLeft:[18,37],altDown:[18,40],ctrlShiftUp:[16,17,38]},m=function(t,a){this.el=t,this.$el=e(t),this.opts=e.extend(!0,{},l,a,this.$el.data()),i==s&&(i=e("body")),this.opts.startDate||(this.opts.startDate=new Date),"INPUT"==this.el.nodeName&&(this.elIsInput=!0),this.opts.altField&&(this.$altField="string"==typeof this.opts.altField?e(this.opts.altField):this.opts.altField),this.inited=!1,this.visible=!1,this.silent=!1,this.currentDate=this.opts.startDate,this.currentView=this.opts.view,this._createShortCuts(),this.selectedDates=[],this.views={},this.keys=[],this.minRange="",this.maxRange="",this._prevOnSelectValue="",this.init()};n=m,n.prototype={VERSION:h,viewIndexes:["days","months","years"],init:function(){c||this.opts.inline||!this.elIsInput||this._buildDatepickersContainer(),this._buildBaseHtml(),this._defineLocale(this.opts.language),this._syncWithMinMaxDates(),this.elIsInput&&(this.opts.inline||(this._setPositionClasses(this.opts.position),this._bindEvents()),this.opts.keyboardNav&&!this.opts.onlyTimepicker&&this._bindKeyboardEvents(),this.$datepicker.on("mousedown",this._onMouseDownDatepicker.bind(this)),this.$datepicker.on("mouseup",this._onMouseUpDatepicker.bind(this))),this.opts.classes&&this.$datepicker.addClass(this.opts.classes),this.opts.timepicker&&(this.timepicker=new e.fn.datepicker.Timepicker(this,this.opts),this._bindTimepickerEvents()),this.opts.onlyTimepicker&&this.$datepicker.addClass("-only-timepicker-"),this.views[this.currentView]=new e.fn.datepicker.Body(this,this.currentView,this.opts),this.views[this.currentView].show(),this.nav=new e.fn.datepicker.Navigation(this,this.opts),this.view=this.currentView,this.$el.on("clickCell.adp",this._onClickCell.bind(this)),this.$datepicker.on("mouseenter",".datepicker--cell",this._onMouseEnterCell.bind(this)),this.$datepicker.on("mouseleave",".datepicker--cell",this._onMouseLeaveCell.bind(this)),this.inited=!0},_createShortCuts:function(){this.minDate=this.opts.minDate?this.opts.minDate:new Date((-86399999136e5)),this.maxDate=this.opts.maxDate?this.opts.maxDate:new Date(86399999136e5)},_bindEvents:function(){this.$el.on(this.opts.showEvent+".adp",this._onShowEvent.bind(this)),this.$el.on("mouseup.adp",this._onMouseUpEl.bind(this)),this.$el.on("blur.adp",this._onBlur.bind(this)),this.$el.on("keyup.adp",this._onKeyUpGeneral.bind(this)),e(t).on("resize.adp",this._onResize.bind(this)),e("body").on("mouseup.adp",this._onMouseUpBody.bind(this))},_bindKeyboardEvents:function(){this.$el.on("keydown.adp",this._onKeyDown.bind(this)),this.$el.on("keyup.adp",this._onKeyUp.bind(this)),this.$el.on("hotKey.adp",this._onHotKey.bind(this))},_bindTimepickerEvents:function(){this.$el.on("timeChange.adp",this._onTimeChange.bind(this))},isWeekend:function(t){return this.opts.weekends.indexOf(t)!==-1},_defineLocale:function(t){"string"==typeof t?(this.loc=e.fn.datepicker.language[t],this.loc||(console.warn("Can't find language \""+t+'" in Datepicker.language, will use "ru" instead'),this.loc=e.extend(!0,{},e.fn.datepicker.language.ru)),this.loc=e.extend(!0,{},e.fn.datepicker.language.ru,e.fn.datepicker.language[t])):this.loc=e.extend(!0,{},e.fn.datepicker.language.ru,t),this.opts.dateFormat&&(this.loc.dateFormat=this.opts.dateFormat),this.opts.timeFormat&&(this.loc.timeFormat=this.opts.timeFormat),""!==this.opts.firstDay&&(this.loc.firstDay=this.opts.firstDay),this.opts.timepicker&&(this.loc.dateFormat=[this.loc.dateFormat,this.loc.timeFormat].join(this.opts.dateTimeSeparator)),this.opts.onlyTimepicker&&(this.loc.dateFormat=this.loc.timeFormat);var s=this._getWordBoundaryRegExp;(this.loc.timeFormat.match(s("aa"))||this.loc.timeFormat.match(s("AA")))&&(this.ampm=!0)},_buildDatepickersContainer:function(){c=!0,i.append('
'),a=e("#datepickers-container")},_buildBaseHtml:function(){var t,s=e('
');t="INPUT"==this.el.nodeName?this.opts.inline?s.insertAfter(this.$el):a:s.appendTo(this.$el),this.$datepicker=e(d).appendTo(t),this.$content=e(".datepicker--content",this.$datepicker),this.$nav=e(".datepicker--nav",this.$datepicker)},_triggerOnChange:function(){if(!this.selectedDates.length){if(""===this._prevOnSelectValue)return;return this._prevOnSelectValue="",this.opts.onSelect("","",this)}var t,e=this.selectedDates,s=n.getParsedDate(e[0]),i=this,a=new Date(s.year,s.month,s.date,s.hours,s.minutes,s.seconds);t=e.map(function(t){return i.formatDate(i.loc.dateFormat,t)}).join(this.opts.multipleDatesSeparator),(this.opts.multipleDates||this.opts.range)&&(a=e.map(function(t){var e=n.getParsedDate(t);return new Date(e.year,e.month,e.date,e.hours,e.minutes,e.seconds)})),this._prevOnSelectValue=t,this.opts.onSelect(t,a,this)},next:function(){var t=this.parsedDate,e=this.opts;switch(this.view){case"days":this.date=new Date(t.year,t.month+1,1),e.onChangeMonth&&e.onChangeMonth(this.parsedDate.month,this.parsedDate.year);break;case"months":this.date=new Date(t.year+1,t.month,1),e.onChangeYear&&e.onChangeYear(this.parsedDate.year);break;case"years":this.date=new Date(t.year+10,0,1),e.onChangeDecade&&e.onChangeDecade(this.curDecade)}},prev:function(){var t=this.parsedDate,e=this.opts;switch(this.view){case"days":this.date=new Date(t.year,t.month-1,1),e.onChangeMonth&&e.onChangeMonth(this.parsedDate.month,this.parsedDate.year);break;case"months":this.date=new Date(t.year-1,t.month,1),e.onChangeYear&&e.onChangeYear(this.parsedDate.year);break;case"years":this.date=new Date(t.year-10,0,1),e.onChangeDecade&&e.onChangeDecade(this.curDecade)}},formatDate:function(t,e){e=e||this.date;var s,i=t,a=this._getWordBoundaryRegExp,h=this.loc,o=n.getLeadingZeroNum,r=n.getDecade(e),c=n.getParsedDate(e),d=c.fullHours,l=c.hours,u=t.match(a("aa"))||t.match(a("AA")),m="am",p=this._replacer;switch(this.opts.timepicker&&this.timepicker&&u&&(s=this.timepicker._getValidHoursFromDate(e,u),d=o(s.hours),l=s.hours,m=s.dayPeriod),!0){case/@/.test(i):i=i.replace(/@/,e.getTime());case/aa/.test(i):i=p(i,a("aa"),m);case/AA/.test(i):i=p(i,a("AA"),m.toUpperCase());case/dd/.test(i):i=p(i,a("dd"),c.fullDate);case/d/.test(i):i=p(i,a("d"),c.date);case/DD/.test(i):i=p(i,a("DD"),h.days[c.day]);case/D/.test(i):i=p(i,a("D"),h.daysShort[c.day]);case/mm/.test(i):i=p(i,a("mm"),c.fullMonth);case/m/.test(i):i=p(i,a("m"),c.month+1);case/MM/.test(i):i=p(i,a("MM"),this.loc.months[c.month]);case/M/.test(i):i=p(i,a("M"),h.monthsShort[c.month]);case/ss/.test(i):i=p(i,a("ss"),c.fullSeconds);case/s/.test(i):i=p(i,a("s"),c.seconds);case/ii/.test(i):i=p(i,a("ii"),c.fullMinutes);case/i/.test(i):i=p(i,a("i"),c.minutes);case/hh/.test(i):i=p(i,a("hh"),d);case/h/.test(i):i=p(i,a("h"),l);case/yyyy/.test(i):i=p(i,a("yyyy"),c.year);case/yyyy1/.test(i):i=p(i,a("yyyy1"),r[0]);case/yyyy2/.test(i):i=p(i,a("yyyy2"),r[1]);case/yy/.test(i):i=p(i,a("yy"),c.year.toString().slice(-2))}return i},_replacer:function(t,e,s){return t.replace(e,function(t,e,i,a){return e+s+a})},_getWordBoundaryRegExp:function(t){var e="\\s|\\.|-|/|\\\\|,|\\$|\\!|\\?|:|;";return new RegExp("(^|>|"+e+")("+t+")($|<|"+e+")","g")},selectDate:function(t){var e=this,s=e.opts,i=e.parsedDate,a=e.selectedDates,h=a.length,o="";if(Array.isArray(t))return void t.forEach(function(t){e.selectDate(t)});if(t instanceof Date){if(this.lastSelectedDate=t,this.timepicker&&this.timepicker._setTime(t),e._trigger("selectDate",t),this.timepicker&&(t.setHours(this.timepicker.hours),t.setMinutes(this.timepicker.minutes),t.setSeconds(this.timepicker.seconds)),"days"==e.view&&t.getMonth()!=i.month&&s.moveToOtherMonthsOnSelect&&(o=new Date(t.getFullYear(),t.getMonth(),1)),"years"==e.view&&t.getFullYear()!=i.year&&s.moveToOtherYearsOnSelect&&(o=new Date(t.getFullYear(),0,1)),o&&(e.silent=!0,e.date=o,e.silent=!1,e.nav._render()),s.multipleDates&&!s.range){if(h===s.multipleDates)return;e._isSelected(t)||e.selectedDates.push(t)}else s.range?2==h?(e.selectedDates=[t],e.minRange=t,e.maxRange=""):1==h?(e.selectedDates.push(t),e.maxRange?e.minRange=t:e.maxRange=t,n.bigger(e.maxRange,e.minRange)&&(e.maxRange=e.minRange,e.minRange=t),e.selectedDates=[e.minRange,e.maxRange]):(e.selectedDates=[t],e.minRange=t):e.selectedDates=[t];e._setInputValue(),s.onSelect&&e._triggerOnChange(),s.autoClose&&!this.timepickerIsActive&&(s.multipleDates||s.range?s.range&&2==e.selectedDates.length&&e.hide():e.hide()),e.views[this.currentView]._render()}},removeDate:function(t){var e=this.selectedDates,s=this;if(t instanceof Date)return e.some(function(i,a){if(n.isSame(i,t))return e.splice(a,1),s.selectedDates.length?s.lastSelectedDate=s.selectedDates[s.selectedDates.length-1]:(s.minRange="",s.maxRange="",s.lastSelectedDate=""),s.views[s.currentView]._render(),s._setInputValue(),s.opts.onSelect&&s._triggerOnChange(),!0})},today:function(){this.silent=!0,this.view=this.opts.minView,this.silent=!1,this.date=new Date,this.opts.todayButton instanceof Date&&this.selectDate(this.opts.todayButton)},clear:function(){this.selectedDates=[],this.minRange="",this.maxRange="",this.views[this.currentView]._render(),this._setInputValue(),this.opts.onSelect&&this._triggerOnChange()},update:function(t,s){var i=arguments.length,a=this.lastSelectedDate;return 2==i?this.opts[t]=s:1==i&&"object"==typeof t&&(this.opts=e.extend(!0,this.opts,t)),this._createShortCuts(),this._syncWithMinMaxDates(),this._defineLocale(this.opts.language),this.nav._addButtonsIfNeed(),this.opts.onlyTimepicker||this.nav._render(),this.views[this.currentView]._render(),this.elIsInput&&!this.opts.inline&&(this._setPositionClasses(this.opts.position),this.visible&&this.setPosition(this.opts.position)),this.opts.classes&&this.$datepicker.addClass(this.opts.classes),this.opts.onlyTimepicker&&this.$datepicker.addClass("-only-timepicker-"),this.opts.timepicker&&(a&&this.timepicker._handleDate(a),this.timepicker._updateRanges(),this.timepicker._updateCurrentTime(),a&&(a.setHours(this.timepicker.hours),a.setMinutes(this.timepicker.minutes),a.setSeconds(this.timepicker.seconds))),this._setInputValue(),this},_syncWithMinMaxDates:function(){var t=this.date.getTime();this.silent=!0,this.minTime>t&&(this.date=this.minDate),this.maxTime=this.minTime&&s<=this.maxTime,month:o>=this.minTime&&r<=this.maxTime,year:i.year>=a.year&&i.year<=h.year};return e?c[e]:c.day},_getDimensions:function(t){var e=t.offset();return{width:t.outerWidth(),height:t.outerHeight(),left:e.left,top:e.top}},_getDateFromCell:function(t){var e=this.parsedDate,i=t.data("year")||e.year,a=t.data("month")==s?e.month:t.data("month"),n=t.data("date")||1;return new Date(i,a,n)},_setPositionClasses:function(t){t=t.split(" ");var e=t[0],s=t[1],i="datepicker -"+e+"-"+s+"- -from-"+e+"-";this.visible&&(i+=" active"),this.$datepicker.removeAttr("class").addClass(i)},setPosition:function(t){t=t||this.opts.position;var e,s,i=this._getDimensions(this.$el),a=this._getDimensions(this.$datepicker),n=t.split(" "),h=this.opts.offset,o=n[0],r=n[1];switch(o){case"top":e=i.top-a.height-h;break;case"right":s=i.left+i.width+h;break;case"bottom":e=i.top+i.height+h;break;case"left":s=i.left-a.width-h}switch(r){case"top":e=i.top;break;case"right":s=i.left+i.width-a.width;break;case"bottom":e=i.top+i.height-a.height;break;case"left":s=i.left;break;case"center":/left|right/.test(o)?e=i.top+i.height/2-a.height/2:s=i.left+i.width/2-a.width/2}this.$datepicker.css({left:s,top:e})},show:function(){var t=this.opts.onShow;this.setPosition(this.opts.position),this.$datepicker.addClass("active"),this.visible=!0,t&&this._bindVisionEvents(t)},hide:function(){var t=this.opts.onHide;this.$datepicker.removeClass("active").css({left:"-100000px"}),this.focused="",this.keys=[],this.inFocus=!1,this.visible=!1,this.$el.blur(),t&&this._bindVisionEvents(t)},down:function(t){this._changeView(t,"down")},up:function(t){this._changeView(t,"up")},_bindVisionEvents:function(t){this.$datepicker.off("transitionend.dp"),t(this,!1),this.$datepicker.one("transitionend.dp",t.bind(this,this,!0))},_changeView:function(t,e){t=t||this.focused||this.date;var s="up"==e?this.viewIndex+1:this.viewIndex-1;s>2&&(s=2),s<0&&(s=0),this.silent=!0,this.date=new Date(t.getFullYear(),t.getMonth(),1),this.silent=!1,this.view=this.viewIndexes[s]},_handleHotKey:function(t){var e,s,i,a=n.getParsedDate(this._getFocusedDate()),h=this.opts,o=!1,r=!1,c=!1,d=a.year,l=a.month,u=a.date;switch(t){case"ctrlRight":case"ctrlUp":l+=1,o=!0;break;case"ctrlLeft":case"ctrlDown":l-=1,o=!0;break;case"shiftRight":case"shiftUp":r=!0,d+=1;break;case"shiftLeft":case"shiftDown":r=!0,d-=1;break;case"altRight":case"altUp":c=!0,d+=10;break;case"altLeft":case"altDown":c=!0,d-=10;break;case"ctrlShiftUp":this.up()}i=n.getDaysCount(new Date(d,l)),s=new Date(d,l,u),ithis.maxTime&&(s=this.maxDate),this.focused=s,e=n.getParsedDate(s),o&&h.onChangeMonth&&h.onChangeMonth(e.month,e.year),r&&h.onChangeYear&&h.onChangeYear(e.year),c&&h.onChangeDecade&&h.onChangeDecade(this.curDecade)},_registerKey:function(t){var e=this.keys.some(function(e){return e==t});e||this.keys.push(t)},_unRegisterKey:function(t){var e=this.keys.indexOf(t);this.keys.splice(e,1)},_isHotKeyPressed:function(){var t,e=!1,s=this,i=this.keys.sort();for(var a in u)t=u[a],i.length==t.length&&t.every(function(t,e){return t==i[e]})&&(s._trigger("hotKey",a),e=!0);return e},_trigger:function(t,e){this.$el.trigger(t,e)},_focusNextCell:function(t,e){e=e||this.cellType;var s=n.getParsedDate(this._getFocusedDate()),i=s.year,a=s.month,h=s.date;if(!this._isHotKeyPressed()){switch(t){case 37:"day"==e?h-=1:"","month"==e?a-=1:"","year"==e?i-=1:"";break;case 38:"day"==e?h-=7:"","month"==e?a-=3:"","year"==e?i-=4:"";break;case 39:"day"==e?h+=1:"","month"==e?a+=1:"","year"==e?i+=1:"";break;case 40:"day"==e?h+=7:"","month"==e?a+=3:"","year"==e?i+=4:""}var o=new Date(i,a,h);o.getTime()this.maxTime&&(o=this.maxDate),this.focused=o}},_getFocusedDate:function(){var t=this.focused||this.selectedDates[this.selectedDates.length-1],e=this.parsedDate;if(!t)switch(this.view){case"days":t=new Date(e.year,e.month,(new Date).getDate());break;case"months":t=new Date(e.year,e.month,1);break;case"years":t=new Date(e.year,0,1)}return t},_getCell:function(t,s){s=s||this.cellType;var i,a=n.getParsedDate(t),h='.datepicker--cell[data-year="'+a.year+'"]';switch(s){case"month":h='[data-month="'+a.month+'"]';break;case"day":h+='[data-month="'+a.month+'"][data-date="'+a.date+'"]'}return i=this.views[this.currentView].$el.find(h),i.length?i:e("")},destroy:function(){var t=this;t.$el.off(".adp").data("datepicker",""),t.selectedDates=[],t.focused="",t.views={},t.keys=[],t.minRange="",t.maxRange="",t.opts.inline||!t.elIsInput?t.$datepicker.closest(".datepicker-inline").remove():t.$datepicker.remove()},_handleAlreadySelectedDates:function(t,e){this.opts.range?this.opts.toggleSelected?this.removeDate(e):2!=this.selectedDates.length&&this._trigger("clickCell",e):this.opts.toggleSelected&&this.removeDate(e),this.opts.toggleSelected||(this.lastSelectedDate=t,this.opts.timepicker&&(this.timepicker._setTime(t),this.timepicker.update()))},_onShowEvent:function(t){this.visible||this.show()},_onBlur:function(){!this.inFocus&&this.visible&&this.hide()},_onMouseDownDatepicker:function(t){this.inFocus=!0},_onMouseUpDatepicker:function(t){this.inFocus=!1,t.originalEvent.inFocus=!0,t.originalEvent.timepickerFocus||this.$el.focus()},_onKeyUpGeneral:function(t){var e=this.$el.val();e||this.clear()},_onResize:function(){this.visible&&this.setPosition()},_onMouseUpBody:function(t){t.originalEvent.inFocus||this.visible&&!this.inFocus&&this.hide()},_onMouseUpEl:function(t){t.originalEvent.inFocus=!0,setTimeout(this._onKeyUpGeneral.bind(this),4)},_onKeyDown:function(t){var e=t.which;if(this._registerKey(e),e>=37&&e<=40&&(t.preventDefault(),this._focusNextCell(e)),13==e&&this.focused){if(this._getCell(this.focused).hasClass("-disabled-"))return;if(this.view!=this.opts.minView)this.down();else{var s=this._isSelected(this.focused,this.cellType);if(!s)return this.timepicker&&(this.focused.setHours(this.timepicker.hours),this.focused.setMinutes(this.timepicker.minutes),this.focused.setSeconds(this.timepicker.seconds)),void this.selectDate(this.focused);this._handleAlreadySelectedDates(s,this.focused)}}27==e&&this.hide()},_onKeyUp:function(t){var e=t.which;this._unRegisterKey(e)},_onHotKey:function(t,e){this._handleHotKey(e)},_onMouseEnterCell:function(t){var s=e(t.target).closest(".datepicker--cell"),i=this._getDateFromCell(s);this.silent=!0,this.focused&&(this.focused=""),s.addClass("-focus-"),this.focused=i,this.silent=!1,this.opts.range&&1==this.selectedDates.length&&(this.minRange=this.selectedDates[0],this.maxRange="",n.less(this.minRange,this.focused)&&(this.maxRange=this.minRange,this.minRange=""),this.views[this.currentView]._update())},_onMouseLeaveCell:function(t){var s=e(t.target).closest(".datepicker--cell");s.removeClass("-focus-"),this.silent=!0,this.focused="",this.silent=!1},_onTimeChange:function(t,e,s,i){var a=new Date,n=this.selectedDates,h=!1;n.length&&(h=!0,a=this.lastSelectedDate),a.setHours(e),a.setMinutes(s),a.setSeconds(i),h||this._getCell(a).hasClass("-disabled-")?(this._setInputValue(),this.opts.onSelect&&this._triggerOnChange()):this.selectDate(a)},_onClickCell:function(t,e){this.timepicker&&(e.setHours(this.timepicker.hours),e.setMinutes(this.timepicker.minutes),e.setSeconds(this.timepicker.seconds)),this.selectDate(e)},set focused(t){if(!t&&this.focused){var e=this._getCell(this.focused);e.length&&e.removeClass("-focus-")}this._focused=t,this.opts.range&&1==this.selectedDates.length&&(this.minRange=this.selectedDates[0],this.maxRange="",n.less(this.minRange,this._focused)&&(this.maxRange=this.minRange,this.minRange="")),this.silent||(this.date=t)},get focused(){return this._focused},get parsedDate(){return n.getParsedDate(this.date)},set date(t){if(t instanceof Date)return this.currentDate=t,this.inited&&!this.silent&&(this.views[this.view]._render(),this.nav._render(),this.visible&&this.elIsInput&&this.setPosition()),t},get date(){return this.currentDate},set view(t){if(this.viewIndex=this.viewIndexes.indexOf(t),!(this.viewIndex<0))return this.prevView=this.currentView,this.currentView=t,this.inited&&(this.views[t]?this.views[t]._render():this.views[t]=new e.fn.datepicker.Body(this,t,this.opts),this.views[this.prevView].hide(),this.views[t].show(),this.nav._render(),this.opts.onChangeView&&this.opts.onChangeView(t),this.elIsInput&&this.visible&&this.setPosition()),t},get view(){return this.currentView},get cellType(){return this.view.substring(0,this.view.length-1)},get minTime(){var t=n.getParsedDate(this.minDate);return new Date(t.year,t.month,t.date).getTime()},get maxTime(){var t=n.getParsedDate(this.maxDate);return new Date(t.year,t.month,t.date).getTime()},get curDecade(){return n.getDecade(this.date)}},n.getDaysCount=function(t){return new Date(t.getFullYear(),t.getMonth()+1,0).getDate()},n.getParsedDate=function(t){return{year:t.getFullYear(),month:t.getMonth(),fullMonth:t.getMonth()+1<10?"0"+(t.getMonth()+1):t.getMonth()+1,date:t.getDate(),fullDate:t.getDate()<10?"0"+t.getDate():t.getDate(),day:t.getDay(),hours:t.getHours(),fullHours:t.getHours()<10?"0"+t.getHours():t.getHours(),minutes:t.getMinutes(),fullMinutes:t.getMinutes()<10?"0"+t.getMinutes():t.getMinutes(),seconds:t.getSeconds(),fullSeconds:t.getSeconds()<10?"0"+t.getSeconds():t.getSeconds()}},n.getDecade=function(t){var e=10*Math.floor(t.getFullYear()/10);return[e,e+9]},n.template=function(t,e){return t.replace(/#\{([\w]+)\}/g,function(t,s){if(e[s]||0===e[s])return e[s]})},n.isSame=function(t,e,s){if(!t||!e)return!1;var i=n.getParsedDate(t),a=n.getParsedDate(e),h=s?s:"day",o={day:i.date==a.date&&i.month==a.month&&i.year==a.year,month:i.month==a.month&&i.year==a.year,year:i.year==a.year};return o[h]},n.less=function(t,e,s){return!(!t||!e)&&e.getTime()t.getTime()},n.getLeadingZeroNum=function(t){return parseInt(t)<10?"0"+t:t},n.resetTime=function(t){if("object"==typeof t)return t=n.getParsedDate(t),new Date(t.year,t.month,t.date)},e.fn.datepicker=function(t){return this.each(function(){if(e.data(this,o)){var s=e.data(this,o);s.opts=e.extend(!0,s.opts,t),s.update()}else e.data(this,o,new m(this,t))})},e.fn.datepicker.Constructor=m,e.fn.datepicker.language={ru:{days:["Воскресенье","Понедельник","Вторник","Среда","Четверг","Пятница","Суббота"],daysShort:["Вос","Пон","Вто","Сре","Чет","Пят","Суб"],daysMin:["Вс","Пн","Вт","Ср","Чт","Пт","Сб"],months:["Январь","Февраль","Март","Апрель","Май","Июнь","Июль","Август","Сентябрь","Октябрь","Ноябрь","Декабрь"],monthsShort:["Янв","Фев","Мар","Апр","Май","Июн","Июл","Авг","Сен","Окт","Ноя","Дек"],today:"Сегодня",clear:"Очистить",dateFormat:"dd.mm.yyyy",timeFormat:"hh:ii",firstDay:1}},e(function(){e(r).datepicker()})}(),function(){var t={days:'
',months:'
',years:'
'},i=e.fn.datepicker,a=i.Constructor;i.Body=function(t,s,i){this.d=t,this.type=s,this.opts=i,this.$el=e(""),this.opts.onlyTimepicker||this.init()},i.Body.prototype={init:function(){this._buildBaseHtml(),this._render(),this._bindEvents()},_bindEvents:function(){this.$el.on("click",".datepicker--cell",e.proxy(this._onClickCell,this))},_buildBaseHtml:function(){this.$el=e(t[this.type]).appendTo(this.d.$content),this.$names=e(".datepicker--days-names",this.$el),this.$cells=e(".datepicker--cells",this.$el)},_getDayNamesHtml:function(t,e,i,a){return e=e!=s?e:t,i=i?i:"",a=a!=s?a:0,a>7?i:7==e?this._getDayNamesHtml(t,0,i,++a):(i+='
'+this.d.loc.daysMin[e]+"
",this._getDayNamesHtml(t,++e,i,++a))},_getCellContents:function(t,e){var s="datepicker--cell datepicker--cell-"+e,i=new Date,n=this.d,h=a.resetTime(n.minRange),o=a.resetTime(n.maxRange),r=n.opts,c=a.getParsedDate(t),d={},l=c.date;switch(e){case"day":n.isWeekend(c.day)&&(s+=" -weekend-"),c.month!=this.d.parsedDate.month&&(s+=" -other-month-",r.selectOtherMonths||(s+=" -disabled-"),r.showOtherMonths||(l=""));break;case"month":l=n.loc[n.opts.monthsField][c.month];break;case"year":var u=n.curDecade;l=c.year,(c.yearu[1])&&(s+=" -other-decade-",r.selectOtherYears||(s+=" -disabled-"),r.showOtherYears||(l=""))}return r.onRenderCell&&(d=r.onRenderCell(t,e)||{},l=d.html?d.html:l,s+=d.classes?" "+d.classes:""),r.range&&(a.isSame(h,t,e)&&(s+=" -range-from-"),a.isSame(o,t,e)&&(s+=" -range-to-"),1==n.selectedDates.length&&n.focused?((a.bigger(h,t)&&a.less(n.focused,t)||a.less(o,t)&&a.bigger(n.focused,t))&&(s+=" -in-range-"),a.less(o,t)&&a.isSame(n.focused,t)&&(s+=" -range-from-"),a.bigger(h,t)&&a.isSame(n.focused,t)&&(s+=" -range-to-")):2==n.selectedDates.length&&a.bigger(h,t)&&a.less(o,t)&&(s+=" -in-range-")),a.isSame(i,t,e)&&(s+=" -current-"),n.focused&&a.isSame(t,n.focused,e)&&(s+=" -focus-"),n._isSelected(t,e)&&(s+=" -selected-"),n._isInRange(t,e)&&!d.disabled||(s+=" -disabled-"),{html:l,classes:s}},_getDaysHtml:function(t){var e=a.getDaysCount(t),s=new Date(t.getFullYear(),t.getMonth(),1).getDay(),i=new Date(t.getFullYear(),t.getMonth(),e).getDay(),n=s-this.d.loc.firstDay,h=6-i+this.d.loc.firstDay;n=n<0?n+7:n,h=h>6?h-7:h;for(var o,r,c=-n+1,d="",l=c,u=e+h;l<=u;l++)r=t.getFullYear(),o=t.getMonth(),d+=this._getDayHtml(new Date(r,o,l));return d},_getDayHtml:function(t){var e=this._getCellContents(t,"day");return'
'+e.html+"
"},_getMonthsHtml:function(t){for(var e="",s=a.getParsedDate(t),i=0;i<12;)e+=this._getMonthHtml(new Date(s.year,i)),i++;return e},_getMonthHtml:function(t){var e=this._getCellContents(t,"month");return'
'+e.html+"
"},_getYearsHtml:function(t){var e=(a.getParsedDate(t),a.getDecade(t)),s=e[0]-1,i="",n=s;for(n;n<=e[1]+1;n++)i+=this._getYearHtml(new Date(n,0));return i},_getYearHtml:function(t){var e=this._getCellContents(t,"year");return'
'+e.html+"
"},_renderTypes:{days:function(){var t=this._getDayNamesHtml(this.d.loc.firstDay),e=this._getDaysHtml(this.d.currentDate);this.$cells.html(e),this.$names.html(t)},months:function(){var t=this._getMonthsHtml(this.d.currentDate);this.$cells.html(t)},years:function(){var t=this._getYearsHtml(this.d.currentDate);this.$cells.html(t)}},_render:function(){this.opts.onlyTimepicker||this._renderTypes[this.type].bind(this)()},_update:function(){var t,s,i,a=e(".datepicker--cell",this.$cells),n=this;a.each(function(a,h){s=e(this),i=n.d._getDateFromCell(e(this)),t=n._getCellContents(i,n.d.cellType),s.attr("class",t.classes)})},show:function(){this.opts.onlyTimepicker||(this.$el.addClass("active"),this.acitve=!0)},hide:function(){this.$el.removeClass("active"),this.active=!1},_handleClick:function(t){var e=t.data("date")||1,s=t.data("month")||0,i=t.data("year")||this.d.parsedDate.year,a=this.d;if(a.view!=this.opts.minView)return void a.down(new Date(i,s,e));var n=new Date(i,s,e),h=this.d._isSelected(n,this.d.cellType);return h?void a._handleAlreadySelectedDates.bind(a,h,n)():void a._trigger("clickCell",n)},_onClickCell:function(t){var s=e(t.target).closest(".datepicker--cell");s.hasClass("-disabled-")||this._handleClick.bind(this)(s)}}}(),function(){var t='
#{prevHtml}
#{title}
#{nextHtml}
',s='
',i='#{label}',a=e.fn.datepicker,n=a.Constructor;a.Navigation=function(t,e){this.d=t,this.opts=e,this.$buttonsContainer="",this.init()},a.Navigation.prototype={init:function(){this._buildBaseHtml(),this._bindEvents()},_bindEvents:function(){this.d.$nav.on("click",".datepicker--nav-action",e.proxy(this._onClickNavButton,this)),this.d.$nav.on("click",".datepicker--nav-title",e.proxy(this._onClickNavTitle,this)),this.d.$datepicker.on("click",".datepicker--button",e.proxy(this._onClickNavButton,this))},_buildBaseHtml:function(){this.opts.onlyTimepicker||this._render(),this._addButtonsIfNeed()},_addButtonsIfNeed:function(){this.opts.todayButton&&this._addButton("today"),this.opts.clearButton&&this._addButton("clear")},_render:function(){var s=this._getTitle(this.d.currentDate),i=n.template(t,e.extend({title:s},this.opts));this.d.$nav.html(i),"years"==this.d.view&&e(".datepicker--nav-title",this.d.$nav).addClass("-disabled-"),this.setNavStatus()},_getTitle:function(t){return this.d.formatDate(this.opts.navTitles[this.d.view],t)},_addButton:function(t){this.$buttonsContainer.length||this._addButtonsContainer();var s={action:t,label:this.d.loc[t]},a=n.template(i,s);e("[data-action="+t+"]",this.$buttonsContainer).length||this.$buttonsContainer.append(a)},_addButtonsContainer:function(){this.d.$datepicker.append(s),this.$buttonsContainer=e(".datepicker--buttons",this.d.$datepicker)},setNavStatus:function(){if((this.opts.minDate||this.opts.maxDate)&&this.opts.disableNavWhenOutOfRange){var t=this.d.parsedDate,e=t.month,s=t.year,i=t.date;switch(this.d.view){case"days":this.d._isInRange(new Date(s,e-1,1),"month")||this._disableNav("prev"),this.d._isInRange(new Date(s,e+1,1),"month")||this._disableNav("next");break;case"months":this.d._isInRange(new Date(s-1,e,i),"year")||this._disableNav("prev"),this.d._isInRange(new Date(s+1,e,i),"year")||this._disableNav("next");break;case"years":var a=n.getDecade(this.d.date);this.d._isInRange(new Date(a[0]-1,0,1),"year")||this._disableNav("prev"),this.d._isInRange(new Date(a[1]+1,0,1),"year")||this._disableNav("next")}}},_disableNav:function(t){e('[data-action="'+t+'"]',this.d.$nav).addClass("-disabled-")},_activateNav:function(t){e('[data-action="'+t+'"]',this.d.$nav).removeClass("-disabled-")},_onClickNavButton:function(t){var s=e(t.target).closest("[data-action]"),i=s.data("action");this.d[i]()},_onClickNavTitle:function(t){if(!e(t.target).hasClass("-disabled-"))return"days"==this.d.view?this.d.view="months":void(this.d.view="years")}}}(),function(){var t='
#{hourVisible} : #{minValue} : #{secValue}
',s=e.fn.datepicker,i=s.Constructor;s.Timepicker=function(t,e){this.d=t,this.opts=e,this.init()},s.Timepicker.prototype={init:function(){var t="input";this._setTime(this.d.date),this._buildHTML(),navigator.userAgent.match(/trident/gi)&&(t="change"),this.d.$el.on("selectDate",this._onSelectDate.bind(this)), +this.$ranges.on(t,this._onChangeRange.bind(this)),this.$ranges.on("mouseup",this._onMouseUpRange.bind(this)),this.$ranges.on("mousemove focus ",this._onMouseEnterRange.bind(this)),this.$ranges.on("mouseout blur",this._onMouseOutRange.bind(this))},_setTime:function(t){var e=i.getParsedDate(t);this._handleDate(t),this.hours=e.hourst.getHours()&&(this.minMinutes=this.opts.minMinutes)},_setMaxTimeFromDate:function(t){this.maxHours=t.getHours(),this.maxMinutes=t.getMinutes(),this.maxSeconds=t.getSeconds(),this.d.lastSelectedDate&&this.d.lastSelectedDate.getHours()t?0:i.minHours,this.minMinutes=i.minMinutes<0||i.minMinutes>e?0:i.minMinutes,this.maxHours=i.maxHours<0||i.maxHours>t?t:i.maxHours,this.maxMinutes=i.maxMinutes<0||i.maxMinutes>e?e:i.maxMinutes,this.minSeconds=i.minSeconds<0||i.minSeconds>s?0:i.minSeconds,this.maxSeconds=i.maxSeconds<0||i.maxSeconds>s?s:i.maxSeconds},_validateHoursMinutes:function(t){this.hoursthis.maxHours&&(this.hours=this.maxHours),this.minutesthis.maxMinutes&&(this.minutes=this.maxMinutes),this.secondsthis.maxSeconds&&(this.seconds=this.maxSeconds)},_buildHTML:function(){var s=i.getLeadingZeroNum,a={hourMin:this.minHours,hourMax:s(this.maxHours),hourStep:this.opts.hoursStep,hourValue:this.hours,hourVisible:s(this.displayHours),minMin:this.minMinutes,minMax:s(this.maxMinutes),minStep:this.opts.minutesStep,minValue:s(this.minutes),secMin:this.minSeconds,secMax:s(this.maxSeconds),secStep:this.opts.secondsStep,secValue:s(this.seconds)},n=i.template(t,a);this.$timepicker=e(n).appendTo(this.d.$datepicker),this.$ranges=e('[type="range"]',this.$timepicker),this.$hours=e('[name="hours"]',this.$timepicker),this.$minutes=e('[name="minutes"]',this.$timepicker),this.$seconds=e('[name="seconds"]',this.$timepicker),this.$hoursText=e(".datepicker--time-current-hours",this.$timepicker),this.$minutesText=e(".datepicker--time-current-minutes",this.$timepicker),this.$secondsText=e(".datepicker--time-current-seconds",this.$timepicker),this.d.ampm&&(this.$ampm=e('').appendTo(e(".datepicker--time-current",this.$timepicker)).html(this.dayPeriod),this.$timepicker.addClass("-am-pm-"))},_updateCurrentTime:function(){var t=i.getLeadingZeroNum(this.displayHours),e=i.getLeadingZeroNum(this.minutes),s=i.getLeadingZeroNum(this.seconds);this.$hoursText.html(t),this.$minutesText.html(e),this.$secondsText.html(s),this.d.ampm&&this.$ampm.html(this.dayPeriod)},_updateRanges:function(){this.$hours.attr({min:this.minHours,max:this.maxHours}).val(this.hours),this.$minutes.attr({min:this.minMinutes,max:this.maxMinutes}).val(this.minutes),this.$seconds.attr({min:this.minSeconds,max:this.maxSeconds}).val(this.seconds)},_handleDate:function(t){this._setDefaultMinMaxTime(),t&&(i.isSame(t,this.d.opts.minDate)?this._setMinTimeFromDate(this.d.opts.minDate):i.isSame(t,this.d.opts.maxDate)&&this._setMaxTimeFromDate(this.d.opts.maxDate)),this._validateHoursMinutes(t)},update:function(){this._updateRanges(),this._updateCurrentTime()},_getValidHoursFromDate:function(t,e){var s=t,a=t;t instanceof Date&&(s=i.getParsedDate(t),a=s.hours);var n=e||this.d.ampm,h="am";if(n)switch(!0){case 0==a:a=12;break;case 12==a:h="pm";break;case a>11:a-=12,h="pm"}return{hours:a,dayPeriod:h}},set hours(t){this._hours=t;var e=this._getValidHoursFromDate(t);this.displayHours=e.hours,this.dayPeriod=e.dayPeriod},get hours(){return this._hours},_onChangeRange:function(t){var s=e(t.target),i=s.attr("name");this.d.timepickerIsActive=!0,this[i]=s.val(),this._updateCurrentTime(),this.d._trigger("timeChange",[this.hours,this.minutes,this.seconds]),this._handleDate(this.d.lastSelectedDate),this.update()},_onSelectDate:function(t,e){this._handleDate(e),this.update()},_onMouseEnterRange:function(t){var s=e(t.target).attr("name");e(".datepicker--time-current-"+s,this.$timepicker).addClass("-focus-")},_onMouseOutRange:function(t){var s=e(t.target).attr("name");this.d.inFocus||e(".datepicker--time-current-"+s,this.$timepicker).removeClass("-focus-")},_onMouseUpRange:function(t){this.d.timepickerIsActive=!1}}}()}(window,jQuery); \ No newline at end of file diff --git a/dist/js/i18n/datepicker.cs.js b/dist/js/i18n/datepicker.cs.js new file mode 100644 index 0000000..a89db7c --- /dev/null +++ b/dist/js/i18n/datepicker.cs.js @@ -0,0 +1,12 @@ +;(function ($) { $.fn.datepicker.language['cs'] = { + days: ['Neděle', 'Pondělí', 'Úterý', 'Středa', 'Čtvrtek', 'Pátek', 'Sobota'], + daysShort: ['Ne', 'Po', 'Út', 'St', 'Čt', 'Pá', 'So'], + daysMin: ['Ne', 'Po', 'Út', 'St', 'Čt', 'Pá', 'So'], + months: ['Leden', 'Únor', 'Březen', 'Duben', 'Květen', 'Červen', 'Červenec', 'Srpen', 'Září', 'Říjen', 'Listopad', 'Prosinec'], + monthsShort: ['Led', 'Úno', 'Bře', 'Dub', 'Kvě', 'Čvn', 'Čvc', 'Srp', 'Zář', 'Říj', 'Lis', 'Pro'], + today: 'Dnes', + clear: 'Vymazat', + dateFormat: 'dd.mm.yyyy', + timeFormat: 'hh:ii', + firstDay: 1 +}; })(jQuery); \ No newline at end of file diff --git a/dist/js/i18n/datepicker.da.js b/dist/js/i18n/datepicker.da.js new file mode 100644 index 0000000..f34456e --- /dev/null +++ b/dist/js/i18n/datepicker.da.js @@ -0,0 +1,12 @@ +;(function ($) { $.fn.datepicker.language['da'] = { + days: ['Søndag', 'Mandag', 'Tirsdag', 'Onsdag', 'Torsdag', 'Fredag', 'Lørdag'], + daysShort: ['Søn', 'Man', 'Tir', 'Ons', 'Tor', 'Fre', 'Lør'], + daysMin: ['Sø', 'Ma', 'Ti', 'On', 'To', 'Fr', 'Lø'], + months: ['Januar','Februar','Marts','April','Maj','Juni', 'Juli','August','September','Oktober','November','December'], + monthsShort: ['Jan', 'Feb', 'Mar', 'Apr', 'Maj', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dec'], + today: 'I dag', + clear: 'Nulstil', + dateFormat: 'dd/mm/yyyy', + timeFormat: 'hh:ii', + firstDay: 1 +}; })(jQuery); \ No newline at end of file diff --git a/dist/js/i18n/datepicker.de.js b/dist/js/i18n/datepicker.de.js new file mode 100644 index 0000000..fd9f8ff --- /dev/null +++ b/dist/js/i18n/datepicker.de.js @@ -0,0 +1,13 @@ +;(function ($) { $.fn.datepicker.language['de'] = { + days: ['Sonntag', 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag'], + daysShort: ['Son', 'Mon', 'Die', 'Mit', 'Don', 'Fre', 'Sam'], + daysMin: ['So', 'Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa'], + months: ['Januar','Februar','März','April','Mai','Juni', 'Juli','August','September','Oktober','November','Dezember'], + monthsShort: ['Jan', 'Feb', 'Mär', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez'], + today: 'Heute', + clear: 'Aufräumen', + dateFormat: 'dd.mm.yyyy', + timeFormat: 'hh:ii', + firstDay: 1 +}; + })(jQuery); \ No newline at end of file diff --git a/dist/js/i18n/datepicker.en.js b/dist/js/i18n/datepicker.en.js new file mode 100644 index 0000000..32072f6 --- /dev/null +++ b/dist/js/i18n/datepicker.en.js @@ -0,0 +1,12 @@ +;(function ($) { $.fn.datepicker.language['en'] = { + days: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], + daysShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], + daysMin: ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'], + months: ['January','February','March','April','May','June', 'July','August','September','October','November','December'], + monthsShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], + today: 'Today', + clear: 'Clear', + dateFormat: 'mm/dd/yyyy', + timeFormat: 'hh:ii aa', + firstDay: 0 +}; })(jQuery); \ No newline at end of file diff --git a/dist/js/i18n/datepicker.es.js b/dist/js/i18n/datepicker.es.js new file mode 100644 index 0000000..a8b6af5 --- /dev/null +++ b/dist/js/i18n/datepicker.es.js @@ -0,0 +1,12 @@ +;(function ($) { $.fn.datepicker.language['es'] = { + days: ['Domingo', 'Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado'], + daysShort: ['Dom', 'Lun', 'Mar', 'Mie', 'Jue', 'Vie', 'Sab'], + daysMin: ['Do', 'Lu', 'Ma', 'Mi', 'Ju', 'Vi', 'Sa'], + months: ['Enero','Febrero','Marzo','Abril','Mayo','Junio', 'Julio','Augosto','Septiembre','Octubre','Noviembre','Diciembre'], + monthsShort: ['Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic'], + today: 'Hoy', + clear: 'Limpiar', + dateFormat: 'dd/mm/yyyy', + timeFormat: 'hh:ii aa', + firstDay: 1 +}; })(jQuery); \ No newline at end of file diff --git a/dist/js/i18n/datepicker.fi.js b/dist/js/i18n/datepicker.fi.js new file mode 100644 index 0000000..9619705 --- /dev/null +++ b/dist/js/i18n/datepicker.fi.js @@ -0,0 +1,13 @@ +;(function ($) { $.fn.datepicker.language['fi'] = { + days: ['Sunnuntai', 'Maanantai', 'Tiistai', 'Keskiviikko', 'Torstai', 'Perjantai', 'Lauantai'], + daysShort: ['Su', 'Ma', 'Ti', 'Ke', 'To', 'Pe', 'La'], + daysMin: ['Su', 'Ma', 'Ti', 'Ke', 'To', 'Pe', 'La'], + months: ['Tammikuu','Helmikuu','Maaliskuu','Huhtikuu','Toukokuu','Kesäkuu', 'Heinäkuu','Elokuu','Syyskuu','Lokakuu','Marraskuu','Joulukuu'], + monthsShort: ['Tammi', 'Helmi', 'Maalis', 'Huhti', 'Touko', 'Kesä', 'Heinä', 'Elo', 'Syys', 'Loka', 'Marras', 'Joulu'], + today: 'Tänään', + clear: 'Tyhjennä', + dateFormat: 'dd.mm.yyyy', + timeFormat: 'hh:ii', + firstDay: 1 +}; + })(jQuery); \ No newline at end of file diff --git a/dist/js/i18n/datepicker.fr.js b/dist/js/i18n/datepicker.fr.js new file mode 100644 index 0000000..0d083b2 --- /dev/null +++ b/dist/js/i18n/datepicker.fr.js @@ -0,0 +1,12 @@ +;(function ($) { $.fn.datepicker.language['fr'] = { + days: ['Dimanche', 'Lundi', 'Mardi', 'Mercredi', 'Jeudi', 'Vendredi', 'Samedi'], + daysShort: ['Dim', 'Lun', 'Mar', 'Mer', 'Jeu', 'Ven', 'Sam'], + daysMin: ['Di', 'Lu', 'Ma', 'Me', 'Je', 'Ve', 'Sa'], + months: ['Janvier','Février','Mars','Avril','Mai','Juin', 'Juillet','Août','Septembre','Octobre','Novembre','Decembre'], + monthsShort: ['Jan', 'Fév', 'Mars', 'Avr', 'Mai', 'Juin', 'Juil', 'Août', 'Sep', 'Oct', 'Nov', 'Dec'], + today: "Aujourd'hui", + clear: 'Effacer', + dateFormat: 'dd/mm/yyyy', + timeFormat: 'hh:ii', + firstDay: 1 +}; })(jQuery); \ No newline at end of file diff --git a/dist/js/i18n/datepicker.hu.js b/dist/js/i18n/datepicker.hu.js new file mode 100644 index 0000000..7d144b3 --- /dev/null +++ b/dist/js/i18n/datepicker.hu.js @@ -0,0 +1,12 @@ +;(function ($) { ;(function ($) { $.fn.datepicker.language['hu'] = { + days: ['Vasárnap', 'Hétfő', 'Kedd', 'Szerda', 'Csütörtök', 'Péntek', 'Szombat'], + daysShort: ['Va', 'Hé', 'Ke', 'Sze', 'Cs', 'Pé', 'Szo'], + daysMin: ['V', 'H', 'K', 'Sz', 'Cs', 'P', 'Sz'], + months: ['Január', 'Február', 'Március', 'Április', 'Május', 'Június', 'Július', 'Augusztus', 'Szeptember', 'Október', 'November', 'December'], + monthsShort: ['Jan', 'Feb', 'Már', 'Ápr', 'Máj', 'Jún', 'Júl', 'Aug', 'Szep', 'Okt', 'Nov', 'Dec'], + today: 'Ma', + clear: 'Törlés', + dateFormat: 'yyyy-mm-dd', + timeFormat: 'hh:ii aa', + firstDay: 1 +}; })(jQuery); })(jQuery); \ No newline at end of file diff --git a/dist/js/i18n/datepicker.nl.js b/dist/js/i18n/datepicker.nl.js new file mode 100644 index 0000000..8d29a5a --- /dev/null +++ b/dist/js/i18n/datepicker.nl.js @@ -0,0 +1,12 @@ +;(function ($) { $.fn.datepicker.language['nl'] = { + days: ['zondag', 'maandag', 'dinsdag', 'woensdag', 'donderdag', 'vrijdag', 'zaterdag'], + daysShort: ['zo', 'ma', 'di', 'wo', 'do', 'vr', 'za'], + daysMin: ['zo', 'ma', 'di', 'wo', 'do', 'vr', 'za'], + months: ['Januari', 'Februari', 'Maart', 'April', 'Mei', 'Juni', 'Juli', 'Augustus', 'September', 'Oktober', 'November', 'December'], + monthsShort: ['Jan', 'Feb', 'Mrt', 'Apr', 'Mei', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dec'], + today: 'Vandaag', + clear: 'Legen', + dateFormat: 'dd-MM-yy', + timeFormat: 'hh:ii', + firstDay: 0 +}; })(jQuery); \ No newline at end of file diff --git a/dist/js/i18n/datepicker.pl.js b/dist/js/i18n/datepicker.pl.js new file mode 100644 index 0000000..3c0f565 --- /dev/null +++ b/dist/js/i18n/datepicker.pl.js @@ -0,0 +1,13 @@ +;(function ($) { $.fn.datepicker.language['pl'] = { + days: ['Niedziela', 'Poniedziałek', 'Wtorek', 'Środa', 'Czwartek', 'Piątek', 'Sobota'], + daysShort: ['Nie', 'Pon', 'Wto', 'Śro', 'Czw', 'Pią', 'Sob'], + daysMin: ['Nd', 'Pn', 'Wt', 'Śr', 'Czw', 'Pt', 'So'], + months: ['Styczeń','Luty','Marzec','Kwiecień','Maj','Czerwiec', 'Lipiec','Sierpień','Wrzesień','Październik','Listopad','Grudzień'], + monthsShort: ['Sty', 'Lut', 'Mar', 'Kwi', 'Maj', 'Cze', 'Lip', 'Sie', 'Wrz', 'Paź', 'Lis', 'Gru'], + today: 'Dzisiaj', + clear: 'Wyczyść', + dateFormat: 'yyyy-mm-dd', + timeFormat: 'hh:ii:aa', + firstDay: 1 +}; + })(jQuery); \ No newline at end of file diff --git a/dist/js/i18n/datepicker.pt-BR.js b/dist/js/i18n/datepicker.pt-BR.js new file mode 100644 index 0000000..13a79f5 --- /dev/null +++ b/dist/js/i18n/datepicker.pt-BR.js @@ -0,0 +1,12 @@ +;(function ($) { $.fn.datepicker.language['pt-BR'] = { + days: ['Domingo', 'Segunda', 'Terça', 'Quarta', 'Quinta', 'Sexta', 'Sábado'], + daysShort: ['Dom', 'Seg', 'Ter', 'Qua', 'Qui', 'Sex', 'Sab'], + daysMin: ['Do', 'Se', 'Te', 'Qu', 'Qu', 'Se', 'Sa'], + months: ['Janeiro', 'Fevereiro', 'Março', 'Abril', 'Maio', 'Junho', 'Julho', 'Agosto', 'Setembro', 'Outubro', 'Novembro', 'Dezembro'], + monthsShort: ['Jan', 'Fev', 'Mar', 'Abr', 'Mai', 'Jun', 'Jul', 'Ago', 'Set', 'Out', 'Nov', 'Dez'], + today: 'Hoje', + clear: 'Limpar', + dateFormat: 'dd/mm/yyyy', + timeFormat: 'hh:ii', + firstDay: 0 +}; })(jQuery); \ No newline at end of file diff --git a/dist/js/i18n/datepicker.pt.js b/dist/js/i18n/datepicker.pt.js new file mode 100644 index 0000000..92a3a08 --- /dev/null +++ b/dist/js/i18n/datepicker.pt.js @@ -0,0 +1,12 @@ +;(function ($) { $.fn.datepicker.language['pt'] = { + days: ['Domingo', 'Segunda', 'Terça', 'Quarta', 'Quinta', 'Sexta', 'Sábado'], + daysShort: ['Dom', 'Seg', 'Ter', 'Qua', 'Qui', 'Sex', 'Sab'], + daysMin: ['Do', 'Se', 'Te', 'Qa', 'Qi', 'Sx', 'Sa'], + months: ['Janeiro', 'Fevereiro', 'Março', 'Abril', 'Maio', 'Junho', 'Julho', 'Agosto', 'Setembro', 'Outubro', 'Novembro', 'Dezembro'], + monthsShort: ['Jan', 'Fev', 'Mar', 'Abr', 'Mai', 'Jun', 'Jul', 'Ago', 'Set', 'Out', 'Nov', 'Dez'], + today: 'Hoje', + clear: 'Limpar', + dateFormat: 'dd/mm/yyyy', + timeFormat: 'hh:ii', + firstDay: 1 +}; })(jQuery); \ No newline at end of file diff --git a/dist/js/i18n/datepicker.ro.js b/dist/js/i18n/datepicker.ro.js new file mode 100644 index 0000000..0034204 --- /dev/null +++ b/dist/js/i18n/datepicker.ro.js @@ -0,0 +1,13 @@ +;(function ($) { $.fn.datepicker.language['ro'] = { + days: ['Duminică', 'Luni', 'Marţi', 'Miercuri', 'Joi', 'Vineri', 'Sâmbătă'], + daysShort: ['Dum', 'Lun', 'Mar', 'Mie', 'Joi', 'Vin', 'Sâm'], + daysMin: ['D', 'L', 'Ma', 'Mi', 'J', 'V', 'S'], + months: ['Ianuarie','Februarie','Martie','Aprilie','Mai','Iunie','Iulie','August','Septembrie','Octombrie','Noiembrie','Decembrie'], + monthsShort: ['Ian', 'Feb', 'Mar', 'Apr', 'Mai', 'Iun', 'Iul', 'Aug', 'Sept', 'Oct', 'Nov', 'Dec'], + today: 'Azi', + clear: 'Şterge', + dateFormat: 'dd.mm.yyyy', + timeFormat: 'hh:ii', + firstDay: 1 +}; + })(jQuery); \ No newline at end of file diff --git a/dist/js/i18n/datepicker.sk.js b/dist/js/i18n/datepicker.sk.js new file mode 100644 index 0000000..3312386 --- /dev/null +++ b/dist/js/i18n/datepicker.sk.js @@ -0,0 +1,12 @@ +;(function ($) { $.fn.datepicker.language['sk'] = { + days: ['Nedeľa', 'Pondelok', 'Utorok', 'Streda', 'Štvrtok', 'Piatok', 'Sobota'], + daysShort: ['Ned', 'Pon', 'Uto', 'Str', 'Štv', 'Pia', 'Sob'], + daysMin: ['Ne', 'Po', 'Ut', 'St', 'Št', 'Pi', 'So'], + months: ['Január','Február','Marec','Apríl','Máj','Jún', 'Júl','August','September','Október','November','December'], + monthsShort: ['Jan', 'Feb', 'Mar', 'Apr', 'Máj', 'Jún', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dec'], + today: 'Dnes', + clear: 'Vymazať', + dateFormat: 'dd.mm.yyyy', + timeFormat: 'hh:ii', + firstDay: 1 +}; })(jQuery); \ No newline at end of file diff --git a/dist/js/i18n/datepicker.zh.js b/dist/js/i18n/datepicker.zh.js new file mode 100644 index 0000000..08633cc --- /dev/null +++ b/dist/js/i18n/datepicker.zh.js @@ -0,0 +1,12 @@ +;(function ($) { $.fn.datepicker.language['zh'] = { + days: ['周日', '周一', '周二', '周三', '周四', '周五', '周六'], + daysShort: ['日', '一', '二', '三', '四', '五', '六'], + daysMin: ['日', '一', '二', '三', '四', '五', '六'], + months: ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'], + monthsShort: ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'], + today: '今天', + clear: '清除', + dateFormat: 'yyyy-mm-dd', + timeFormat: 'hh:ii', + firstDay: 1 +}; })(jQuery); \ No newline at end of file diff --git a/gulpfile.js b/gulpfile.js new file mode 100644 index 0000000..0c4b98d --- /dev/null +++ b/gulpfile.js @@ -0,0 +1,38 @@ +var gulp = require('gulp'), + watch = require('gulp-watch'), + livereload = require('gulp-livereload'); + +gulp.task('css', require('./tasks/css')); +gulp.task('js', require('./tasks/js')); +gulp.task('i18n', require('./tasks/i18n')); +gulp.task('cssPage', require('./tasks/cssPage')); +gulp.task('jade-ru', require('./tasks/jade').ru); +gulp.task('jade-en', require('./tasks/jade').en); +gulp.task('gzip', require('./tasks/gzip')); + +gulp.task('watch', function () { + livereload.listen(); + + gulp.watch('src/sass/*.scss', ['css']).on('change', function (file) { + livereload.changed(file) + }); + + gulp.watch('src/js/**/*.js', ['js']).on('change', function (file) { + livereload.changed(file) + }); + + gulp.watch('docs/sass/*.scss', ['cssPage']).on('change', function (file) { + livereload.changed(file) + }); + + gulp.watch('docs/jade/**/*.jade', ['jade-ru', 'jade-en']).on('change', function (file) { + livereload.changed(file) + }); +}); + +gulp.task('dev', ['css','js','i18n', 'cssPage', 'jade-ru', 'jade-en', 'watch']); +gulp.task('build', ['css','js','i18n', 'jade-ru', 'jade-en']); + + + + diff --git a/package.json b/package.json new file mode 100644 index 0000000..b2c7cc9 --- /dev/null +++ b/package.json @@ -0,0 +1,80 @@ +{ + "_from": "github:influxframework/air-datepicker", + "_id": "air-datepicker@2.2.3", + "_inBundle": false, + "_integrity": "", + "_location": "/air-datepicker", + "_phantomChildren": {}, + "_requested": { + "type": "git", + "raw": "air-datepicker@github:influxframework/air-datepicker", + "name": "air-datepicker", + "escapedName": "air-datepicker", + "rawSpec": "github:influxframework/air-datepicker", + "saveSpec": "github:influxframework/air-datepicker", + "fetchSpec": null, + "gitCommittish": null + }, + "_requiredBy": [ + "/" + ], + "_resolved": "github:influxframework/air-datepicker#ed37b94d95c68d8544357e330be0c89d044a3eea", + "_spec": "air-datepicker@github:influxframework/air-datepicker", + "_where": "E:\\Python Projects\\demo", + "author": { + "name": "t1m0n", + "email": "t1m0n.tr@gmail.com" + }, + "bugs": { + "url": "https://github.com/t1m0n/air-datepicker/issues" + }, + "bundleDependencies": false, + "dependencies": { + "jquery": ">=2.0.0 <4.0.0" + }, + "deprecated": false, + "description": "Lightweight customizable cross-browser jQuery datepicker, built with es5 and css-flexbox. Works in all modern desktop and mobile browsers (tested no Android 4.4+ and iOS8+)\r ![air datepicker image](https://github.com/t1m0n/air-datepicker/raw/master/docs/img/promo-img.png)", + "devDependencies": { + "autoprefixer": "^6.1.0", + "browserify": "^13.0.0", + "chai": "^3.4.1", + "gulp": "^3.9.0", + "gulp-clone": "^1.0.0", + "gulp-concat": "^2.6.0", + "gulp-gzip": "^1.2.0", + "gulp-jade": "^1.1.0", + "gulp-livereload": "^3.8.0", + "gulp-minify-css": "^1.2.1", + "gulp-plumber": "^1.0.1", + "gulp-postcss": "^6.0.1", + "gulp-rename": "^1.2.2", + "gulp-sass": "^2.0.4", + "gulp-uglify": "^1.2.0", + "gulp-watch": "^4.3.5", + "gulp-wrap": "^0.11.0", + "jade": "^1.11.0", + "mocha": "^2.3.4", + "node-static": "^0.7.7", + "vinyl-source-stream": "^1.1.0" + }, + "directories": { + "doc": "docs", + "test": "tests" + }, + "homepage": "http://t1m0n.name/air-datepicker/docs/", + "keywords": [ + "datepicker", + "timepicker", + "plugin", + "customizable", + "powerful" + ], + "license": "MIT", + "main": "src/js/air-datepicker.js", + "name": "air-datepicker", + "repository": { + "type": "git", + "url": "git+https://github.com/t1m0n/air-datepicker.git" + }, + "version": "2.2.3" +} diff --git a/src/js/air-datepicker.js b/src/js/air-datepicker.js new file mode 100644 index 0000000..4c61783 --- /dev/null +++ b/src/js/air-datepicker.js @@ -0,0 +1,4 @@ +require('./datepicker'); +require('./body'); +require('./navigation'); +require('./timepicker'); \ No newline at end of file diff --git a/src/js/body.js b/src/js/body.js new file mode 100644 index 0000000..70a1ed8 --- /dev/null +++ b/src/js/body.js @@ -0,0 +1,311 @@ +;(function () { + var templates = { + days:'' + + '
' + + '
' + + '
' + + '
', + months: '' + + '
' + + '
' + + '
', + years: '' + + '
' + + '
' + + '
' + }, + datepicker = $.fn.datepicker, + dp = datepicker.Constructor; + + datepicker.Body = function (d, type, opts) { + this.d = d; + this.type = type; + this.opts = opts; + this.$el = $(''); + + if (this.opts.onlyTimepicker) return; + this.init(); + }; + + datepicker.Body.prototype = { + init: function () { + this._buildBaseHtml(); + this._render(); + + this._bindEvents(); + }, + + _bindEvents: function () { + this.$el.on('click', '.datepicker--cell', $.proxy(this._onClickCell, this)); + }, + + _buildBaseHtml: function () { + this.$el = $(templates[this.type]).appendTo(this.d.$content); + this.$names = $('.datepicker--days-names', this.$el); + this.$cells = $('.datepicker--cells', this.$el); + }, + + _getDayNamesHtml: function (firstDay, curDay, html, i) { + curDay = curDay != undefined ? curDay : firstDay; + html = html ? html : ''; + i = i != undefined ? i : 0; + + if (i > 7) return html; + if (curDay == 7) return this._getDayNamesHtml(firstDay, 0, html, ++i); + + html += '
' + this.d.loc.daysMin[curDay] + '
'; + + return this._getDayNamesHtml(firstDay, ++curDay, html, ++i); + }, + + _getCellContents: function (date, type) { + var classes = "datepicker--cell datepicker--cell-" + type, + currentDate = new Date(), + parent = this.d, + minRange = dp.resetTime(parent.minRange), + maxRange = dp.resetTime(parent.maxRange), + opts = parent.opts, + d = dp.getParsedDate(date), + render = {}, + html = d.date; + + switch (type) { + case 'day': + if (parent.isWeekend(d.day)) classes += " -weekend-"; + if (d.month != this.d.parsedDate.month) { + classes += " -other-month-"; + if (!opts.selectOtherMonths) { + classes += " -disabled-"; + } + if (!opts.showOtherMonths) html = ''; + } + break; + case 'month': + html = parent.loc[parent.opts.monthsField][d.month]; + break; + case 'year': + var decade = parent.curDecade; + html = d.year; + if (d.year < decade[0] || d.year > decade[1]) { + classes += ' -other-decade-'; + if (!opts.selectOtherYears) { + classes += " -disabled-"; + } + if (!opts.showOtherYears) html = ''; + } + break; + } + + if (opts.onRenderCell) { + render = opts.onRenderCell(date, type) || {}; + html = render.html ? render.html : html; + classes += render.classes ? ' ' + render.classes : ''; + } + + if (opts.range) { + if (dp.isSame(minRange, date, type)) classes += ' -range-from-'; + if (dp.isSame(maxRange, date, type)) classes += ' -range-to-'; + + if (parent.selectedDates.length == 1 && parent.focused) { + if ( + (dp.bigger(minRange, date) && dp.less(parent.focused, date)) || + (dp.less(maxRange, date) && dp.bigger(parent.focused, date))) + { + classes += ' -in-range-' + } + + if (dp.less(maxRange, date) && dp.isSame(parent.focused, date)) { + classes += ' -range-from-' + } + if (dp.bigger(minRange, date) && dp.isSame(parent.focused, date)) { + classes += ' -range-to-' + } + + } else if (parent.selectedDates.length == 2) { + if (dp.bigger(minRange, date) && dp.less(maxRange, date)) { + classes += ' -in-range-' + } + } + } + + + if (dp.isSame(currentDate, date, type)) classes += ' -current-'; + if (parent.focused && dp.isSame(date, parent.focused, type)) classes += ' -focus-'; + if (parent._isSelected(date, type)) classes += ' -selected-'; + if (!parent._isInRange(date, type) || render.disabled) classes += ' -disabled-'; + + return { + html: html, + classes: classes + } + }, + + /** + * Calculates days number to render. Generates days html and returns it. + * @param {object} date - Date object + * @returns {string} + * @private + */ + _getDaysHtml: function (date) { + var totalMonthDays = dp.getDaysCount(date), + firstMonthDay = new Date(date.getFullYear(), date.getMonth(), 1).getDay(), + lastMonthDay = new Date(date.getFullYear(), date.getMonth(), totalMonthDays).getDay(), + daysFromPevMonth = firstMonthDay - this.d.loc.firstDay, + daysFromNextMonth = 6 - lastMonthDay + this.d.loc.firstDay; + + daysFromPevMonth = daysFromPevMonth < 0 ? daysFromPevMonth + 7 : daysFromPevMonth; + daysFromNextMonth = daysFromNextMonth > 6 ? daysFromNextMonth - 7 : daysFromNextMonth; + + var startDayIndex = -daysFromPevMonth + 1, + m, y, + html = ''; + + for (var i = startDayIndex, max = totalMonthDays + daysFromNextMonth; i <= max; i++) { + y = date.getFullYear(); + m = date.getMonth(); + + html += this._getDayHtml(new Date(y, m, i)) + } + + return html; + }, + + _getDayHtml: function (date) { + var content = this._getCellContents(date, 'day'); + + return '
' + content.html + '
'; + }, + + /** + * Generates months html + * @param {object} date - date instance + * @returns {string} + * @private + */ + _getMonthsHtml: function (date) { + var html = '', + d = dp.getParsedDate(date), + i = 0; + + while(i < 12) { + html += this._getMonthHtml(new Date(d.year, i)); + i++ + } + + return html; + }, + + _getMonthHtml: function (date) { + var content = this._getCellContents(date, 'month'); + + return '
' + content.html + '
' + }, + + _getYearsHtml: function (date) { + var d = dp.getParsedDate(date), + decade = dp.getDecade(date), + firstYear = decade[0] - 1, + html = '', + i = firstYear; + + for (i; i <= decade[1] + 1; i++) { + html += this._getYearHtml(new Date(i , 0)); + } + + return html; + }, + + _getYearHtml: function (date) { + var content = this._getCellContents(date, 'year'); + + return '
' + content.html + '
' + }, + + _renderTypes: { + days: function () { + var dayNames = this._getDayNamesHtml(this.d.loc.firstDay), + days = this._getDaysHtml(this.d.currentDate); + + this.$cells.html(days); + this.$names.html(dayNames) + }, + months: function () { + var html = this._getMonthsHtml(this.d.currentDate); + + this.$cells.html(html) + }, + years: function () { + var html = this._getYearsHtml(this.d.currentDate); + + this.$cells.html(html) + } + }, + + _render: function () { + if (this.opts.onlyTimepicker) return; + this._renderTypes[this.type].bind(this)(); + }, + + _update: function () { + var $cells = $('.datepicker--cell', this.$cells), + _this = this, + classes, + $cell, + date; + $cells.each(function (cell, i) { + $cell = $(this); + date = _this.d._getDateFromCell($(this)); + classes = _this._getCellContents(date, _this.d.cellType); + $cell.attr('class',classes.classes) + }); + }, + + show: function () { + if (this.opts.onlyTimepicker) return; + this.$el.addClass('active'); + this.acitve = true; + }, + + hide: function () { + this.$el.removeClass('active'); + this.active = false; + }, + + // Events + // ------------------------------------------------- + + _handleClick: function (el) { + var date = el.data('date') || 1, + month = el.data('month') || 0, + year = el.data('year') || this.d.parsedDate.year, + dp = this.d; + // Change view if min view does not reach yet + if (dp.view != this.opts.minView) { + dp.down(new Date(year, month, date)); + return; + } + // Select date if min view is reached + var selectedDate = new Date(year, month, date), + alreadySelected = this.d._isSelected(selectedDate, this.d.cellType); + + if (!alreadySelected) { + dp._trigger('clickCell', selectedDate); + return; + } + + dp._handleAlreadySelectedDates.bind(dp, alreadySelected, selectedDate)(); + + }, + + _onClickCell: function (e) { + var $el = $(e.target).closest('.datepicker--cell'); + + if ($el.hasClass('-disabled-')) return; + + this._handleClick.bind(this)($el); + } + }; +})(); diff --git a/src/js/datepicker.js b/src/js/datepicker.js new file mode 100644 index 0000000..9a137f0 --- /dev/null +++ b/src/js/datepicker.js @@ -0,0 +1,1508 @@ +;(function () { + var VERSION = '2.2.3', + pluginName = 'datepicker', + autoInitSelector = '.datepicker-here', + $body, $datepickersContainer, + containerBuilt = false, + baseTemplate = '' + + '
' + + '' + + '' + + '
' + + '
', + defaults = { + classes: '', + inline: false, + language: 'ru', + startDate: new Date(), + firstDay: '', + weekends: [6, 0], + dateFormat: '', + altField: '', + altFieldDateFormat: '@', + toggleSelected: true, + keyboardNav: true, + + position: 'bottom left', + offset: 12, + + view: 'days', + minView: 'days', + + showOtherMonths: true, + selectOtherMonths: true, + moveToOtherMonthsOnSelect: true, + + showOtherYears: true, + selectOtherYears: true, + moveToOtherYearsOnSelect: true, + + minDate: '', + maxDate: '', + disableNavWhenOutOfRange: true, + + multipleDates: false, // Boolean or Number + multipleDatesSeparator: ',', + range: false, + + todayButton: false, + clearButton: false, + + showEvent: 'focus', + autoClose: false, + + // navigation + monthsField: 'monthsShort', + prevHtml: '', + nextHtml: '', + navTitles: { + days: 'MM, yyyy', + months: 'yyyy', + years: 'yyyy1 - yyyy2' + }, + + // timepicker + timepicker: false, + onlyTimepicker: false, + dateTimeSeparator: ' ', + timeFormat: '', + minHours: 0, + maxHours: 24, + minMinutes: 0, + maxMinutes: 59, + minSeconds: 0, + maxSeconds: 59, + hoursStep: 1, + minutesStep: 1, + secondsStep: 1, + + // events + onSelect: '', + onShow: '', + onHide: '', + onChangeMonth: '', + onChangeYear: '', + onChangeDecade: '', + onChangeView: '', + onRenderCell: '' + }, + hotKeys = { + 'ctrlRight': [17, 39], + 'ctrlUp': [17, 38], + 'ctrlLeft': [17, 37], + 'ctrlDown': [17, 40], + 'shiftRight': [16, 39], + 'shiftUp': [16, 38], + 'shiftLeft': [16, 37], + 'shiftDown': [16, 40], + 'altUp': [18, 38], + 'altRight': [18, 39], + 'altLeft': [18, 37], + 'altDown': [18, 40], + 'ctrlShiftUp': [16, 17, 38] + }, + datepicker; + + var Datepicker = function (el, options) { + this.el = el; + this.$el = $(el); + + this.opts = $.extend(true, {}, defaults, options, this.$el.data()); + + if ($body == undefined) { + $body = $('body'); + } + + if (!this.opts.startDate) { + this.opts.startDate = new Date(); + } + + if (this.el.nodeName == 'INPUT') { + this.elIsInput = true; + } + + if (this.opts.altField) { + this.$altField = typeof this.opts.altField == 'string' ? $(this.opts.altField) : this.opts.altField; + } + + this.inited = false; + this.visible = false; + this.silent = false; // Need to prevent unnecessary rendering + + this.currentDate = this.opts.startDate; + this.currentView = this.opts.view; + this._createShortCuts(); + this.selectedDates = []; + this.views = {}; + this.keys = []; + this.minRange = ''; + this.maxRange = ''; + this._prevOnSelectValue = ''; + + this.init() + }; + + datepicker = Datepicker; + + datepicker.prototype = { + VERSION: VERSION, + viewIndexes: ['days', 'months', 'years'], + + init: function () { + if (!containerBuilt && !this.opts.inline && this.elIsInput) { + this._buildDatepickersContainer(); + } + this._buildBaseHtml(); + this._defineLocale(this.opts.language); + this._syncWithMinMaxDates(); + + if (this.elIsInput) { + if (!this.opts.inline) { + // Set extra classes for proper transitions + this._setPositionClasses(this.opts.position); + this._bindEvents() + } + if (this.opts.keyboardNav && !this.opts.onlyTimepicker) { + this._bindKeyboardEvents(); + } + this.$datepicker.on('mousedown', this._onMouseDownDatepicker.bind(this)); + this.$datepicker.on('mouseup', this._onMouseUpDatepicker.bind(this)); + } + + if (this.opts.classes) { + this.$datepicker.addClass(this.opts.classes) + } + + if (this.opts.timepicker) { + this.timepicker = new $.fn.datepicker.Timepicker(this, this.opts); + this._bindTimepickerEvents(); + } + + if (this.opts.onlyTimepicker) { + this.$datepicker.addClass('-only-timepicker-'); + } + + this.views[this.currentView] = new $.fn.datepicker.Body(this, this.currentView, this.opts); + this.views[this.currentView].show(); + this.nav = new $.fn.datepicker.Navigation(this, this.opts); + this.view = this.currentView; + + this.$el.on('clickCell.adp', this._onClickCell.bind(this)); + this.$datepicker.on('mouseenter', '.datepicker--cell', this._onMouseEnterCell.bind(this)); + this.$datepicker.on('mouseleave', '.datepicker--cell', this._onMouseLeaveCell.bind(this)); + + this.inited = true; + }, + + _createShortCuts: function () { + this.minDate = this.opts.minDate ? this.opts.minDate : new Date(-8639999913600000); + this.maxDate = this.opts.maxDate ? this.opts.maxDate : new Date(8639999913600000); + }, + + _bindEvents : function () { + this.$el.on(this.opts.showEvent + '.adp', this._onShowEvent.bind(this)); + this.$el.on('mouseup.adp', this._onMouseUpEl.bind(this)); + this.$el.on('blur.adp', this._onBlur.bind(this)); + this.$el.on('keyup.adp', this._onKeyUpGeneral.bind(this)); + $(window).on('resize.adp', this._onResize.bind(this)); + $('body').on('mouseup.adp', this._onMouseUpBody.bind(this)); + }, + + _bindKeyboardEvents: function () { + this.$el.on('keydown.adp', this._onKeyDown.bind(this)); + this.$el.on('keyup.adp', this._onKeyUp.bind(this)); + this.$el.on('hotKey.adp', this._onHotKey.bind(this)); + }, + + _bindTimepickerEvents: function () { + this.$el.on('timeChange.adp', this._onTimeChange.bind(this)); + }, + + isWeekend: function (day) { + return this.opts.weekends.indexOf(day) !== -1; + }, + + _defineLocale: function (lang) { + if (typeof lang == 'string') { + this.loc = $.fn.datepicker.language[lang]; + if (!this.loc) { + console.warn('Can\'t find language "' + lang + '" in Datepicker.language, will use "ru" instead'); + this.loc = $.extend(true, {}, $.fn.datepicker.language.ru) + } + + this.loc = $.extend(true, {}, $.fn.datepicker.language.ru, $.fn.datepicker.language[lang]) + } else { + this.loc = $.extend(true, {}, $.fn.datepicker.language.ru, lang) + } + + if (this.opts.dateFormat) { + this.loc.dateFormat = this.opts.dateFormat + } + + if (this.opts.timeFormat) { + this.loc.timeFormat = this.opts.timeFormat + } + + if (this.opts.firstDay !== '') { + this.loc.firstDay = this.opts.firstDay + } + + if (this.opts.timepicker) { + this.loc.dateFormat = [this.loc.dateFormat, this.loc.timeFormat].join(this.opts.dateTimeSeparator); + } + + if (this.opts.onlyTimepicker) { + this.loc.dateFormat = this.loc.timeFormat; + } + + var boundary = this._getWordBoundaryRegExp; + if (this.loc.timeFormat.match(boundary('aa')) || + this.loc.timeFormat.match(boundary('AA')) + ) { + this.ampm = true; + } + }, + + _buildDatepickersContainer: function () { + containerBuilt = true; + $body.append('
'); + $datepickersContainer = $('#datepickers-container'); + }, + + _buildBaseHtml: function () { + var $appendTarget, + $inline = $('
'); + + if(this.el.nodeName == 'INPUT') { + if (!this.opts.inline) { + $appendTarget = $datepickersContainer; + } else { + $appendTarget = $inline.insertAfter(this.$el) + } + } else { + $appendTarget = $inline.appendTo(this.$el) + } + + this.$datepicker = $(baseTemplate).appendTo($appendTarget); + this.$content = $('.datepicker--content', this.$datepicker); + this.$nav = $('.datepicker--nav', this.$datepicker); + }, + + _triggerOnChange: function () { + if (!this.selectedDates.length) { + // Prevent from triggering multiple onSelect callback with same argument (empty string) in IE10-11 + if (this._prevOnSelectValue === '') return; + this._prevOnSelectValue = ''; + return this.opts.onSelect('', '', this); + } + + var selectedDates = this.selectedDates, + parsedSelected = datepicker.getParsedDate(selectedDates[0]), + formattedDates, + _this = this, + dates = new Date( + parsedSelected.year, + parsedSelected.month, + parsedSelected.date, + parsedSelected.hours, + parsedSelected.minutes, + parsedSelected.seconds + ); + + formattedDates = selectedDates.map(function (date) { + return _this.formatDate(_this.loc.dateFormat, date) + }).join(this.opts.multipleDatesSeparator); + + // Create new dates array, to separate it from original selectedDates + if (this.opts.multipleDates || this.opts.range) { + dates = selectedDates.map(function(date) { + var parsedDate = datepicker.getParsedDate(date); + return new Date( + parsedDate.year, + parsedDate.month, + parsedDate.date, + parsedDate.hours, + parsedDate.minutes, + parsedDate.seconds + ); + }) + } + this._prevOnSelectValue = formattedDates; + this.opts.onSelect(formattedDates, dates, this); + }, + + next: function () { + var d = this.parsedDate, + o = this.opts; + switch (this.view) { + case 'days': + this.date = new Date(d.year, d.month + 1, 1); + if (o.onChangeMonth) o.onChangeMonth(this.parsedDate.month, this.parsedDate.year); + break; + case 'months': + this.date = new Date(d.year + 1, d.month, 1); + if (o.onChangeYear) o.onChangeYear(this.parsedDate.year); + break; + case 'years': + this.date = new Date(d.year + 10, 0, 1); + if (o.onChangeDecade) o.onChangeDecade(this.curDecade); + break; + } + }, + + prev: function () { + var d = this.parsedDate, + o = this.opts; + switch (this.view) { + case 'days': + this.date = new Date(d.year, d.month - 1, 1); + if (o.onChangeMonth) o.onChangeMonth(this.parsedDate.month, this.parsedDate.year); + break; + case 'months': + this.date = new Date(d.year - 1, d.month, 1); + if (o.onChangeYear) o.onChangeYear(this.parsedDate.year); + break; + case 'years': + this.date = new Date(d.year - 10, 0, 1); + if (o.onChangeDecade) o.onChangeDecade(this.curDecade); + break; + } + }, + + formatDate: function (string, date) { + date = date || this.date; + var result = string, + boundary = this._getWordBoundaryRegExp, + locale = this.loc, + leadingZero = datepicker.getLeadingZeroNum, + decade = datepicker.getDecade(date), + d = datepicker.getParsedDate(date), + fullHours = d.fullHours, + hours = d.hours, + ampm = string.match(boundary('aa')) || string.match(boundary('AA')), + dayPeriod = 'am', + replacer = this._replacer, + validHours; + + if (this.opts.timepicker && this.timepicker && ampm) { + validHours = this.timepicker._getValidHoursFromDate(date, ampm); + fullHours = leadingZero(validHours.hours); + hours = validHours.hours; + dayPeriod = validHours.dayPeriod; + } + + switch (true) { + case /@/.test(result): + result = result.replace(/@/, date.getTime()); + case /aa/.test(result): + result = replacer(result, boundary('aa'), dayPeriod); + case /AA/.test(result): + result = replacer(result, boundary('AA'), dayPeriod.toUpperCase()); + case /dd/.test(result): + result = replacer(result, boundary('dd'), d.fullDate); + case /d/.test(result): + result = replacer(result, boundary('d'), d.date); + case /DD/.test(result): + result = replacer(result, boundary('DD'), locale.days[d.day]); + case /D/.test(result): + result = replacer(result, boundary('D'), locale.daysShort[d.day]); + case /mm/.test(result): + result = replacer(result, boundary('mm'), d.fullMonth); + case /m/.test(result): + result = replacer(result, boundary('m'), d.month + 1); + case /MM/.test(result): + result = replacer(result, boundary('MM'), this.loc.months[d.month]); + case /M/.test(result): + result = replacer(result, boundary('M'), locale.monthsShort[d.month]); + case /ss/.test(result): + result = replacer(result, boundary('ss'), d.fullSeconds); + case /s/.test(result): + result = replacer(result, boundary('s'), d.seconds); + case /ii/.test(result): + result = replacer(result, boundary('ii'), d.fullMinutes); + case /i/.test(result): + result = replacer(result, boundary('i'), d.minutes); + case /hh/.test(result): + result = replacer(result, boundary('hh'), fullHours); + case /h/.test(result): + result = replacer(result, boundary('h'), hours); + case /yyyy/.test(result): + result = replacer(result, boundary('yyyy'), d.year); + case /yyyy1/.test(result): + result = replacer(result, boundary('yyyy1'), decade[0]); + case /yyyy2/.test(result): + result = replacer(result, boundary('yyyy2'), decade[1]); + case /yy/.test(result): + result = replacer(result, boundary('yy'), d.year.toString().slice(-2)); + } + + return result; + }, + + _replacer: function (str, reg, data) { + return str.replace(reg, function (match, p1,p2,p3) { + return p1 + data + p3; + }) + }, + + _getWordBoundaryRegExp: function (sign) { + var symbols = '\\s|\\.|-|/|\\\\|,|\\$|\\!|\\?|:|;'; + + return new RegExp('(^|>|' + symbols + ')(' + sign + ')($|<|' + symbols + ')', 'g'); + }, + + + selectDate: function (date) { + var _this = this, + opts = _this.opts, + d = _this.parsedDate, + selectedDates = _this.selectedDates, + len = selectedDates.length, + newDate = ''; + + if (Array.isArray(date)) { + date.forEach(function (d) { + _this.selectDate(d) + }); + return; + } + + if (!(date instanceof Date)) return; + + this.lastSelectedDate = date; + + // Set new time values from Date + if (this.timepicker) { + this.timepicker._setTime(date); + } + + // On this step timepicker will set valid values in it's instance + _this._trigger('selectDate', date); + + // Set correct time values after timepicker's validation + // Prevent from setting hours or minutes which values are lesser then `min` value or + // greater then `max` value + if (this.timepicker) { + date.setHours(this.timepicker.hours); + date.setMinutes(this.timepicker.minutes) + date.setSeconds(this.timepicker.seconds) + } + + if (_this.view == 'days') { + if (date.getMonth() != d.month && opts.moveToOtherMonthsOnSelect) { + newDate = new Date(date.getFullYear(), date.getMonth(), 1); + } + } + + if (_this.view == 'years') { + if (date.getFullYear() != d.year && opts.moveToOtherYearsOnSelect) { + newDate = new Date(date.getFullYear(), 0, 1); + } + } + + if (newDate) { + _this.silent = true; + _this.date = newDate; + _this.silent = false; + _this.nav._render() + } + + if (opts.multipleDates && !opts.range) { // Set priority to range functionality + if (len === opts.multipleDates) return; + if (!_this._isSelected(date)) { + _this.selectedDates.push(date); + } + } else if (opts.range) { + if (len == 2) { + _this.selectedDates = [date]; + _this.minRange = date; + _this.maxRange = ''; + } else if (len == 1) { + _this.selectedDates.push(date); + if (!_this.maxRange){ + _this.maxRange = date; + } else { + _this.minRange = date; + } + // Swap dates if they were selected via dp.selectDate() and second date was smaller then first + if (datepicker.bigger(_this.maxRange, _this.minRange)) { + _this.maxRange = _this.minRange; + _this.minRange = date; + } + _this.selectedDates = [_this.minRange, _this.maxRange] + + } else { + _this.selectedDates = [date]; + _this.minRange = date; + } + } else { + _this.selectedDates = [date]; + } + + _this._setInputValue(); + + if (opts.onSelect) { + _this._triggerOnChange(); + } + + if (opts.autoClose && !this.timepickerIsActive) { + if (!opts.multipleDates && !opts.range) { + _this.hide(); + } else if (opts.range && _this.selectedDates.length == 2) { + _this.hide(); + } + } + + _this.views[this.currentView]._render() + }, + + removeDate: function (date) { + var selected = this.selectedDates, + _this = this; + + if (!(date instanceof Date)) return; + + return selected.some(function (curDate, i) { + if (datepicker.isSame(curDate, date)) { + selected.splice(i, 1); + + if (!_this.selectedDates.length) { + _this.minRange = ''; + _this.maxRange = ''; + _this.lastSelectedDate = ''; + } else { + _this.lastSelectedDate = _this.selectedDates[_this.selectedDates.length - 1]; + } + + _this.views[_this.currentView]._render(); + _this._setInputValue(); + + if (_this.opts.onSelect) { + _this._triggerOnChange(); + } + + return true + } + }) + }, + + today: function () { + this.silent = true; + this.view = this.opts.minView; + this.silent = false; + this.date = new Date(); + + if (this.opts.todayButton instanceof Date) { + this.selectDate(this.opts.todayButton) + } + }, + + clear: function () { + this.selectedDates = []; + this.minRange = ''; + this.maxRange = ''; + this.views[this.currentView]._render(); + this._setInputValue(); + if (this.opts.onSelect) { + this._triggerOnChange() + } + }, + + /** + * Updates datepicker options + * @param {String|Object} param - parameter's name to update. If object then it will extend current options + * @param {String|Number|Object} [value] - new param value + */ + update: function (param, value) { + var len = arguments.length, + lastSelectedDate = this.lastSelectedDate; + + if (len == 2) { + this.opts[param] = value; + } else if (len == 1 && typeof param == 'object') { + this.opts = $.extend(true, this.opts, param) + } + + this._createShortCuts(); + this._syncWithMinMaxDates(); + this._defineLocale(this.opts.language); + this.nav._addButtonsIfNeed(); + if (!this.opts.onlyTimepicker) this.nav._render(); + this.views[this.currentView]._render(); + + if (this.elIsInput && !this.opts.inline) { + this._setPositionClasses(this.opts.position); + if (this.visible) { + this.setPosition(this.opts.position) + } + } + + if (this.opts.classes) { + this.$datepicker.addClass(this.opts.classes) + } + + if (this.opts.onlyTimepicker) { + this.$datepicker.addClass('-only-timepicker-'); + } + + if (this.opts.timepicker) { + if (lastSelectedDate) this.timepicker._handleDate(lastSelectedDate); + this.timepicker._updateRanges(); + this.timepicker._updateCurrentTime(); + // Change hours and minutes if it's values have been changed through min/max hours/minutes + if (lastSelectedDate) { + lastSelectedDate.setHours(this.timepicker.hours); + lastSelectedDate.setMinutes(this.timepicker.minutes); + lastSelectedDate.setSeconds(this.timepicker.seconds); + } + } + + this._setInputValue(); + + return this; + }, + + _syncWithMinMaxDates: function () { + var curTime = this.date.getTime(); + this.silent = true; + if (this.minTime > curTime) { + this.date = this.minDate; + } + + if (this.maxTime < curTime) { + this.date = this.maxDate; + } + this.silent = false; + }, + + _isSelected: function (checkDate, cellType) { + var res = false; + this.selectedDates.some(function (date) { + if (datepicker.isSame(date, checkDate, cellType)) { + res = date; + return true; + } + }); + return res; + }, + + _setInputValue: function () { + var _this = this, + opts = _this.opts, + format = _this.loc.dateFormat, + altFormat = opts.altFieldDateFormat, + value = _this.selectedDates.map(function (date) { + return _this.formatDate(format, date) + }), + altValues; + + if (opts.altField && _this.$altField.length) { + altValues = this.selectedDates.map(function (date) { + return _this.formatDate(altFormat, date) + }); + altValues = altValues.join(this.opts.multipleDatesSeparator); + this.$altField.val(altValues); + } + + value = value.join(this.opts.multipleDatesSeparator); + + this.$el.val(value) + }, + + /** + * Check if date is between minDate and maxDate + * @param date {object} - date object + * @param type {string} - cell type + * @returns {boolean} + * @private + */ + _isInRange: function (date, type) { + var time = date.getTime(), + d = datepicker.getParsedDate(date), + min = datepicker.getParsedDate(this.minDate), + max = datepicker.getParsedDate(this.maxDate), + dMinTime = new Date(d.year, d.month, min.date).getTime(), + dMaxTime = new Date(d.year, d.month, max.date).getTime(), + types = { + day: time >= this.minTime && time <= this.maxTime, + month: dMinTime >= this.minTime && dMaxTime <= this.maxTime, + year: d.year >= min.year && d.year <= max.year + }; + return type ? types[type] : types.day + }, + + _getDimensions: function ($el) { + var offset = $el.offset(); + + return { + width: $el.outerWidth(), + height: $el.outerHeight(), + left: offset.left, + top: offset.top + } + }, + + _getDateFromCell: function (cell) { + var curDate = this.parsedDate, + year = cell.data('year') || curDate.year, + month = cell.data('month') == undefined ? curDate.month : cell.data('month'), + date = cell.data('date') || 1; + + return new Date(year, month, date); + }, + + _setPositionClasses: function (pos) { + pos = pos.split(' '); + var main = pos[0], + sec = pos[1], + classes = 'datepicker -' + main + '-' + sec + '- -from-' + main + '-'; + + if (this.visible) classes += ' active'; + + this.$datepicker + .removeAttr('class') + .addClass(classes); + }, + + setPosition: function (position) { + position = position || this.opts.position; + + var dims = this._getDimensions(this.$el), + selfDims = this._getDimensions(this.$datepicker), + pos = position.split(' '), + top, left, + offset = this.opts.offset, + main = pos[0], + secondary = pos[1]; + + switch (main) { + case 'top': + top = dims.top - selfDims.height - offset; + break; + case 'right': + left = dims.left + dims.width + offset; + break; + case 'bottom': + top = dims.top + dims.height + offset; + break; + case 'left': + left = dims.left - selfDims.width - offset; + break; + } + + switch(secondary) { + case 'top': + top = dims.top; + break; + case 'right': + left = dims.left + dims.width - selfDims.width; + break; + case 'bottom': + top = dims.top + dims.height - selfDims.height; + break; + case 'left': + left = dims.left; + break; + case 'center': + if (/left|right/.test(main)) { + top = dims.top + dims.height/2 - selfDims.height/2; + } else { + left = dims.left + dims.width/2 - selfDims.width/2; + } + } + + this.$datepicker + .css({ + left: left, + top: top + }) + }, + + show: function () { + var onShow = this.opts.onShow; + + this.setPosition(this.opts.position); + this.$datepicker.addClass('active'); + this.visible = true; + + if (onShow) { + this._bindVisionEvents(onShow) + } + }, + + hide: function () { + var onHide = this.opts.onHide; + + this.$datepicker + .removeClass('active') + .css({ + left: '-100000px' + }); + + this.focused = ''; + this.keys = []; + + this.inFocus = false; + this.visible = false; + this.$el.blur(); + + if (onHide) { + this._bindVisionEvents(onHide) + } + }, + + down: function (date) { + this._changeView(date, 'down'); + }, + + up: function (date) { + this._changeView(date, 'up'); + }, + + _bindVisionEvents: function (event) { + this.$datepicker.off('transitionend.dp'); + event(this, false); + this.$datepicker.one('transitionend.dp', event.bind(this, this, true)) + }, + + _changeView: function (date, dir) { + date = date || this.focused || this.date; + + var nextView = dir == 'up' ? this.viewIndex + 1 : this.viewIndex - 1; + if (nextView > 2) nextView = 2; + if (nextView < 0) nextView = 0; + + this.silent = true; + this.date = new Date(date.getFullYear(), date.getMonth(), 1); + this.silent = false; + this.view = this.viewIndexes[nextView]; + + }, + + _handleHotKey: function (key) { + var date = datepicker.getParsedDate(this._getFocusedDate()), + focusedParsed, + o = this.opts, + newDate, + totalDaysInNextMonth, + monthChanged = false, + yearChanged = false, + decadeChanged = false, + y = date.year, + m = date.month, + d = date.date; + + switch (key) { + case 'ctrlRight': + case 'ctrlUp': + m += 1; + monthChanged = true; + break; + case 'ctrlLeft': + case 'ctrlDown': + m -= 1; + monthChanged = true; + break; + case 'shiftRight': + case 'shiftUp': + yearChanged = true; + y += 1; + break; + case 'shiftLeft': + case 'shiftDown': + yearChanged = true; + y -= 1; + break; + case 'altRight': + case 'altUp': + decadeChanged = true; + y += 10; + break; + case 'altLeft': + case 'altDown': + decadeChanged = true; + y -= 10; + break; + case 'ctrlShiftUp': + this.up(); + break; + } + + totalDaysInNextMonth = datepicker.getDaysCount(new Date(y,m)); + newDate = new Date(y,m,d); + + // If next month has less days than current, set date to total days in that month + if (totalDaysInNextMonth < d) d = totalDaysInNextMonth; + + // Check if newDate is in valid range + if (newDate.getTime() < this.minTime) { + newDate = this.minDate; + } else if (newDate.getTime() > this.maxTime) { + newDate = this.maxDate; + } + + this.focused = newDate; + + focusedParsed = datepicker.getParsedDate(newDate); + if (monthChanged && o.onChangeMonth) { + o.onChangeMonth(focusedParsed.month, focusedParsed.year) + } + if (yearChanged && o.onChangeYear) { + o.onChangeYear(focusedParsed.year) + } + if (decadeChanged && o.onChangeDecade) { + o.onChangeDecade(this.curDecade) + } + }, + + _registerKey: function (key) { + var exists = this.keys.some(function (curKey) { + return curKey == key; + }); + + if (!exists) { + this.keys.push(key) + } + }, + + _unRegisterKey: function (key) { + var index = this.keys.indexOf(key); + + this.keys.splice(index, 1); + }, + + _isHotKeyPressed: function () { + var currentHotKey, + found = false, + _this = this, + pressedKeys = this.keys.sort(); + + for (var hotKey in hotKeys) { + currentHotKey = hotKeys[hotKey]; + if (pressedKeys.length != currentHotKey.length) continue; + + if (currentHotKey.every(function (key, i) { return key == pressedKeys[i]})) { + _this._trigger('hotKey', hotKey); + found = true; + } + } + + return found; + }, + + _trigger: function (event, args) { + this.$el.trigger(event, args) + }, + + _focusNextCell: function (keyCode, type) { + type = type || this.cellType; + + var date = datepicker.getParsedDate(this._getFocusedDate()), + y = date.year, + m = date.month, + d = date.date; + + if (this._isHotKeyPressed()){ + return; + } + + switch(keyCode) { + case 37: // left + type == 'day' ? (d -= 1) : ''; + type == 'month' ? (m -= 1) : ''; + type == 'year' ? (y -= 1) : ''; + break; + case 38: // up + type == 'day' ? (d -= 7) : ''; + type == 'month' ? (m -= 3) : ''; + type == 'year' ? (y -= 4) : ''; + break; + case 39: // right + type == 'day' ? (d += 1) : ''; + type == 'month' ? (m += 1) : ''; + type == 'year' ? (y += 1) : ''; + break; + case 40: // down + type == 'day' ? (d += 7) : ''; + type == 'month' ? (m += 3) : ''; + type == 'year' ? (y += 4) : ''; + break; + } + + var nd = new Date(y,m,d); + if (nd.getTime() < this.minTime) { + nd = this.minDate; + } else if (nd.getTime() > this.maxTime) { + nd = this.maxDate; + } + + this.focused = nd; + + }, + + _getFocusedDate: function () { + var focused = this.focused || this.selectedDates[this.selectedDates.length - 1], + d = this.parsedDate; + + if (!focused) { + switch (this.view) { + case 'days': + focused = new Date(d.year, d.month, new Date().getDate()); + break; + case 'months': + focused = new Date(d.year, d.month, 1); + break; + case 'years': + focused = new Date(d.year, 0, 1); + break; + } + } + + return focused; + }, + + _getCell: function (date, type) { + type = type || this.cellType; + + var d = datepicker.getParsedDate(date), + selector = '.datepicker--cell[data-year="' + d.year + '"]', + $cell; + + switch (type) { + case 'month': + selector = '[data-month="' + d.month + '"]'; + break; + case 'day': + selector += '[data-month="' + d.month + '"][data-date="' + d.date + '"]'; + break; + } + $cell = this.views[this.currentView].$el.find(selector); + + return $cell.length ? $cell : $(''); + }, + + destroy: function () { + var _this = this; + _this.$el + .off('.adp') + .data('datepicker', ''); + + _this.selectedDates = []; + _this.focused = ''; + _this.views = {}; + _this.keys = []; + _this.minRange = ''; + _this.maxRange = ''; + + if (_this.opts.inline || !_this.elIsInput) { + _this.$datepicker.closest('.datepicker-inline').remove(); + } else { + _this.$datepicker.remove(); + } + }, + + _handleAlreadySelectedDates: function (alreadySelected, selectedDate) { + if (this.opts.range) { + if (!this.opts.toggleSelected) { + // Add possibility to select same date when range is true + if (this.selectedDates.length != 2) { + this._trigger('clickCell', selectedDate); + } + } else { + this.removeDate(selectedDate); + } + } else if (this.opts.toggleSelected){ + this.removeDate(selectedDate); + } + + // Change last selected date to be able to change time when clicking on this cell + if (!this.opts.toggleSelected) { + this.lastSelectedDate = alreadySelected; + if (this.opts.timepicker) { + this.timepicker._setTime(alreadySelected); + this.timepicker.update(); + } + } + }, + + _onShowEvent: function (e) { + if (!this.visible) { + this.show(); + } + }, + + _onBlur: function () { + if (!this.inFocus && this.visible) { + this.hide(); + } + }, + + _onMouseDownDatepicker: function (e) { + this.inFocus = true; + }, + + _onMouseUpDatepicker: function (e) { + this.inFocus = false; + e.originalEvent.inFocus = true; + if (!e.originalEvent.timepickerFocus) this.$el.focus(); + }, + + _onKeyUpGeneral: function (e) { + var val = this.$el.val(); + + if (!val) { + this.clear(); + } + }, + + _onResize: function () { + if (this.visible) { + this.setPosition(); + } + }, + + _onMouseUpBody: function (e) { + if (e.originalEvent.inFocus) return; + + if (this.visible && !this.inFocus) { + this.hide(); + } + }, + + _onMouseUpEl: function (e) { + e.originalEvent.inFocus = true; + setTimeout(this._onKeyUpGeneral.bind(this),4); + }, + + _onKeyDown: function (e) { + var code = e.which; + this._registerKey(code); + + // Arrows + if (code >= 37 && code <= 40) { + e.preventDefault(); + this._focusNextCell(code); + } + + // Enter + if (code == 13) { + if (this.focused) { + if (this._getCell(this.focused).hasClass('-disabled-')) return; + if (this.view != this.opts.minView) { + this.down() + } else { + var alreadySelected = this._isSelected(this.focused, this.cellType); + + if (!alreadySelected) { + if (this.timepicker) { + this.focused.setHours(this.timepicker.hours); + this.focused.setMinutes(this.timepicker.minutes); + this.focused.setSeconds(this.timepicker.seconds); + } + this.selectDate(this.focused); + return; + } + this._handleAlreadySelectedDates(alreadySelected, this.focused) + } + } + } + + // Esc + if (code == 27) { + this.hide(); + } + }, + + _onKeyUp: function (e) { + var code = e.which; + this._unRegisterKey(code); + }, + + _onHotKey: function (e, hotKey) { + this._handleHotKey(hotKey); + }, + + _onMouseEnterCell: function (e) { + var $cell = $(e.target).closest('.datepicker--cell'), + date = this._getDateFromCell($cell); + + // Prevent from unnecessary rendering and setting new currentDate + this.silent = true; + + if (this.focused) { + this.focused = '' + } + + $cell.addClass('-focus-'); + + this.focused = date; + this.silent = false; + + if (this.opts.range && this.selectedDates.length == 1) { + this.minRange = this.selectedDates[0]; + this.maxRange = ''; + if (datepicker.less(this.minRange, this.focused)) { + this.maxRange = this.minRange; + this.minRange = ''; + } + this.views[this.currentView]._update(); + } + }, + + _onMouseLeaveCell: function (e) { + var $cell = $(e.target).closest('.datepicker--cell'); + + $cell.removeClass('-focus-'); + + this.silent = true; + this.focused = ''; + this.silent = false; + }, + + _onTimeChange: function (e, h, m, s) { + var date = new Date(), + selectedDates = this.selectedDates, + selected = false; + + if (selectedDates.length) { + selected = true; + date = this.lastSelectedDate; + } + + date.setHours(h); + date.setMinutes(m); + date.setSeconds(s); + + if (!selected && !this._getCell(date).hasClass('-disabled-')) { + this.selectDate(date); + } else { + this._setInputValue(); + if (this.opts.onSelect) { + this._triggerOnChange(); + } + } + }, + + _onClickCell: function (e, date) { + if (this.timepicker) { + date.setHours(this.timepicker.hours); + date.setMinutes(this.timepicker.minutes); + date.setSeconds(this.timepicker.seconds) + } + this.selectDate(date); + }, + + set focused(val) { + if (!val && this.focused) { + var $cell = this._getCell(this.focused); + + if ($cell.length) { + $cell.removeClass('-focus-') + } + } + this._focused = val; + if (this.opts.range && this.selectedDates.length == 1) { + this.minRange = this.selectedDates[0]; + this.maxRange = ''; + if (datepicker.less(this.minRange, this._focused)) { + this.maxRange = this.minRange; + this.minRange = ''; + } + } + if (this.silent) return; + this.date = val; + }, + + get focused() { + return this._focused; + }, + + get parsedDate() { + return datepicker.getParsedDate(this.date); + }, + + set date (val) { + if (!(val instanceof Date)) return; + + this.currentDate = val; + + if (this.inited && !this.silent) { + this.views[this.view]._render(); + this.nav._render(); + if (this.visible && this.elIsInput) { + this.setPosition(); + } + } + return val; + }, + + get date () { + return this.currentDate + }, + + set view (val) { + this.viewIndex = this.viewIndexes.indexOf(val); + + if (this.viewIndex < 0) { + return; + } + + this.prevView = this.currentView; + this.currentView = val; + + if (this.inited) { + if (!this.views[val]) { + this.views[val] = new $.fn.datepicker.Body(this, val, this.opts) + } else { + this.views[val]._render(); + } + + this.views[this.prevView].hide(); + this.views[val].show(); + this.nav._render(); + + if (this.opts.onChangeView) { + this.opts.onChangeView(val) + } + if (this.elIsInput && this.visible) this.setPosition(); + } + + return val + }, + + get view() { + return this.currentView; + }, + + get cellType() { + return this.view.substring(0, this.view.length - 1) + }, + + get minTime() { + var min = datepicker.getParsedDate(this.minDate); + return new Date(min.year, min.month, min.date).getTime() + }, + + get maxTime() { + var max = datepicker.getParsedDate(this.maxDate); + return new Date(max.year, max.month, max.date).getTime() + }, + + get curDecade() { + return datepicker.getDecade(this.date) + } + }; + + // Utils + // ------------------------------------------------- + + datepicker.getDaysCount = function (date) { + return new Date(date.getFullYear(), date.getMonth() + 1, 0).getDate(); + }; + + datepicker.getParsedDate = function (date) { + return { + year: date.getFullYear(), + month: date.getMonth(), + fullMonth: (date.getMonth() + 1) < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1, // One based + date: date.getDate(), + fullDate: date.getDate() < 10 ? '0' + date.getDate() : date.getDate(), + day: date.getDay(), + hours: date.getHours(), + fullHours: date.getHours() < 10 ? '0' + date.getHours() : date.getHours() , + minutes: date.getMinutes(), + fullMinutes: date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes(), + seconds: date.getSeconds(), + fullSeconds: date.getSeconds() < 10 ? '0' + date.getSeconds() : date.getSeconds() + } + }; + + datepicker.getDecade = function (date) { + var firstYear = Math.floor(date.getFullYear() / 10) * 10; + + return [firstYear, firstYear + 9]; + }; + + datepicker.template = function (str, data) { + return str.replace(/#\{([\w]+)\}/g, function (source, match) { + if (data[match] || data[match] === 0) { + return data[match] + } + }); + }; + + datepicker.isSame = function (date1, date2, type) { + if (!date1 || !date2) return false; + var d1 = datepicker.getParsedDate(date1), + d2 = datepicker.getParsedDate(date2), + _type = type ? type : 'day', + + conditions = { + day: d1.date == d2.date && d1.month == d2.month && d1.year == d2.year, + month: d1.month == d2.month && d1.year == d2.year, + year: d1.year == d2.year + }; + + return conditions[_type]; + }; + + datepicker.less = function (dateCompareTo, date, type) { + if (!dateCompareTo || !date) return false; + return date.getTime() < dateCompareTo.getTime(); + }; + + datepicker.bigger = function (dateCompareTo, date, type) { + if (!dateCompareTo || !date) return false; + return date.getTime() > dateCompareTo.getTime(); + }; + + datepicker.getLeadingZeroNum = function (num) { + return parseInt(num) < 10 ? '0' + num : num; + }; + + /** + * Returns copy of date with hours and minutes equals to 0 + * @param date {Date} + */ + datepicker.resetTime = function (date) { + if (typeof date != 'object') return; + date = datepicker.getParsedDate(date); + return new Date(date.year, date.month, date.date) + }; + + $.fn.datepicker = function ( options ) { + return this.each(function () { + if (!$.data(this, pluginName)) { + $.data(this, pluginName, + new Datepicker( this, options )); + } else { + var _this = $.data(this, pluginName); + + _this.opts = $.extend(true, _this.opts, options); + _this.update(); + } + }); + }; + + $.fn.datepicker.Constructor = Datepicker; + + $.fn.datepicker.language = { + ru: { + days: ['Воскресенье', 'Понедельник', 'Вторник', 'Среда', 'Четверг', 'Пятница', 'Суббота'], + daysShort: ['Вос','Пон','Вто','Сре','Чет','Пят','Суб'], + daysMin: ['Вс','Пн','Вт','Ср','Чт','Пт','Сб'], + months: ['Январь', 'Февраль', 'Март', 'Апрель', 'Май', 'Июнь', 'Июль', 'Август', 'Сентябрь', 'Октябрь', 'Ноябрь', 'Декабрь'], + monthsShort: ['Янв', 'Фев', 'Мар', 'Апр', 'Май', 'Июн', 'Июл', 'Авг', 'Сен', 'Окт', 'Ноя', 'Дек'], + today: 'Сегодня', + clear: 'Очистить', + dateFormat: 'dd.mm.yyyy', + timeFormat: 'hh:ii', + firstDay: 1 + } + }; + + $(function () { + $(autoInitSelector).datepicker(); + }) + +})(); diff --git a/src/js/i18n/datepicker.cs.js b/src/js/i18n/datepicker.cs.js new file mode 100644 index 0000000..05fdabc --- /dev/null +++ b/src/js/i18n/datepicker.cs.js @@ -0,0 +1,12 @@ +$.fn.datepicker.language['cs'] = { + days: ['Neděle', 'Pondělí', 'Úterý', 'Středa', 'Čtvrtek', 'Pátek', 'Sobota'], + daysShort: ['Ne', 'Po', 'Út', 'St', 'Čt', 'Pá', 'So'], + daysMin: ['Ne', 'Po', 'Út', 'St', 'Čt', 'Pá', 'So'], + months: ['Leden', 'Únor', 'Březen', 'Duben', 'Květen', 'Červen', 'Červenec', 'Srpen', 'Září', 'Říjen', 'Listopad', 'Prosinec'], + monthsShort: ['Led', 'Úno', 'Bře', 'Dub', 'Kvě', 'Čvn', 'Čvc', 'Srp', 'Zář', 'Říj', 'Lis', 'Pro'], + today: 'Dnes', + clear: 'Vymazat', + dateFormat: 'dd.mm.yyyy', + timeFormat: 'hh:ii', + firstDay: 1 +}; \ No newline at end of file diff --git a/src/js/i18n/datepicker.da.js b/src/js/i18n/datepicker.da.js new file mode 100644 index 0000000..fc63e28 --- /dev/null +++ b/src/js/i18n/datepicker.da.js @@ -0,0 +1,12 @@ +$.fn.datepicker.language['da'] = { + days: ['Søndag', 'Mandag', 'Tirsdag', 'Onsdag', 'Torsdag', 'Fredag', 'Lørdag'], + daysShort: ['Søn', 'Man', 'Tir', 'Ons', 'Tor', 'Fre', 'Lør'], + daysMin: ['Sø', 'Ma', 'Ti', 'On', 'To', 'Fr', 'Lø'], + months: ['Januar','Februar','Marts','April','Maj','Juni', 'Juli','August','September','Oktober','November','December'], + monthsShort: ['Jan', 'Feb', 'Mar', 'Apr', 'Maj', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dec'], + today: 'I dag', + clear: 'Nulstil', + dateFormat: 'dd/mm/yyyy', + timeFormat: 'hh:ii', + firstDay: 1 +}; \ No newline at end of file diff --git a/src/js/i18n/datepicker.de.js b/src/js/i18n/datepicker.de.js new file mode 100644 index 0000000..6472863 --- /dev/null +++ b/src/js/i18n/datepicker.de.js @@ -0,0 +1,12 @@ +$.fn.datepicker.language['de'] = { + days: ['Sonntag', 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag'], + daysShort: ['Son', 'Mon', 'Die', 'Mit', 'Don', 'Fre', 'Sam'], + daysMin: ['So', 'Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa'], + months: ['Januar','Februar','März','April','Mai','Juni', 'Juli','August','September','Oktober','November','Dezember'], + monthsShort: ['Jan', 'Feb', 'Mär', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez'], + today: 'Heute', + clear: 'Aufräumen', + dateFormat: 'dd.mm.yyyy', + timeFormat: 'hh:ii', + firstDay: 1 +}; diff --git a/src/js/i18n/datepicker.en.js b/src/js/i18n/datepicker.en.js new file mode 100644 index 0000000..5963553 --- /dev/null +++ b/src/js/i18n/datepicker.en.js @@ -0,0 +1,12 @@ +$.fn.datepicker.language['en'] = { + days: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], + daysShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], + daysMin: ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'], + months: ['January','February','March','April','May','June', 'July','August','September','October','November','December'], + monthsShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], + today: 'Today', + clear: 'Clear', + dateFormat: 'mm/dd/yyyy', + timeFormat: 'hh:ii aa', + firstDay: 0 +}; \ No newline at end of file diff --git a/src/js/i18n/datepicker.es.js b/src/js/i18n/datepicker.es.js new file mode 100644 index 0000000..8ad1921 --- /dev/null +++ b/src/js/i18n/datepicker.es.js @@ -0,0 +1,12 @@ +$.fn.datepicker.language['es'] = { + days: ['Domingo', 'Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado'], + daysShort: ['Dom', 'Lun', 'Mar', 'Mie', 'Jue', 'Vie', 'Sab'], + daysMin: ['Do', 'Lu', 'Ma', 'Mi', 'Ju', 'Vi', 'Sa'], + months: ['Enero','Febrero','Marzo','Abril','Mayo','Junio', 'Julio','Augosto','Septiembre','Octubre','Noviembre','Diciembre'], + monthsShort: ['Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic'], + today: 'Hoy', + clear: 'Limpiar', + dateFormat: 'dd/mm/yyyy', + timeFormat: 'hh:ii aa', + firstDay: 1 +}; \ No newline at end of file diff --git a/src/js/i18n/datepicker.fi.js b/src/js/i18n/datepicker.fi.js new file mode 100644 index 0000000..27f741b --- /dev/null +++ b/src/js/i18n/datepicker.fi.js @@ -0,0 +1,12 @@ +$.fn.datepicker.language['fi'] = { + days: ['Sunnuntai', 'Maanantai', 'Tiistai', 'Keskiviikko', 'Torstai', 'Perjantai', 'Lauantai'], + daysShort: ['Su', 'Ma', 'Ti', 'Ke', 'To', 'Pe', 'La'], + daysMin: ['Su', 'Ma', 'Ti', 'Ke', 'To', 'Pe', 'La'], + months: ['Tammikuu','Helmikuu','Maaliskuu','Huhtikuu','Toukokuu','Kesäkuu', 'Heinäkuu','Elokuu','Syyskuu','Lokakuu','Marraskuu','Joulukuu'], + monthsShort: ['Tammi', 'Helmi', 'Maalis', 'Huhti', 'Touko', 'Kesä', 'Heinä', 'Elo', 'Syys', 'Loka', 'Marras', 'Joulu'], + today: 'Tänään', + clear: 'Tyhjennä', + dateFormat: 'dd.mm.yyyy', + timeFormat: 'hh:ii', + firstDay: 1 +}; diff --git a/src/js/i18n/datepicker.fr.js b/src/js/i18n/datepicker.fr.js new file mode 100644 index 0000000..de36c31 --- /dev/null +++ b/src/js/i18n/datepicker.fr.js @@ -0,0 +1,12 @@ +$.fn.datepicker.language['fr'] = { + days: ['Dimanche', 'Lundi', 'Mardi', 'Mercredi', 'Jeudi', 'Vendredi', 'Samedi'], + daysShort: ['Dim', 'Lun', 'Mar', 'Mer', 'Jeu', 'Ven', 'Sam'], + daysMin: ['Di', 'Lu', 'Ma', 'Me', 'Je', 'Ve', 'Sa'], + months: ['Janvier','Février','Mars','Avril','Mai','Juin', 'Juillet','Août','Septembre','Octobre','Novembre','Decembre'], + monthsShort: ['Jan', 'Fév', 'Mars', 'Avr', 'Mai', 'Juin', 'Juil', 'Août', 'Sep', 'Oct', 'Nov', 'Dec'], + today: "Aujourd'hui", + clear: 'Effacer', + dateFormat: 'dd/mm/yyyy', + timeFormat: 'hh:ii', + firstDay: 1 +}; \ No newline at end of file diff --git a/src/js/i18n/datepicker.hu.js b/src/js/i18n/datepicker.hu.js new file mode 100644 index 0000000..1ead746 --- /dev/null +++ b/src/js/i18n/datepicker.hu.js @@ -0,0 +1,12 @@ +;(function ($) { $.fn.datepicker.language['hu'] = { + days: ['Vasárnap', 'Hétfő', 'Kedd', 'Szerda', 'Csütörtök', 'Péntek', 'Szombat'], + daysShort: ['Va', 'Hé', 'Ke', 'Sze', 'Cs', 'Pé', 'Szo'], + daysMin: ['V', 'H', 'K', 'Sz', 'Cs', 'P', 'Sz'], + months: ['Január', 'Február', 'Március', 'Április', 'Május', 'Június', 'Július', 'Augusztus', 'Szeptember', 'Október', 'November', 'December'], + monthsShort: ['Jan', 'Feb', 'Már', 'Ápr', 'Máj', 'Jún', 'Júl', 'Aug', 'Szep', 'Okt', 'Nov', 'Dec'], + today: 'Ma', + clear: 'Törlés', + dateFormat: 'yyyy-mm-dd', + timeFormat: 'hh:ii aa', + firstDay: 1 +}; })(jQuery); \ No newline at end of file diff --git a/src/js/i18n/datepicker.nl.js b/src/js/i18n/datepicker.nl.js new file mode 100644 index 0000000..08cfe41 --- /dev/null +++ b/src/js/i18n/datepicker.nl.js @@ -0,0 +1,12 @@ +$.fn.datepicker.language['nl'] = { + days: ['zondag', 'maandag', 'dinsdag', 'woensdag', 'donderdag', 'vrijdag', 'zaterdag'], + daysShort: ['zo', 'ma', 'di', 'wo', 'do', 'vr', 'za'], + daysMin: ['zo', 'ma', 'di', 'wo', 'do', 'vr', 'za'], + months: ['Januari', 'Februari', 'Maart', 'April', 'Mei', 'Juni', 'Juli', 'Augustus', 'September', 'Oktober', 'November', 'December'], + monthsShort: ['Jan', 'Feb', 'Mrt', 'Apr', 'Mei', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dec'], + today: 'Vandaag', + clear: 'Legen', + dateFormat: 'dd-MM-yy', + timeFormat: 'hh:ii', + firstDay: 0 +}; \ No newline at end of file diff --git a/src/js/i18n/datepicker.pl.js b/src/js/i18n/datepicker.pl.js new file mode 100644 index 0000000..67f87f6 --- /dev/null +++ b/src/js/i18n/datepicker.pl.js @@ -0,0 +1,12 @@ +$.fn.datepicker.language['pl'] = { + days: ['Niedziela', 'Poniedziałek', 'Wtorek', 'Środa', 'Czwartek', 'Piątek', 'Sobota'], + daysShort: ['Nie', 'Pon', 'Wto', 'Śro', 'Czw', 'Pią', 'Sob'], + daysMin: ['Nd', 'Pn', 'Wt', 'Śr', 'Czw', 'Pt', 'So'], + months: ['Styczeń','Luty','Marzec','Kwiecień','Maj','Czerwiec', 'Lipiec','Sierpień','Wrzesień','Październik','Listopad','Grudzień'], + monthsShort: ['Sty', 'Lut', 'Mar', 'Kwi', 'Maj', 'Cze', 'Lip', 'Sie', 'Wrz', 'Paź', 'Lis', 'Gru'], + today: 'Dzisiaj', + clear: 'Wyczyść', + dateFormat: 'yyyy-mm-dd', + timeFormat: 'hh:ii:aa', + firstDay: 1 +}; diff --git a/src/js/i18n/datepicker.pt-BR.js b/src/js/i18n/datepicker.pt-BR.js new file mode 100644 index 0000000..bb076ab --- /dev/null +++ b/src/js/i18n/datepicker.pt-BR.js @@ -0,0 +1,12 @@ +$.fn.datepicker.language['pt-BR'] = { + days: ['Domingo', 'Segunda', 'Terça', 'Quarta', 'Quinta', 'Sexta', 'Sábado'], + daysShort: ['Dom', 'Seg', 'Ter', 'Qua', 'Qui', 'Sex', 'Sab'], + daysMin: ['Do', 'Se', 'Te', 'Qu', 'Qu', 'Se', 'Sa'], + months: ['Janeiro', 'Fevereiro', 'Março', 'Abril', 'Maio', 'Junho', 'Julho', 'Agosto', 'Setembro', 'Outubro', 'Novembro', 'Dezembro'], + monthsShort: ['Jan', 'Fev', 'Mar', 'Abr', 'Mai', 'Jun', 'Jul', 'Ago', 'Set', 'Out', 'Nov', 'Dez'], + today: 'Hoje', + clear: 'Limpar', + dateFormat: 'dd/mm/yyyy', + timeFormat: 'hh:ii', + firstDay: 0 +}; \ No newline at end of file diff --git a/src/js/i18n/datepicker.pt.js b/src/js/i18n/datepicker.pt.js new file mode 100644 index 0000000..b9f6a27 --- /dev/null +++ b/src/js/i18n/datepicker.pt.js @@ -0,0 +1,12 @@ +$.fn.datepicker.language['pt'] = { + days: ['Domingo', 'Segunda', 'Terça', 'Quarta', 'Quinta', 'Sexta', 'Sábado'], + daysShort: ['Dom', 'Seg', 'Ter', 'Qua', 'Qui', 'Sex', 'Sab'], + daysMin: ['Do', 'Se', 'Te', 'Qa', 'Qi', 'Sx', 'Sa'], + months: ['Janeiro', 'Fevereiro', 'Março', 'Abril', 'Maio', 'Junho', 'Julho', 'Agosto', 'Setembro', 'Outubro', 'Novembro', 'Dezembro'], + monthsShort: ['Jan', 'Fev', 'Mar', 'Abr', 'Mai', 'Jun', 'Jul', 'Ago', 'Set', 'Out', 'Nov', 'Dez'], + today: 'Hoje', + clear: 'Limpar', + dateFormat: 'dd/mm/yyyy', + timeFormat: 'hh:ii', + firstDay: 1 +}; \ No newline at end of file diff --git a/src/js/i18n/datepicker.ro.js b/src/js/i18n/datepicker.ro.js new file mode 100644 index 0000000..f458341 --- /dev/null +++ b/src/js/i18n/datepicker.ro.js @@ -0,0 +1,12 @@ +$.fn.datepicker.language['ro'] = { + days: ['Duminică', 'Luni', 'Marţi', 'Miercuri', 'Joi', 'Vineri', 'Sâmbătă'], + daysShort: ['Dum', 'Lun', 'Mar', 'Mie', 'Joi', 'Vin', 'Sâm'], + daysMin: ['D', 'L', 'Ma', 'Mi', 'J', 'V', 'S'], + months: ['Ianuarie','Februarie','Martie','Aprilie','Mai','Iunie','Iulie','August','Septembrie','Octombrie','Noiembrie','Decembrie'], + monthsShort: ['Ian', 'Feb', 'Mar', 'Apr', 'Mai', 'Iun', 'Iul', 'Aug', 'Sept', 'Oct', 'Nov', 'Dec'], + today: 'Azi', + clear: 'Şterge', + dateFormat: 'dd.mm.yyyy', + timeFormat: 'hh:ii', + firstDay: 1 +}; diff --git a/src/js/i18n/datepicker.sk.js b/src/js/i18n/datepicker.sk.js new file mode 100644 index 0000000..e471ba6 --- /dev/null +++ b/src/js/i18n/datepicker.sk.js @@ -0,0 +1,12 @@ +$.fn.datepicker.language['sk'] = { + days: ['Nedeľa', 'Pondelok', 'Utorok', 'Streda', 'Štvrtok', 'Piatok', 'Sobota'], + daysShort: ['Ned', 'Pon', 'Uto', 'Str', 'Štv', 'Pia', 'Sob'], + daysMin: ['Ne', 'Po', 'Ut', 'St', 'Št', 'Pi', 'So'], + months: ['Január','Február','Marec','Apríl','Máj','Jún', 'Júl','August','September','Október','November','December'], + monthsShort: ['Jan', 'Feb', 'Mar', 'Apr', 'Máj', 'Jún', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dec'], + today: 'Dnes', + clear: 'Vymazať', + dateFormat: 'dd.mm.yyyy', + timeFormat: 'hh:ii', + firstDay: 1 +}; \ No newline at end of file diff --git a/src/js/i18n/datepicker.zh.js b/src/js/i18n/datepicker.zh.js new file mode 100644 index 0000000..464bbd5 --- /dev/null +++ b/src/js/i18n/datepicker.zh.js @@ -0,0 +1,12 @@ +$.fn.datepicker.language['zh'] = { + days: ['周日', '周一', '周二', '周三', '周四', '周五', '周六'], + daysShort: ['日', '一', '二', '三', '四', '五', '六'], + daysMin: ['日', '一', '二', '三', '四', '五', '六'], + months: ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'], + monthsShort: ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'], + today: '今天', + clear: '清除', + dateFormat: 'yyyy-mm-dd', + timeFormat: 'hh:ii', + firstDay: 1 +}; \ No newline at end of file diff --git a/src/js/navigation.js b/src/js/navigation.js new file mode 100644 index 0000000..c3d664a --- /dev/null +++ b/src/js/navigation.js @@ -0,0 +1,145 @@ +;(function () { + var template = '' + + '
#{prevHtml}
' + + '
#{title}
' + + '
#{nextHtml}
', + buttonsContainerTemplate = '
', + button = '#{label}', + datepicker = $.fn.datepicker, + dp = datepicker.Constructor; + + datepicker.Navigation = function (d, opts) { + this.d = d; + this.opts = opts; + + this.$buttonsContainer = ''; + + this.init(); + }; + + datepicker.Navigation.prototype = { + init: function () { + this._buildBaseHtml(); + this._bindEvents(); + }, + + _bindEvents: function () { + this.d.$nav.on('click', '.datepicker--nav-action', $.proxy(this._onClickNavButton, this)); + this.d.$nav.on('click', '.datepicker--nav-title', $.proxy(this._onClickNavTitle, this)); + this.d.$datepicker.on('click', '.datepicker--button', $.proxy(this._onClickNavButton, this)); + }, + + _buildBaseHtml: function () { + if (!this.opts.onlyTimepicker) { + this._render(); + } + this._addButtonsIfNeed(); + }, + + _addButtonsIfNeed: function () { + if (this.opts.todayButton) { + this._addButton('today') + } + if (this.opts.clearButton) { + this._addButton('clear') + } + }, + + _render: function () { + var title = this._getTitle(this.d.currentDate), + html = dp.template(template, $.extend({title: title}, this.opts)); + this.d.$nav.html(html); + if (this.d.view == 'years') { + $('.datepicker--nav-title', this.d.$nav).addClass('-disabled-'); + } + this.setNavStatus(); + }, + + _getTitle: function (date) { + return this.d.formatDate(this.opts.navTitles[this.d.view], date) + }, + + _addButton: function (type) { + if (!this.$buttonsContainer.length) { + this._addButtonsContainer(); + } + + var data = { + action: type, + label: this.d.loc[type] + }, + html = dp.template(button, data); + + if ($('[data-action=' + type + ']', this.$buttonsContainer).length) return; + this.$buttonsContainer.append(html); + }, + + _addButtonsContainer: function () { + this.d.$datepicker.append(buttonsContainerTemplate); + this.$buttonsContainer = $('.datepicker--buttons', this.d.$datepicker); + }, + + setNavStatus: function () { + if (!(this.opts.minDate || this.opts.maxDate) || !this.opts.disableNavWhenOutOfRange) return; + + var date = this.d.parsedDate, + m = date.month, + y = date.year, + d = date.date; + + switch (this.d.view) { + case 'days': + if (!this.d._isInRange(new Date(y, m-1, 1), 'month')) { + this._disableNav('prev') + } + if (!this.d._isInRange(new Date(y, m+1, 1), 'month')) { + this._disableNav('next') + } + break; + case 'months': + if (!this.d._isInRange(new Date(y-1, m, d), 'year')) { + this._disableNav('prev') + } + if (!this.d._isInRange(new Date(y+1, m, d), 'year')) { + this._disableNav('next') + } + break; + case 'years': + var decade = dp.getDecade(this.d.date); + if (!this.d._isInRange(new Date(decade[0] - 1, 0, 1), 'year')) { + this._disableNav('prev') + } + if (!this.d._isInRange(new Date(decade[1] + 1, 0, 1), 'year')) { + this._disableNav('next') + } + break; + } + }, + + _disableNav: function (nav) { + $('[data-action="' + nav + '"]', this.d.$nav).addClass('-disabled-') + }, + + _activateNav: function (nav) { + $('[data-action="' + nav + '"]', this.d.$nav).removeClass('-disabled-') + }, + + _onClickNavButton: function (e) { + var $el = $(e.target).closest('[data-action]'), + action = $el.data('action'); + + this.d[action](); + }, + + _onClickNavTitle: function (e) { + if ($(e.target).hasClass('-disabled-')) return; + + if (this.d.view == 'days') { + return this.d.view = 'months' + } + + this.d.view = 'years'; + } + } + +})(); diff --git a/src/js/timepicker.js b/src/js/timepicker.js new file mode 100644 index 0000000..4522532 --- /dev/null +++ b/src/js/timepicker.js @@ -0,0 +1,313 @@ +;(function () { + var template = '
' + + '
' + + ' #{hourVisible}' + + ' :' + + ' #{minValue}' + + ' :' + + ' #{secValue}' + + '
' + + '
' + + '
' + + ' ' + + '
' + + '
' + + ' ' + + '
' + + '
' + + ' ' + + '
' + + '
' + + '
', + datepicker = $.fn.datepicker, + dp = datepicker.Constructor; + + datepicker.Timepicker = function (inst, opts) { + this.d = inst; + this.opts = opts; + + this.init(); + }; + + datepicker.Timepicker.prototype = { + init: function () { + var input = 'input'; + this._setTime(this.d.date); + this._buildHTML(); + + if (navigator.userAgent.match(/trident/gi)) { + input = 'change'; + } + + this.d.$el.on('selectDate', this._onSelectDate.bind(this)); + this.$ranges.on(input, this._onChangeRange.bind(this)); + this.$ranges.on('mouseup', this._onMouseUpRange.bind(this)); + this.$ranges.on('mousemove focus ', this._onMouseEnterRange.bind(this)); + this.$ranges.on('mouseout blur', this._onMouseOutRange.bind(this)); + }, + + _setTime: function (date) { + var _date = dp.getParsedDate(date); + + this._handleDate(date); + this.hours = _date.hours < this.minHours ? this.minHours : _date.hours; + this.minutes = _date.minutes < this.minMinutes ? this.minMinutes : _date.minutes; + this.seconds = _date.seconds < this.minSeconds ? this.minSeconds : _date.seconds; + }, + + /** + * Sets minHours and minMinutes from date (usually it's a minDate) + * Also changes minMinutes if current hours are bigger then @date hours + * @param date {Date} + * @private + */ + _setMinTimeFromDate: function (date) { + this.minHours = date.getHours(); + this.minMinutes = date.getMinutes(); + this.minSeconds = date.getSeconds(); + + // If, for example, min hours are 10, and current hours are 12, + // update minMinutes to default value, to be able to choose whole range of values + if (this.d.lastSelectedDate) { + if (this.d.lastSelectedDate.getHours() > date.getHours()) { + this.minMinutes = this.opts.minMinutes; + } + } + }, + + _setMaxTimeFromDate: function (date) { + this.maxHours = date.getHours(); + this.maxMinutes = date.getMinutes(); + this.maxSeconds = date.getSeconds(); + + if (this.d.lastSelectedDate) { + if (this.d.lastSelectedDate.getHours() < date.getHours()) { + this.maxMinutes = this.opts.maxMinutes; + } + } + }, + + _setDefaultMinMaxTime: function () { + var maxHours = 23, + maxMinutes = 59, + maxSeconds = 59, + opts = this.opts; + + this.minHours = opts.minHours < 0 || opts.minHours > maxHours ? 0 : opts.minHours; + this.minMinutes = opts.minMinutes < 0 || opts.minMinutes > maxMinutes ? 0 : opts.minMinutes; + this.maxHours = opts.maxHours < 0 || opts.maxHours > maxHours ? maxHours : opts.maxHours; + this.maxMinutes = opts.maxMinutes < 0 || opts.maxMinutes > maxMinutes ? maxMinutes : opts.maxMinutes; + this.minSeconds = opts.minSeconds < 0 || opts.minSeconds > maxSeconds ? 0 : opts.minSeconds; + this.maxSeconds = opts.maxSeconds < 0 || opts.maxSeconds > maxSeconds ? maxSeconds : opts.maxSeconds; + }, + + /** + * Looks for min/max hours/minutes and if current values + * are out of range sets valid values. + * @private + */ + _validateHoursMinutes: function (date) { + if (this.hours < this.minHours) { + this.hours = this.minHours; + } else if (this.hours > this.maxHours) { + this.hours = this.maxHours; + } + + if (this.minutes < this.minMinutes) { + this.minutes = this.minMinutes; + } else if (this.minutes > this.maxMinutes) { + this.minutes = this.maxMinutes; + } + + if (this.seconds < this.minSeconds) { + this.seconds = this.minSeconds; + } else if (this.seconds > this.maxSeconds) { + this.seconds = this.maxSeconds; + } + }, + + _buildHTML: function () { + var lz = dp.getLeadingZeroNum, + data = { + hourMin: this.minHours, + hourMax: lz(this.maxHours), + hourStep: this.opts.hoursStep, + hourValue: this.hours, + hourVisible: lz(this.displayHours), + minMin: this.minMinutes, + minMax: lz(this.maxMinutes), + minStep: this.opts.minutesStep, + minValue: lz(this.minutes), + secMin: this.minSeconds, + secMax: lz(this.maxSeconds), + secStep: this.opts.secondsStep, + secValue: lz(this.seconds) + }, + _template = dp.template(template, data); + + this.$timepicker = $(_template).appendTo(this.d.$datepicker); + this.$ranges = $('[type="range"]', this.$timepicker); + this.$hours = $('[name="hours"]', this.$timepicker); + this.$minutes = $('[name="minutes"]', this.$timepicker); + this.$seconds = $('[name="seconds"]', this.$timepicker); + this.$hoursText = $('.datepicker--time-current-hours', this.$timepicker); + this.$minutesText = $('.datepicker--time-current-minutes', this.$timepicker); + this.$secondsText = $('.datepicker--time-current-seconds', this.$timepicker); + + if (this.d.ampm) { + this.$ampm = $('') + .appendTo($('.datepicker--time-current', this.$timepicker)) + .html(this.dayPeriod); + + this.$timepicker.addClass('-am-pm-'); + } + }, + + _updateCurrentTime: function () { + var h = dp.getLeadingZeroNum(this.displayHours), + m = dp.getLeadingZeroNum(this.minutes), + s = dp.getLeadingZeroNum(this.seconds); + + this.$hoursText.html(h); + this.$minutesText.html(m); + this.$secondsText.html(s); + + if (this.d.ampm) { + this.$ampm.html(this.dayPeriod); + } + }, + + _updateRanges: function () { + this.$hours.attr({ + min: this.minHours, + max: this.maxHours + }).val(this.hours); + + this.$minutes.attr({ + min: this.minMinutes, + max: this.maxMinutes + }).val(this.minutes); + + this.$seconds.attr({ + min: this.minSeconds, + max: this.maxSeconds + }).val(this.seconds); + }, + + /** + * Sets minHours, minMinutes etc. from date. If date is not passed, than sets + * values from options + * @param [date] {object} - Date object, to get values from + * @private + */ + _handleDate: function (date) { + this._setDefaultMinMaxTime(); + if (date) { + if (dp.isSame(date, this.d.opts.minDate)) { + this._setMinTimeFromDate(this.d.opts.minDate); + } else if (dp.isSame(date, this.d.opts.maxDate)) { + this._setMaxTimeFromDate(this.d.opts.maxDate); + } + } + + this._validateHoursMinutes(date); + }, + + update: function () { + this._updateRanges(); + this._updateCurrentTime(); + }, + + /** + * Calculates valid hour value to display in text input and datepicker's body. + * @param date {Date|Number} - date or hours + * @param [ampm] {Boolean} - 12 hours mode + * @returns {{hours: *, dayPeriod: string}} + * @private + */ + _getValidHoursFromDate: function (date, ampm) { + var d = date, + hours = date; + + if (date instanceof Date) { + d = dp.getParsedDate(date); + hours = d.hours; + } + + var _ampm = ampm || this.d.ampm, + dayPeriod = 'am'; + + if (_ampm) { + switch(true) { + case hours == 0: + hours = 12; + break; + case hours == 12: + dayPeriod = 'pm'; + break; + case hours > 11: + hours = hours - 12; + dayPeriod = 'pm'; + break; + default: + break; + } + } + + return { + hours: hours, + dayPeriod: dayPeriod + } + }, + + set hours (val) { + this._hours = val; + + var displayHours = this._getValidHoursFromDate(val); + + this.displayHours = displayHours.hours; + this.dayPeriod = displayHours.dayPeriod; + }, + + get hours() { + return this._hours; + }, + + // Events + // ------------------------------------------------- + + _onChangeRange: function (e) { + var $target = $(e.target), + name = $target.attr('name'); + + this.d.timepickerIsActive = true; + + this[name] = $target.val(); + this._updateCurrentTime(); + this.d._trigger('timeChange', [this.hours, this.minutes, this.seconds]); + + this._handleDate(this.d.lastSelectedDate); + this.update() + }, + + _onSelectDate: function (e, data) { + this._handleDate(data); + this.update(); + }, + + _onMouseEnterRange: function (e) { + var name = $(e.target).attr('name'); + $('.datepicker--time-current-' + name, this.$timepicker).addClass('-focus-'); + }, + + _onMouseOutRange: function (e) { + var name = $(e.target).attr('name'); + if (this.d.inFocus) return; // Prevent removing focus when mouse out of range slider + $('.datepicker--time-current-' + name, this.$timepicker).removeClass('-focus-'); + }, + + _onMouseUpRange: function (e) { + this.d.timepickerIsActive = false; + } + }; +})(); diff --git a/src/sass/_datepicker-config.scss b/src/sass/_datepicker-config.scss new file mode 100644 index 0000000..eb7ea62 --- /dev/null +++ b/src/sass/_datepicker-config.scss @@ -0,0 +1,84 @@ +$datepickerDayCellSize: 32px !default; +$datepickerWidth: 250px !default; +$datepickerMinBodyHeight: 170px !default; +$datepickerBorderRadius: 4px !default; +$datepickerPadding: 4px !default; +$datepickerZIndex: 100 !default; + +$datepickerFontFamily: Tahoma !default; +$datepickerFontSize: 14px !default; + +$datepickerYearsPerRow: 4 !default; + +$datepickerTextColor: ( + button: #5cc4ef, + otherMonth: #dedede, + otherMonthInRange: #ccc, + disabled: #aeaeae, + currentDate: #4EB5E6, + common: #4a4a4a, + dayNames: #FF9A19, + navArrows: #9c9c9c +) !default; + +$datepickerBG: ( + selected: #5cc4ef, + selectedHover: darken(#5cc4ef, 5), + inRange: rgba(#5cc4ef, .1), + hover: #f0f0f0 +) !default; + +$datepickerBorderColor: ( + nav: #efefef, + inline: #d7d7d7, + default: #dbdbdb +) !default; + +$datepickerNavigationHeight: 32px !default; +$datepickerNavigationButtonsOffset: 2px !default; + +$datepickerPointerSize: 10px !default; +$datepickerPointerOffset: 10px !default; + +// Transitions +$datepickerTransitionSpeed: .3s !default; +$datepickerTransitionEase: ease !default; +$datepickerTransitionOffset: 8px !default; + +// Objects +%otherMonth { + color: map_get($datepickerTextColor, otherMonth); + + &:hover { + color: darken(map_get($datepickerTextColor, otherMonth), 10); + } + + &.-disabled- { + &.-focus- { + color: map_get($datepickerTextColor, otherMonth); + } + } + + &.-selected- { + color: #fff; + background: lighten(map_get($datepickerBG, selected), 15); + &.-focus- { + background: lighten(map_get($datepickerBG, selected), 10); + } + } + + &.-in-range- { + background-color: map_get($datepickerBG, inRange); + color: darken(map_get($datepickerTextColor, otherMonth), 7); + + &.-focus- { + background-color: rgba(map_get($datepickerBG, inRange), .2); + } + } + + + &:empty { + background: none; + border: none; + } +} \ No newline at end of file diff --git a/src/sass/cell.scss b/src/sass/cell.scss new file mode 100644 index 0000000..9d9757d --- /dev/null +++ b/src/sass/cell.scss @@ -0,0 +1,173 @@ +@import "datepicker-config"; + +/* ------------------------------------------------- + Datepicker cells + ------------------------------------------------- */ + +.datepicker--cells { + display: flex; + flex-wrap: wrap; +} + +.datepicker--cell { + border-radius: $datepickerBorderRadius; + box-sizing: border-box; + cursor: pointer; + display: flex; + position: relative; + align-items: center; + justify-content: center; + height: $datepickerDayCellSize; + z-index: 1; + + &.-focus- { + background: map_get($datepickerBG, hover); + } + + &.-current- { + color: map_get($datepickerTextColor, currentDate); + + &.-focus- { + color: map_get($datepickerTextColor, common); + } + + &.-in-range- { + color: map_get($datepickerTextColor, currentDate); + } + } + + &.-in-range- { + background: map_get($datepickerBG, inRange); + color: map_get($datepickerTextColor, common); + border-radius: 0; + + &.-focus- { + background-color: rgba(map_get($datepickerBG, inRange), .2); + } + } + + &.-disabled- { + cursor: default; + color: map_get($datepickerTextColor, disabled); + + &.-focus- { + color: map_get($datepickerTextColor, disabled); + } + + &.-in-range- { + color: darken(map_get($datepickerTextColor, disabled), 5); + } + + &.-current- { + &.-focus- { + color: map_get($datepickerTextColor, disabled); + } + } + } + + &.-range-from- { + border: 1px solid rgba(map_get($datepickerBG, selected), .5); + background-color: map_get($datepickerBG, inRange); + border-radius: $datepickerBorderRadius 0 0 $datepickerBorderRadius; + } + &.-range-to- { + border: 1px solid rgba(map_get($datepickerBG, selected), .5); + background-color: map_get($datepickerBG, inRange); + border-radius: 0 $datepickerBorderRadius $datepickerBorderRadius 0; + } + + &.-range-from-.-range-to- { + border-radius: $datepickerBorderRadius; + + } + + &.-selected- { + color: #fff; + border: none; + background: map_get($datepickerBG, selected); + + &.-current- { + color: #fff; + background: map_get($datepickerBG, selected); + } + + &.-focus- { + background: map_get($datepickerBG, selectedHover); + } + } + + &:empty { + cursor: default; + } +} + +// Day names +// ------------------------------------------------- + +.datepicker--days-names { + display: flex; + flex-wrap: wrap; + margin: 8px 0 3px; +} + +.datepicker--day-name { + color: map_get($datepickerTextColor, dayNames); + display: flex; + align-items: center; + justify-content: center; + flex: 1; + text-align: center; + text-transform: uppercase; + font-size: .8em; +} + +// Day cell +// ------------------------------------------------- + +.datepicker--cell-day { + width: (100/7)#{'%'}; + + &.-other-month- { + @extend %otherMonth; + } +} + + +// Months +// ------------------------------------------------- + +.datepicker--months {} + +.datepicker--cells-months { + height: $datepickerMinBodyHeight; +} + +// Month cell +// ------------------------- + +.datepicker--cell-month { + width: 33.33%; + height: 25%; +} + +// Years +// ------------------------------------------------- + +.datepicker--years { + height: $datepickerMinBodyHeight; +} + +.datepicker--cells-years { + height: $datepickerMinBodyHeight; +} +// Year cell +// ------------------------- + +.datepicker--cell-year { + width: 100% / $datepickerYearsPerRow; + height: 33.33%; + + &.-other-decade- { + @extend %otherMonth; + } +} \ No newline at end of file diff --git a/src/sass/datepicker.scss b/src/sass/datepicker.scss new file mode 100644 index 0000000..e92ec2b --- /dev/null +++ b/src/sass/datepicker.scss @@ -0,0 +1,149 @@ +@import "datepicker-config"; + +/* ------------------------------------------------- + Datepicker + ------------------------------------------------- */ + +.datepickers-container { + position: absolute; + left: 0; + top: 0; + + @media print { + display: none; + } +} + +.datepicker { + background: #fff; + border: 1px solid map_get($datepickerBorderColor, default); + box-shadow: 0 4px 12px rgba(0, 0, 0, .15); + border-radius: $datepickerBorderRadius; + box-sizing: content-box; + font-family: $datepickerFontFamily, sans-serif; + font-size: $datepickerFontSize; + color: map_get($datepickerTextColor, common); + width: $datepickerWidth; + position: absolute; + left: -100000px; + opacity: 0; + transition: opacity $datepickerTransitionSpeed $datepickerTransitionEase, transform $datepickerTransitionSpeed $datepickerTransitionEase, left 0s $datepickerTransitionSpeed; + z-index: $datepickerZIndex; + + &.-from-top- { + transform: translateY(-$datepickerTransitionOffset); + } + &.-from-right- { + transform: translateX($datepickerTransitionOffset); + } + &.-from-bottom- { + transform: translateY($datepickerTransitionOffset); + } + &.-from-left- { + transform: translateX(-$datepickerTransitionOffset); + } + + + &.active { + opacity: 1; + transform: translate(0); + transition: opacity $datepickerTransitionSpeed $datepickerTransitionEase, transform $datepickerTransitionSpeed $datepickerTransitionEase, left 0s 0s; + } +} + +.datepicker-inline { + .datepicker { + border-color: map-get($datepickerBorderColor, inline); + box-shadow: none; + position: static; + left: auto; + right: auto; + opacity: 1; + transform: none; + } + + .datepicker--pointer { + display: none; + } +} + +.datepicker--content { + box-sizing: content-box; + padding: $datepickerPadding; + + .-only-timepicker- & { + display: none; + } +} + +// Pointer +// ------------------------------------------------- +$pointerHalfSize: $datepickerPointerSize / 2 - 1; + +.datepicker--pointer { + position: absolute; + background: #fff; + border-top: 1px solid map-get($datepickerBorderColor, default); + border-right: 1px solid map-get($datepickerBorderColor, default); + width: $datepickerPointerSize; + height: $datepickerPointerSize; + z-index: -1; + + // Main axis + // ------------------------- + + .-top-left- &, .-top-center- &, .-top-right- & { + top: calc(100% - #{$pointerHalfSize}); + transform: rotate(135deg); + } + + .-right-top- &, .-right-center- &, .-right-bottom- & { + right: calc(100% - #{$pointerHalfSize}); + transform: rotate(225deg); + } + + .-bottom-left- &, .-bottom-center- &, .-bottom-right- & { + bottom: calc(100% - #{$pointerHalfSize}); + transform: rotate(315deg); + } + + .-left-top- &, .-left-center- &, .-left-bottom- & { + left: calc(100% - #{$pointerHalfSize}); + transform: rotate(45deg); + } + + // Secondary axis + // ------------------------- + + .-top-left- &, .-bottom-left- & { + left: $datepickerPointerOffset; + } + .-top-right- &, .-bottom-right- & { + right: $datepickerPointerOffset; + } + .-top-center- &, .-bottom-center- & { + left: calc(50% - #{$datepickerPointerSize} / 2); + } + + .-left-top- &, .-right-top- & { + top: $datepickerPointerOffset; + } + .-left-bottom- &, .-right-bottom- & { + bottom: $datepickerPointerOffset; + } + .-left-center- &, .-right-center- & { + top: calc(50% - #{$datepickerPointerSize} / 2); + } + +} + +// Body +// ------------------------------------------------- + +.datepicker--body { + display: none; + + &.active { + display: block; + } +} \ No newline at end of file diff --git a/src/sass/navigation.scss b/src/sass/navigation.scss new file mode 100644 index 0000000..901dbe8 --- /dev/null +++ b/src/sass/navigation.scss @@ -0,0 +1,95 @@ +@import "datepicker-config"; + +/* ------------------------------------------------- + Navigation + ------------------------------------------------- */ + +.datepicker--nav { + display: flex; + justify-content: space-between; + border-bottom: 1px solid map_get($datepickerBorderColor, nav); + min-height: $datepickerNavigationHeight; + padding: $datepickerPadding; + + .-only-timepicker- & { + display: none; + } +} + +.datepicker--nav-title, +.datepicker--nav-action { + display: flex; + cursor: pointer; + align-items: center; + justify-content: center; +} + +.datepicker--nav-action { + width: $datepickerDayCellSize; + border-radius: $datepickerBorderRadius; + user-select: none; + + &:hover { + background: map_get($datepickerBG, hover); + } + + &.-disabled- { + visibility: hidden; + } + + svg { + width: 32px; + height: 32px; + } + + path { + fill: none; + stroke: map_get($datepickerTextColor, navArrows); + stroke-width: 2px; + } +} + +.datepicker--nav-title { + border-radius: $datepickerBorderRadius; + padding: 0 8px; + + i { + font-style: normal; + color: map_get($datepickerTextColor, navArrows); + margin-left: 5px; + } + + &:hover { + background: map_get($datepickerBG, hover); + } + + &.-disabled- { + cursor: default; + background: none; + } +} + +// Buttons +// ------------------------------------------------- + +.datepicker--buttons { + display: flex; + padding: $datepickerPadding; + border-top: 1px solid map_get($datepickerBorderColor, nav); +} + +.datepicker--button { + color: map_get($datepickerTextColor, currentDate); + cursor: pointer; + border-radius: $datepickerBorderRadius; + flex: 1; + display: inline-flex; + justify-content: center; + align-items: center; + height: 32px; + + &:hover { + color: map_get($datepickerTextColor, common); + background: map_get($datepickerBG, hover); + } +} \ No newline at end of file diff --git a/src/sass/timepicker.scss b/src/sass/timepicker.scss new file mode 100644 index 0000000..8fad1c0 --- /dev/null +++ b/src/sass/timepicker.scss @@ -0,0 +1,252 @@ +@import "datepicker-config"; + +/* ------------------------------------------------- + Timepicker + ------------------------------------------------- */ + +$rangeTrackHeight: 1px; +$rangeTrackBg: #dedede; +$rangeThumbSize: 12px; +$rangeThumbBg: #dedede; + +@mixin trackSelector { + &::-webkit-slider-runnable-track { + @content; + } + + &::-moz-range-track { + @content; + } + + &::-ms-track { + @content; + } +} + +@mixin thumbSelector { + &::-webkit-slider-thumb { + @content; + } + + &::-moz-range-thumb { + @content; + } + + &::-ms-thumb { + @content; + } +} + +@mixin thumb { + box-sizing: border-box; + height: $rangeThumbSize; + width: $rangeThumbSize; + border-radius: 3px; + border: 1px solid $rangeTrackBg; + background: #fff; + cursor: pointer; + + transition: background .2s; +} + +@mixin track { + border: none; + height: $rangeTrackHeight; + cursor: pointer; + color: transparent; + background: transparent; +} + +.datepicker--time { + border-top: 1px solid map_get($datepickerBorderColor, nav); + display: flex; + align-items: center; + + padding: $datepickerPadding; + position: relative; + + &.-am-pm- { + .datepicker--time-sliders { + flex: 0 1 138px; + max-width: 138px; + } + } + + .-only-timepicker- & { + border-top: none; + } +} + +.datepicker--time-sliders { + flex: 0 1 153px; + margin-right: 10px; + max-width: 153px; +} + +.datepicker--time-label { + display: none; + font-size: 12px; +} + +.datepicker--time-current { + display: flex; + align-items: center; + flex: 1; + font-size: 14px; + text-align: center; + margin: 0 10px; +} + +.datepicker--time-current-colon { + margin: 0 2px 3px; + line-height: 1; +} + +.datepicker--time-current-hours, +.datepicker--time-current-minutes, +.datepicker--time-current-seconds { + line-height: 1; + font-size: 14px; + font-family: "Century Gothic", CenturyGothic, AppleGothic, sans-serif; + position: relative; + z-index: 1; + + &:after { + content: ''; + background: map_get($datepickerBG, hover); + border-radius: $datepickerBorderRadius; + position: absolute; + left: -2px; + top: -3px; + right: -2px; + bottom: -2px; + z-index: -1; + opacity: 0; + } + + &.-focus- { + &:after { + opacity: 1; + } + } +} + +.datepicker--time-current-ampm { + text-transform: uppercase; + align-self: flex-start; + color: map_get($datepickerTextColor, navArrows); + margin-left: 6px; + font-size: 11px; + margin-bottom: 1px; +} + +.datepicker--time-row { + display: flex; + align-items: center; + font-size: 11px; + height: 17px; + background: linear-gradient(to right,$rangeTrackBg, $rangeTrackBg) left 50%/100% $rangeTrackHeight no-repeat; + + &:first-child { + margin-bottom: 4px; + } + + input[type='range'] { + background: none; + cursor: pointer; + flex: 1; + height: 100%; + padding: 0; + margin: 0; + -webkit-appearance: none; + + &::-webkit-slider-thumb { + -webkit-appearance: none; + } + + &::-ms-tooltip { + display: none; + } + + &:hover { + @include thumbSelector() { + border-color: darken($rangeTrackBg, 15); + } + } + + &:focus { + outline: none; + + @include thumbSelector() { + background: map_get($datepickerBG, selected); + border-color: map_get($datepickerBG, selected); + } + } + + // Thumb + // ------------------------------------------------- + + @include thumbSelector() { + @include thumb; + } + + &::-webkit-slider-thumb { + margin-top: -$rangeThumbSize/2; + } + + // Track + // ------------------------------------------------- + @include trackSelector() { + @include track; + } + + &::-ms-fill-lower { + background: transparent; + } + &:focus::-ms-fill-lower { + + } + &::-ms-fill-upper { + background: transparent; + } + &:focus::-ms-fill-upper { + + } + } + span { + padding: 0 12px; + } +} + +.datepicker--time-icon { + color: map_get($datepickerTextColor, navArrows); + border: 1px solid; + border-radius: 50%; + font-size: 16px; + position: relative; + margin: 0 5px -1px 0; + width: 1em; + height: 1em; + + &:after, &:before { + content: ''; + background: currentColor; + position: absolute; + } + + &:after { + height: .4em; + width: 1px; + left: calc(50% - 1px); + top: calc(50% + 1px); + transform: translateY(-100%); + } + + &:before { + width: .4em; + height: 1px; + top: calc(50% + 1px); + left: calc(50% - 1px); + } +} + diff --git a/tasks/css.js b/tasks/css.js new file mode 100644 index 0000000..1a8a44b --- /dev/null +++ b/tasks/css.js @@ -0,0 +1,24 @@ +var gulp = require('gulp'), + rename = require('gulp-rename'), + sass = require('gulp-sass'), + postcss = require('gulp-postcss'), + autoprefixer = require('autoprefixer')({ browsers: ['last 2 versions'] }), + clone = require('gulp-clone'), + minify = require('gulp-minify-css'), + concat = require('gulp-concat'); + +module.exports = function () { + var stream = gulp.src('src/sass/*.scss') + .pipe(concat('datepicker.scss')) + .pipe(sass().on('error', sass.logError)) + .pipe(postcss([autoprefixer])); + + stream.pipe(clone()) + .pipe(minify()) + .pipe(rename('datepicker.min.css')) + .pipe(gulp.dest('dist/css')); + + stream.pipe(clone()) + .pipe(rename('datepicker.css')) + .pipe(gulp.dest('dist/css')) +}; \ No newline at end of file diff --git a/tasks/cssPage.js b/tasks/cssPage.js new file mode 100644 index 0000000..0b28b83 --- /dev/null +++ b/tasks/cssPage.js @@ -0,0 +1,17 @@ +var gulp = require('gulp'), + rename = require('gulp-rename'), + sass = require('gulp-sass'), + postcss = require('gulp-postcss'), + autoprefixer = require('autoprefixer')({ browsers: ['last 2 versions'] }), + clone = require('gulp-clone'), + minify = require('gulp-minify-css'), + concat = require('gulp-concat'); + +module.exports = function () { + gulp.src('docs/sass/init.scss') + .pipe(concat('style.css')) + .pipe(sass().on('error', sass.logError)) + .pipe(postcss([autoprefixer])) + .pipe(minify()) + .pipe(gulp.dest('docs/css')) +}; \ No newline at end of file diff --git a/tasks/gzip.js b/tasks/gzip.js new file mode 100644 index 0000000..de83006 --- /dev/null +++ b/tasks/gzip.js @@ -0,0 +1,9 @@ +var gulp = require('gulp'), + gzip = require('gulp-gzip'); + +module.exports = function (cb) { + gulp.src('dist/js/datepicker.min.js') + .pipe(gzip()) + .pipe(gulp.dest('dist/')) +}; + diff --git a/tasks/i18n.js b/tasks/i18n.js new file mode 100644 index 0000000..c928baf --- /dev/null +++ b/tasks/i18n.js @@ -0,0 +1,12 @@ +var gulp = require('gulp'), + rename = require('gulp-rename'), + wrap = require('gulp-wrap'), + sass = require('gulp-sass'), + clone = require('gulp-clone'), + concat = require('gulp-concat'); + +module.exports = function () { + gulp.src('src/js/i18n/*.js') + .pipe(wrap(';(function ($) { <%=contents%> })(jQuery);')) + .pipe(gulp.dest('dist/js/i18n')) +}; diff --git a/tasks/jade.js b/tasks/jade.js new file mode 100644 index 0000000..baf8836 --- /dev/null +++ b/tasks/jade.js @@ -0,0 +1,38 @@ +var gulp = require('gulp'), + plumber = require('gulp-plumber'), + _jade = require('jade'), + jade = require('gulp-jade'); + +_jade.filters.code = function( block ) { + return block + .replace( /\…/g, '…' ) + .replace( /&/g, '&' ) + .replace( //g, '>' ) + .replace( /"/g, '"' ) + .replace( /#/g, '#' ) + .replace( /\\/g, '\\\\' ); +}; + +module.exports = { + ru: function () { + gulp.src('docs/jade/pages/index-ru.jade') + .pipe(plumber()) + .pipe(jade({ + data: { + lang: 'ru' + } + })) + .pipe(gulp.dest('docs/')) + }, + en: function () { + gulp.src('docs/jade/pages/index.jade') + .pipe(plumber()) + .pipe(jade({ + data: { + lang: 'en' + } + })) + .pipe(gulp.dest('docs/')) + } +}; \ No newline at end of file diff --git a/tasks/js.js b/tasks/js.js new file mode 100644 index 0000000..4cf5f30 --- /dev/null +++ b/tasks/js.js @@ -0,0 +1,26 @@ +var gulp = require('gulp'), + rename = require('gulp-rename'), + uglify = require('gulp-uglify'), + clone = require('gulp-clone'), + wrap = require('gulp-wrap'), + concat = require('gulp-concat'); + +module.exports = function () { + var stream = gulp.src([ + 'src/js/datepicker.js', + 'src/js/body.js', + 'src/js/navigation.js', + 'src/js/timepicker.js' + ]) + .pipe(concat('datepicker.js')) + .pipe(wrap(';(function (window, $, undefined) { <%=contents%> })(window, jQuery);')); + + stream.pipe(clone()) + .pipe(gulp.dest('dist/js')); + + stream.pipe(clone()) + .pipe(uglify()) + .pipe(rename('datepicker.min.js')) + .pipe(gulp.dest('dist/js')) + +}; \ No newline at end of file