diff --git a/.npmignore b/.npmignore new file mode 100644 index 00000000..bdeb6982 --- /dev/null +++ b/.npmignore @@ -0,0 +1,7 @@ +.idea +tests +docs +bower_components +bower.json +static-server.js +visual-tests.html \ No newline at end of file diff --git a/README.md b/README.md index 724ec9a3..7ea08fbd 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,19 @@ # Air Datepicker -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+) +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+). + ![air datepicker image](https://github.com/t1m0n/air-datepicker/raw/master/docs/img/promo-img.png) ## Install + +### bower ``` bower i --save air-datepicker ``` +### npm +``` +npm i --save air-datepicker +``` ## Usage ```javascript @@ -19,6 +26,21 @@ $('.my-datepicker').datepicker([options]) ## Change log +### 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. diff --git a/bower.json b/bower.json index f22a3deb..0d12a239 100644 --- a/bower.json +++ b/bower.json @@ -1,18 +1,20 @@ { "name": "air-datepicker", - "version": "1.2.4", + "version": "2.0.0", "authors": [ "t1m0n " ], - "description": "A lightweight jQuery datepicker", + "description": "A lightweight, customizable, powerful jQuery datepicker", "main": [ - "dist/js/datepicker.js", - "dist/css/datepicker.css" + "dist/js/datepicker.min.js", + "dist/css/datepicker.min.css" ], "keywords": [ "datepicker", - "calendar", - "lightweight" + "timepicker", + "plugin", + "customizable", + "powerful" ], "license": "MIT", "ignore": [ @@ -28,6 +30,6 @@ "tests" ], "dependencies": { - "jquery": "~2.1.4" + "jquery": "^2.2.3" } } \ No newline at end of file diff --git a/dist/css/datepicker.css b/dist/css/datepicker.css index c8642559..7891a8c9 100644 --- a/dist/css/datepicker.css +++ b/dist/css/datepicker.css @@ -18,26 +18,6 @@ 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 ------------------------------------------------- */ @@ -184,6 +164,9 @@ position: absolute; left: 0; top: 0; } + @media print { + .datepickers-container { + display: none; } } .datepicker { background: #fff; @@ -387,3 +370,247 @@ .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: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: center; + -ms-flex-align: center; + align-items: center; + padding: 4px; + position: relative; } + .datepicker--time.-am-pm- .datepicker--time-sliders { + -webkit-flex: 0 1 138px; + -ms-flex: 0 1 138px; + flex: 0 1 138px; + max-width: 138px; } + +.datepicker--time-sliders { + -webkit-flex: 0 1 153px; + -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: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: center; + -ms-flex-align: center; + align-items: center; + -webkit-flex: 1; + -ms-flex: 1; + flex: 1; + font-size: 14px; + text-align: center; + margin: 0 0 0 10px; } + +.datepicker--time-current-colon { + margin: 0 2px 3px; + line-height: 1; } + +.datepicker--time-current-hours, +.datepicker--time-current-minutes { + line-height: 1; + font-size: 19px; + font-family: "Century Gothic", CenturyGothic, AppleGothic, sans-serif; + position: relative; + z-index: 1; } + .datepicker--time-current-hours:after, + .datepicker--time-current-minutes: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 { + opacity: 1; } + +.datepicker--time-current-ampm { + text-transform: uppercase; + -webkit-align-self: flex-end; + -ms-flex-item-align: end; + align-self: flex-end; + color: #9c9c9c; + margin-left: 6px; + font-size: 11px; + margin-bottom: 1px; } + +.datepicker--time-row { + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: center; + -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; + -webkit-flex: 1; + -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); + -webkit-transform: translateY(-100%); + transform: translateY(-100%); } + .datepicker--time-icon:before { + width: .4em; + height: 1px; + top: calc(50% + 1px); + left: calc(50% - 1px); } + +.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; } diff --git a/dist/css/datepicker.min.css b/dist/css/datepicker.min.css index b8f725a8..32c3007b 100644 --- a/dist/css/datepicker.min.css +++ b/dist/css/datepicker.min.css @@ -1 +1 @@ -.datepicker--cells{display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap}.datepicker--cell{border-radius:4px;box-sizing:border-box;cursor:pointer;display:-webkit-flex;display:-ms-flexbox;display:flex;position:relative;-webkit-align-items:center;-ms-flex-align:center;align-items:center;-webkit-justify-content: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:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;margin:8px 0 3px}.datepicker--day-name{color:#FF9A19;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-ms-flex-align:center;align-items:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;-webkit-flex:1;-ms-flex:1;flex:1;text-align:center;text-transform:uppercase;font-size:.8em}.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}.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,left 0s .3s,-webkit-transform .3s ease;transition:opacity .3s ease,transform .3s ease,left 0s .3s;transition:opacity .3s ease,transform .3s ease,left 0s .3s,-webkit-transform .3s ease;z-index:100}.datepicker.-from-top-{-webkit-transform:translateY(-8px);transform:translateY(-8px)}.datepicker.-from-right-{-webkit-transform:translateX(8px);transform:translateX(8px)}.datepicker.-from-bottom-{-webkit-transform:translateY(8px);transform:translateY(8px)}.datepicker.-from-left-{-webkit-transform:translateX(-8px);transform:translateX(-8px)}.datepicker.active{opacity:1;-webkit-transform:translate(0);transform:translate(0);transition:opacity .3s ease,left 0s 0s,-webkit-transform .3s ease;transition:opacity .3s ease,transform .3s ease,left 0s 0s;transition:opacity .3s ease,transform .3s ease,left 0s 0s,-webkit-transform .3s ease}.datepicker-inline .datepicker{border-color:#d7d7d7;box-shadow:none;position:static;left:auto;right:auto;opacity:1;-webkit-transform:none;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}.-top-center- .datepicker--pointer,.-top-left- .datepicker--pointer,.-top-right- .datepicker--pointer{top:calc(100% - 4px);-webkit-transform:rotate(135deg);transform:rotate(135deg)}.-right-bottom- .datepicker--pointer,.-right-center- .datepicker--pointer,.-right-top- .datepicker--pointer{right:calc(100% - 4px);-webkit-transform:rotate(225deg);transform:rotate(225deg)}.-bottom-center- .datepicker--pointer,.-bottom-left- .datepicker--pointer,.-bottom-right- .datepicker--pointer{bottom:calc(100% - 4px);-webkit-transform:rotate(315deg);transform:rotate(315deg)}.-left-bottom- .datepicker--pointer,.-left-center- .datepicker--pointer,.-left-top- .datepicker--pointer{left:calc(100% - 4px);-webkit-transform:rotate(45deg);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--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--nav-action:hover,.datepicker--nav-title:hover{background:#f0f0f0}.datepicker--nav{display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-justify-content:space-between;-ms-flex-pack:justify;justify-content:space-between;border-bottom:1px solid #efefef;min-height:32px;padding:4px}.datepicker--nav-action,.datepicker--nav-title{display:-webkit-flex;display:-ms-flexbox;display:flex;cursor:pointer;-webkit-align-items:center;-ms-flex-align:center;align-items:center;-webkit-justify-content: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:-webkit-flex;display:-ms-flexbox;display:flex;padding:4px;border-top:1px solid #efefef}.datepicker--button{color:#4EB5E6;cursor:pointer;border-radius:4px;-webkit-flex:1;-ms-flex:1;flex:1;display:-webkit-inline-flex;display:-ms-inline-flexbox;display:inline-flex;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;height:32px}.datepicker--button:hover{color:#4a4a4a;background:#f0f0f0} \ No newline at end of file +.datepicker--cells{display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap}.datepicker--cell{border-radius:4px;box-sizing:border-box;cursor:pointer;display:-webkit-flex;display:-ms-flexbox;display:flex;position:relative;-webkit-align-items:center;-ms-flex-align:center;align-items:center;-webkit-justify-content: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:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;margin:8px 0 3px}.datepicker--day-name{color:#FF9A19;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-ms-flex-align:center;align-items:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;-webkit-flex:1;-ms-flex:1;flex:1;text-align:center;text-transform:uppercase;font-size:.8em}.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,left 0s .3s,-webkit-transform .3s ease;transition:opacity .3s ease,transform .3s ease,left 0s .3s;transition:opacity .3s ease,transform .3s ease,left 0s .3s,-webkit-transform .3s ease;z-index:100}.datepicker.-from-top-{-webkit-transform:translateY(-8px);transform:translateY(-8px)}.datepicker.-from-right-{-webkit-transform:translateX(8px);transform:translateX(8px)}.datepicker.-from-bottom-{-webkit-transform:translateY(8px);transform:translateY(8px)}.datepicker.-from-left-{-webkit-transform:translateX(-8px);transform:translateX(-8px)}.datepicker.active{opacity:1;-webkit-transform:translate(0);transform:translate(0);transition:opacity .3s ease,left 0s 0s,-webkit-transform .3s ease;transition:opacity .3s ease,transform .3s ease,left 0s 0s;transition:opacity .3s ease,transform .3s ease,left 0s 0s,-webkit-transform .3s ease}.datepicker-inline .datepicker{border-color:#d7d7d7;box-shadow:none;position:static;left:auto;right:auto;opacity:1;-webkit-transform:none;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);-webkit-transform:rotate(135deg);transform:rotate(135deg)}.-right-bottom- .datepicker--pointer,.-right-center- .datepicker--pointer,.-right-top- .datepicker--pointer{right:calc(100% - 4px);-webkit-transform:rotate(225deg);transform:rotate(225deg)}.-bottom-center- .datepicker--pointer,.-bottom-left- .datepicker--pointer,.-bottom-right- .datepicker--pointer{bottom:calc(100% - 4px);-webkit-transform:rotate(315deg);transform:rotate(315deg)}.-left-bottom- .datepicker--pointer,.-left-center- .datepicker--pointer,.-left-top- .datepicker--pointer{left:calc(100% - 4px);-webkit-transform:rotate(45deg);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:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-justify-content:space-between;-ms-flex-pack:justify;justify-content:space-between;border-bottom:1px solid #efefef;min-height:32px;padding:4px}.datepicker--nav-action,.datepicker--nav-title{display:-webkit-flex;display:-ms-flexbox;display:flex;cursor:pointer;-webkit-align-items:center;-ms-flex-align:center;align-items:center;-webkit-justify-content: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--buttons,.datepicker--time{border-top:1px solid #efefef;padding:4px}.datepicker--nav-title i{font-style:normal;color:#9c9c9c;margin-left:5px}.datepicker--nav-title.-disabled-{cursor:default;background:0 0}.datepicker--buttons{display:-webkit-flex;display:-ms-flexbox;display:flex}.datepicker--button{color:#4EB5E6;cursor:pointer;border-radius:4px;-webkit-flex:1;-ms-flex:1;flex:1;display:-webkit-inline-flex;display:-ms-inline-flexbox;display:inline-flex;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;height:32px}.datepicker--button:hover{color:#4a4a4a;background:#f0f0f0}.datepicker--time{display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-ms-flex-align:center;align-items:center;position:relative}.datepicker--time.-am-pm- .datepicker--time-sliders{-webkit-flex:0 1 138px;-ms-flex:0 1 138px;flex:0 1 138px;max-width:138px}.datepicker--time-sliders{-webkit-flex:0 1 153px;-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:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-ms-flex-align:center;align-items:center;-webkit-flex:1;-ms-flex:1;flex:1;font-size:14px;text-align:center;margin:0 0 0 10px}.datepicker--time-current-colon{margin:0 2px 3px;line-height:1}.datepicker--time-current-hours,.datepicker--time-current-minutes{line-height:1;font-size:19px;font-family:"Century Gothic",CenturyGothic,AppleGothic,sans-serif;position:relative;z-index:1}.datepicker--time-current-hours:after,.datepicker--time-current-minutes: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{opacity:1}.datepicker--time-current-ampm{text-transform:uppercase;-webkit-align-self:flex-end;-ms-flex-item-align:end;align-self:flex-end;color:#9c9c9c;margin-left:6px;font-size:11px;margin-bottom:1px}.datepicker--time-row{display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-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;-webkit-flex:1;-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);-webkit-transform:translateY(-100%);transform:translateY(-100%)}.datepicker--time-icon:before{width:.4em;height:1px;top:calc(50% + 1px);left:calc(50% - 1px)}.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} \ No newline at end of file diff --git a/dist/js/datepicker.js b/dist/js/datepicker.js index 750ce7bd..a817c5fc 100644 --- a/dist/js/datepicker.js +++ b/dist/js/datepicker.js @@ -1,6 +1,4 @@ -;(function (window, $, undefined) { window.Datepicker = ''; - -(function () { +;(function (window, $, undefined) { ;(function () { var pluginName = 'datepicker', autoInitSelector = '.datepicker-here', $body, $datepickersContainer, @@ -62,6 +60,17 @@ years: 'yyyy1 - yyyy2' }, + // timepicker + timepicker: false, + dateTimeSeparator: ' ', + timeFormat: '', + minHours: 0, + maxHours: 24, + minMinutes: 0, + maxMinutes: 59, + hoursStep: 1, + minutesStep: 1, + // events onSelect: '', onChangeMonth: '', @@ -87,7 +96,7 @@ }, datepicker; - Datepicker = function (el, options) { + var Datepicker = function (el, options) { this.el = el; this.$el = $(el); @@ -121,6 +130,7 @@ this.keys = []; this.minRange = ''; this.maxRange = ''; + this._prevOnSelectValue = ''; this.init() }; @@ -155,11 +165,17 @@ this.$datepicker.addClass(this.opts.classes) } - this.views[this.currentView] = new Datepicker.Body(this, this.currentView, this.opts); + if (this.opts.timepicker) { + this.timepicker = new $.fn.datepicker.Timepicker(this, this.opts); + this._bindTimepickerEvents(); + } + + this.views[this.currentView] = new $.fn.datepicker.Body(this, this.currentView, this.opts); this.views[this.currentView].show(); - this.nav = new Datepicker.Navigation(this, this.opts); + 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)); @@ -173,9 +189,11 @@ _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('input.adp', this._onInput.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 () { @@ -184,30 +202,49 @@ 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 = Datepicker.language[lang]; + 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, {}, Datepicker.language.ru) + this.loc = $.extend(true, {}, $.fn.datepicker.language.ru) } - this.loc = $.extend(true, {}, Datepicker.language.ru, Datepicker.language[lang]) + this.loc = $.extend(true, {}, $.fn.datepicker.language.ru, $.fn.datepicker.language[lang]) } else { - this.loc = $.extend(true, {}, Datepicker.language.ru, lang) + 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); + } + + var boundary = this._getWordBoundaryRegExp; + if (this.loc.timeFormat.match(boundary('aa')) || + this.loc.timeFormat.match(boundary('AA')) + ) { + this.ampm = true; + } }, _buildDatepickersContainer: function () { @@ -237,6 +274,9 @@ _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); } @@ -244,7 +284,13 @@ parsedSelected = datepicker.getParsedDate(selectedDates[0]), formattedDates, _this = this, - dates = new Date(parsedSelected.year, parsedSelected.month, parsedSelected.date); + dates = new Date( + parsedSelected.year, + parsedSelected.month, + parsedSelected.date, + parsedSelected.hours, + parsedSelected.minutes + ); formattedDates = selectedDates.map(function (date) { return _this.formatDate(_this.loc.dateFormat, date) @@ -254,10 +300,17 @@ 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) + return new Date( + parsedSelected.year, + parsedSelected.month, + parsedSelected.date, + parsedSelected.hours, + parsedSelected.minutes + ); }) } + this._prevOnSelectValue = formattedDates; this.opts.onSelect(formattedDates, dates, this); }, @@ -304,12 +357,28 @@ var result = string, boundary = this._getWordBoundaryRegExp, locale = this.loc, + leadingZero = datepicker.getLeadingZeroNum, decade = datepicker.getDecade(date), - d = datepicker.getParsedDate(date); + d = datepicker.getParsedDate(date), + fullHours = d.fullHours, + hours = d.hours, + dayPeriod = 'am', + validHours; + + if (this.opts.timepicker && this.timepicker && this.ampm) { + validHours = this.timepicker._getValidHoursFromDate(date); + 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 = result.replace(boundary('aa'), dayPeriod); + case /AA/.test(result): + result = result.replace(boundary('AA'), dayPeriod.toUpperCase()); case /dd/.test(result): result = result.replace(boundary('dd'), d.fullDate); case /d/.test(result): @@ -326,6 +395,14 @@ result = result.replace(boundary('MM'), this.loc.months[d.month]); case /M/.test(result): result = result.replace(boundary('M'), locale.monthsShort[d.month]); + case /ii/.test(result): + result = result.replace(boundary('ii'), d.fullMinutes); + case /i/.test(result): + result = result.replace(boundary('i'), d.minutes); + case /hh/.test(result): + result = result.replace(boundary('hh'), fullHours); + case /h/.test(result): + result = result.replace(boundary('h'), hours); case /yyyy/.test(result): result = result.replace(boundary('yyyy'), d.year); case /yyyy1/.test(result): @@ -351,8 +428,33 @@ 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) + } + if (_this.view == 'days') { if (date.getMonth() != d.month && opts.moveToOtherMonthsOnSelect) { newDate = new Date(date.getFullYear(), date.getMonth(), 1); @@ -389,6 +491,11 @@ } 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 { @@ -405,7 +512,7 @@ _this._triggerOnChange(); } - if (opts.autoClose) { + if (opts.autoClose && !this.timepickerIsActive) { if (!opts.multipleDates && !opts.range) { _this.hide(); } else if (opts.range && _this.selectedDates.length == 2) { @@ -429,6 +536,9 @@ if (!_this.selectedDates.length) { _this.minRange = ''; _this.maxRange = ''; + _this.lastSelectedDate = ''; + } else { + _this.lastSelectedDate = _this.selectedDates[_this.selectedDates.length - 1]; } _this.views[_this.currentView]._render(); @@ -448,6 +558,10 @@ 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 () { @@ -468,6 +582,7 @@ */ update: function (param, value) { var len = arguments.length; + if (len == 2) { this.opts[param] = value; } else if (len == 1 && typeof param == 'object') { @@ -492,6 +607,19 @@ this.$datepicker.addClass(this.opts.classes) } + if (this.opts.timepicker) { + this.timepicker._handleDate(this.lastSelectedDate); + this.timepicker._updateRanges(); + this.timepicker._updateCurrentTime(); + // Change hours and minutes if it's values have been changed through min/max hours/minutes + if (this.lastSelectedDate) { + this.lastSelectedDate.setHours(this.timepicker.hours); + this.lastSelectedDate.setMinutes(this.timepicker.minutes); + } + } + + this._setInputValue(); + return this; }, @@ -509,9 +637,14 @@ }, _isSelected: function (checkDate, cellType) { - return this.selectedDates.some(function (date) { - return datepicker.isSame(date, checkDate, cellType) - }) + var res = false; + this.selectedDates.some(function (date) { + if (datepicker.isSame(date, checkDate, cellType)) { + res = date; + return true; + } + }); + return res; }, _setInputValue: function () { @@ -911,7 +1044,7 @@ } }, - _onShowEvent: function () { + _onShowEvent: function (e) { if (!this.visible) { this.show(); } @@ -929,10 +1062,11 @@ _onMouseUpDatepicker: function (e) { this.inFocus = false; - this.$el.focus() + e.originalEvent.inFocus = true; + if (!e.originalEvent.timepickerFocus) this.$el.focus(); }, - _onInput: function () { + _onKeyUpGeneral: function (e) { var val = this.$el.val(); if (!val) { @@ -946,6 +1080,19 @@ } }, + _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); @@ -966,6 +1113,10 @@ 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.selectDate(this.focused); } else if (alreadySelected && this.opts.toggleSelected){ this.removeDate(this.focused); @@ -1026,6 +1177,37 @@ this.silent = false; }, + _onTimeChange: function (e, h, m) { + var date = new Date(), + selectedDates = this.selectedDates, + selected = false; + + if (selectedDates.length) { + selected = true; + date = this.lastSelectedDate; + } + + date.setHours(h); + date.setMinutes(m); + + 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); + } + this.selectDate(date); + }, + set focused(val) { if (!val && this.focused) { var $cell = this._getCell(this.focused); @@ -1086,7 +1268,7 @@ if (this.inited) { if (!this.views[val]) { - this.views[val] = new Datepicker.Body(this, val, this.opts) + this.views[val] = new $.fn.datepicker.Body(this, val, this.opts) } else { this.views[val]._render(); } @@ -1141,7 +1323,11 @@ 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() + 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() } }; @@ -1184,21 +1370,11 @@ return date.getTime() > dateCompareTo.getTime(); }; - Datepicker.language = { - ru: { - days: ['Воскресенье', 'Понедельник', 'Вторник', 'Среда', 'Четверг', 'Пятница', 'Суббота'], - daysShort: ['Вос','Пон','Вто','Сре','Чет','Пят','Суб'], - daysMin: ['Вс','Пн','Вт','Ср','Чт','Пт','Сб'], - months: ['Январь', 'Февраль', 'Март', 'Апрель', 'Май', 'Июнь', 'Июль', 'Август', 'Сентябрь', 'Октябрь', 'Ноябрь', 'Декабрь'], - monthsShort: ['Янв', 'Фев', 'Мар', 'Апр', 'Май', 'Июн', 'Июл', 'Авг', 'Сен', 'Окт', 'Ноя', 'Дек'], - today: 'Сегодня', - clear: 'Очистить', - dateFormat: 'dd.mm.yyyy', - firstDay: 1 - } + datepicker.getLeadingZeroNum = function (num) { + return parseInt(num) < 10 ? '0' + num : num; }; - $.fn[pluginName] = function ( options ) { + $.fn.datepicker = function ( options ) { return this.each(function () { if (!$.data(this, pluginName)) { $.data(this, pluginName, @@ -1212,11 +1388,29 @@ }); }; + $.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:'' + @@ -1233,9 +1427,10 @@ '
' + '' }, - D = Datepicker; + datepicker = $.fn.datepicker, + dp = datepicker.Constructor; - D.Body = function (d, type, opts) { + datepicker.Body = function (d, type, opts) { this.d = d; this.type = type; this.opts = opts; @@ -1243,7 +1438,7 @@ this.init(); }; - D.Body.prototype = { + datepicker.Body.prototype = { init: function () { this._buildBaseHtml(); this._render(); @@ -1279,7 +1474,7 @@ currentDate = new Date(), parent = this.d, opts = parent.opts, - d = D.getParsedDate(date), + d = dp.getParsedDate(date), render = {}, html = d.date; @@ -1323,34 +1518,34 @@ } if (opts.range) { - if (D.isSame(parent.minRange, date, type)) classes += ' -range-from-'; - if (D.isSame(parent.maxRange, date, type)) classes += ' -range-to-'; + if (dp.isSame(parent.minRange, date, type)) classes += ' -range-from-'; + if (dp.isSame(parent.maxRange, date, type)) classes += ' -range-to-'; if (parent.selectedDates.length == 1 && parent.focused) { if ( - (D.bigger(parent.minRange, date) && D.less(parent.focused, date)) || - (D.less(parent.maxRange, date) && D.bigger(parent.focused, date))) + (dp.bigger(parent.minRange, date) && dp.less(parent.focused, date)) || + (dp.less(parent.maxRange, date) && dp.bigger(parent.focused, date))) { classes += ' -in-range-' } - if (D.less(parent.maxRange, date) && D.isSame(parent.focused, date)) { + if (dp.less(parent.maxRange, date) && dp.isSame(parent.focused, date)) { classes += ' -range-from-' } - if (D.bigger(parent.minRange, date) && D.isSame(parent.focused, date)) { + if (dp.bigger(parent.minRange, date) && dp.isSame(parent.focused, date)) { classes += ' -range-to-' } } else if (parent.selectedDates.length == 2) { - if (D.bigger(parent.minRange, date) && D.less(parent.maxRange, date)) { + if (dp.bigger(parent.minRange, date) && dp.less(parent.maxRange, date)) { classes += ' -in-range-' } } } - if (D.isSame(currentDate, date, type)) classes += ' -current-'; - if (parent.focused && D.isSame(date, parent.focused, type)) classes += ' -focus-'; + 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-'; @@ -1367,7 +1562,7 @@ * @private */ _getDaysHtml: function (date) { - var totalMonthDays = D.getDaysCount(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, @@ -1407,7 +1602,7 @@ */ _getMonthsHtml: function (date) { var html = '', - d = D.getParsedDate(date), + d = dp.getParsedDate(date), i = 0; while(i < 12) { @@ -1425,8 +1620,8 @@ }, _getYearsHtml: function (date) { - var d = D.getParsedDate(date), - decade = D.getDecade(date), + var d = dp.getParsedDate(date), + decade = dp.getDecade(date), firstYear = decade[0] - 1, html = '', i = firstYear; @@ -1509,9 +1704,15 @@ alreadySelected = this.d._isSelected(selectedDate, this.d.cellType); if (!alreadySelected) { - this.d.selectDate(selectedDate); + this.d._trigger('clickCell', selectedDate); } else if (alreadySelected && this.opts.toggleSelected){ this.d.removeDate(selectedDate); + } else if (alreadySelected && !this.opts.toggleSelected) { + this.d.lastSelectedDate = alreadySelected; + if (this.d.opts.timepicker) { + this.d.timepicker._setTime(alreadySelected); + this.d.timepicker.update(); + } } }, @@ -1532,9 +1733,11 @@ '
#{title}
' + '
#{nextHtml}
', buttonsContainerTemplate = '
', - button = '#{label}'; + button = '#{label}', + datepicker = $.fn.datepicker, + dp = datepicker.Constructor; - Datepicker.Navigation = function (d, opts) { + datepicker.Navigation = function (d, opts) { this.d = d; this.opts = opts; @@ -1543,7 +1746,7 @@ this.init(); }; - Datepicker.Navigation.prototype = { + datepicker.Navigation.prototype = { init: function () { this._buildBaseHtml(); this._bindEvents(); @@ -1571,7 +1774,7 @@ _render: function () { var title = this._getTitle(this.d.currentDate), - html = Datepicker.template(template, $.extend({title: title}, this.opts)); + 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-'); @@ -1592,7 +1795,7 @@ action: type, label: this.d.loc[type] }, - html = Datepicker.template(button, data); + html = dp.template(button, data); if ($('[data-action=' + type + ']', this.$buttonsContainer).length) return; this.$buttonsContainer.append(html); @@ -1665,5 +1868,265 @@ } } +})(); + +;(function () { + var template = '
' + + '
' + + ' #{hourValue}' + + ' :' + + ' #{minValue}' + + '
' + + '
' + + '
' + + ' ' + + '
' + + '
' + + ' ' + + '
' + + '
' + + '
', + 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; + }, + + _setMinTimeFromDate: function (date) { + this.minHours = date.getHours(); + this.minMinutes = date.getMinutes(); + }, + + _setMaxTimeFromDate: function (date) { + this.maxHours = date.getHours(); + this.maxMinutes = date.getMinutes(); + }, + + _setDefaultMinMaxTime: function () { + var maxHours = 23, + maxMinutes = 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; + }, + + /** + * 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; + } + }, + + _buildHTML: function () { + var lz = dp.getLeadingZeroNum, + data = { + hourMin: this.minHours, + hourMax: lz(this.maxHours), + hourStep: this.opts.hoursStep, + hourValue: lz(this.displayHours), + minMin: this.minMinutes, + minMax: lz(this.maxMinutes), + minStep: this.opts.minutesStep, + minValue: lz(this.minutes) + }, + _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.$hoursText = $('.datepicker--time-current-hours', this.$timepicker); + this.$minutesText = $('.datepicker--time-current-minutes', 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); + + this.$hoursText.html(h); + this.$minutesText.html(m); + + 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) + }, + + /** + * 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 + * @returns {{hours: *, dayPeriod: string}} + * @private + */ + _getValidHoursFromDate: function (date) { + var d = date, + hours = date; + + if (date instanceof Date) { + d = dp.getParsedDate(date); + hours = d.hours; + } + + var 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]) + }, + + _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 index a96c81c1..5f8146af 100644 --- a/dist/js/datepicker.min.js +++ b/dist/js/datepicker.min.js @@ -1 +1,2 @@ -!function(e,t,s){e.Datepicker="",function(){var i,a,n,h="datepicker",o=".datepicker-here",r=!1,c='
',d={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"},onSelect:"",onChangeMonth:"",onChangeYear:"",onChangeDecade:"",onChangeView:"",onRenderCell:""},l={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=function(e,a){this.el=e,this.$el=t(e),this.opts=t.extend(!0,{},d,a,this.$el.data()),i==s&&(i=t("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?t(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.init()},n=Datepicker,n.prototype={viewIndexes:["days","months","years"],init:function(){r||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._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.views[this.currentView]=new Datepicker.Body(this,this.currentView,this.opts),this.views[this.currentView].show(),this.nav=new Datepicker.Navigation(this,this.opts),this.view=this.currentView,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("blur.adp",this._onBlur.bind(this)),this.$el.on("input.adp",this._onInput.bind(this)),t(e).on("resize.adp",this._onResize.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))},isWeekend:function(e){return-1!==this.opts.weekends.indexOf(e)},_defineLocale:function(e){"string"==typeof e?(this.loc=Datepicker.language[e],this.loc||(console.warn("Can't find language \""+e+'" in Datepicker.language, will use "ru" instead'),this.loc=t.extend(!0,{},Datepicker.language.ru)),this.loc=t.extend(!0,{},Datepicker.language.ru,Datepicker.language[e])):this.loc=t.extend(!0,{},Datepicker.language.ru,e),this.opts.dateFormat&&(this.loc.dateFormat=this.opts.dateFormat),""!==this.opts.firstDay&&(this.loc.firstDay=this.opts.firstDay)},_buildDatepickersContainer:function(){r=!0,i.append('
'),a=t("#datepickers-container")},_buildBaseHtml:function(){var e,s=t('
');e="INPUT"==this.el.nodeName?this.opts.inline?s.insertAfter(this.$el):a:s.appendTo(this.$el),this.$datepicker=t(c).appendTo(e),this.$content=t(".datepicker--content",this.$datepicker),this.$nav=t(".datepicker--nav",this.$datepicker)},_triggerOnChange:function(){if(!this.selectedDates.length)return this.opts.onSelect("","",this);var e,t=this.selectedDates,s=n.getParsedDate(t[0]),i=this,a=new Date(s.year,s.month,s.date);e=t.map(function(e){return i.formatDate(i.loc.dateFormat,e)}).join(this.opts.multipleDatesSeparator),(this.opts.multipleDates||this.opts.range)&&(a=t.map(function(e){var t=n.getParsedDate(e);return new Date(t.year,t.month,t.date)})),this.opts.onSelect(e,a,this)},next:function(){var e=this.parsedDate,t=this.opts;switch(this.view){case"days":this.date=new Date(e.year,e.month+1,1),t.onChangeMonth&&t.onChangeMonth(this.parsedDate.month,this.parsedDate.year);break;case"months":this.date=new Date(e.year+1,e.month,1),t.onChangeYear&&t.onChangeYear(this.parsedDate.year);break;case"years":this.date=new Date(e.year+10,0,1),t.onChangeDecade&&t.onChangeDecade(this.curDecade)}},prev:function(){var e=this.parsedDate,t=this.opts;switch(this.view){case"days":this.date=new Date(e.year,e.month-1,1),t.onChangeMonth&&t.onChangeMonth(this.parsedDate.month,this.parsedDate.year);break;case"months":this.date=new Date(e.year-1,e.month,1),t.onChangeYear&&t.onChangeYear(this.parsedDate.year);break;case"years":this.date=new Date(e.year-10,0,1),t.onChangeDecade&&t.onChangeDecade(this.curDecade)}},formatDate:function(e,t){t=t||this.date;var s=e,i=this._getWordBoundaryRegExp,a=this.loc,h=n.getDecade(t),o=n.getParsedDate(t);switch(!0){case/@/.test(s):s=s.replace(/@/,t.getTime());case/dd/.test(s):s=s.replace(i("dd"),o.fullDate);case/d/.test(s):s=s.replace(i("d"),o.date);case/DD/.test(s):s=s.replace(i("DD"),a.days[o.day]);case/D/.test(s):s=s.replace(i("D"),a.daysShort[o.day]);case/mm/.test(s):s=s.replace(i("mm"),o.fullMonth);case/m/.test(s):s=s.replace(i("m"),o.month+1);case/MM/.test(s):s=s.replace(i("MM"),this.loc.months[o.month]);case/M/.test(s):s=s.replace(i("M"),a.monthsShort[o.month]);case/yyyy/.test(s):s=s.replace(i("yyyy"),o.year);case/yyyy1/.test(s):s=s.replace(i("yyyy1"),h[0]);case/yyyy2/.test(s):s=s.replace(i("yyyy2"),h[1]);case/yy/.test(s):s=s.replace(i("yy"),o.year.toString().slice(-2))}return s},_getWordBoundaryRegExp:function(e){return new RegExp("\\b(?=[a-zA-Z0-9äöüßÄÖÜ<])"+e+"(?![>a-zA-Z0-9äöüßÄÖÜ])")},selectDate:function(e){var t=this,s=t.opts,i=t.parsedDate,a=t.selectedDates,n=a.length,h="";if(e instanceof Date){if("days"==t.view&&e.getMonth()!=i.month&&s.moveToOtherMonthsOnSelect&&(h=new Date(e.getFullYear(),e.getMonth(),1)),"years"==t.view&&e.getFullYear()!=i.year&&s.moveToOtherYearsOnSelect&&(h=new Date(e.getFullYear(),0,1)),h&&(t.silent=!0,t.date=h,t.silent=!1,t.nav._render()),s.multipleDates&&!s.range){if(n===s.multipleDates)return;t._isSelected(e)||t.selectedDates.push(e)}else s.range?2==n?(t.selectedDates=[e],t.minRange=e,t.maxRange=""):1==n?(t.selectedDates.push(e),t.maxRange?t.minRange=e:t.maxRange=e,t.selectedDates=[t.minRange,t.maxRange]):(t.selectedDates=[e],t.minRange=e):t.selectedDates=[e];t._setInputValue(),s.onSelect&&t._triggerOnChange(),s.autoClose&&(s.multipleDates||s.range?s.range&&2==t.selectedDates.length&&t.hide():t.hide()),t.views[this.currentView]._render()}},removeDate:function(e){var t=this.selectedDates,s=this;if(e instanceof Date)return t.some(function(i,a){return n.isSame(i,e)?(t.splice(a,1),s.selectedDates.length||(s.minRange="",s.maxRange=""),s.views[s.currentView]._render(),s._setInputValue(),s.opts.onSelect&&s._triggerOnChange(),!0):void 0})},today:function(){this.silent=!0,this.view=this.opts.minView,this.silent=!1,this.date=new Date},clear:function(){this.selectedDates=[],this.minRange="",this.maxRange="",this.views[this.currentView]._render(),this._setInputValue(),this.opts.onSelect&&this._triggerOnChange()},update:function(e,s){var i=arguments.length;return 2==i?this.opts[e]=s:1==i&&"object"==typeof e&&(this.opts=t.extend(!0,this.opts,e)),this._createShortCuts(),this._syncWithMinMaxDates(),this._defineLocale(this.opts.language),this.nav._addButtonsIfNeed(),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},_syncWithMinMaxDates:function(){var e=this.date.getTime();this.silent=!0,this.minTime>e&&(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 t?c[t]:c.day},_getDimensions:function(e){var t=e.offset();return{width:e.outerWidth(),height:e.outerHeight(),left:t.left,top:t.top}},_getDateFromCell:function(e){var t=this.parsedDate,i=e.data("year")||t.year,a=e.data("month")==s?t.month:e.data("month"),n=e.data("date")||1;return new Date(i,a,n)},_setPositionClasses:function(e){e=e.split(" ");var t=e[0],s=e[1],i="datepicker -"+t+"-"+s+"- -from-"+t+"-";this.visible&&(i+=" active"),this.$datepicker.removeAttr("class").addClass(i)},setPosition:function(e){e=e||this.opts.position;var t,s,i=this._getDimensions(this.$el),a=this._getDimensions(this.$datepicker),n=e.split(" "),h=this.opts.offset,o=n[0],r=n[1];switch(o){case"top":t=i.top-a.height-h;break;case"right":s=i.left+i.width+h;break;case"bottom":t=i.top+i.height+h;break;case"left":s=i.left-a.width-h}switch(r){case"top":t=i.top;break;case"right":s=i.left+i.width-a.width;break;case"bottom":t=i.top+i.height-a.height;break;case"left":s=i.left;break;case"center":/left|right/.test(o)?t=i.top+i.height/2-a.height/2:s=i.left+i.width/2-a.width/2}this.$datepicker.css({left:s,top:t})},show:function(){this.setPosition(this.opts.position),this.$datepicker.addClass("active"),this.visible=!0},hide:function(){this.$datepicker.removeClass("active").css({left:"-100000px"}),this.focused="",this.keys=[],this.inFocus=!1,this.visible=!1,this.$el.blur()},down:function(e){this._changeView(e,"down")},up:function(e){this._changeView(e,"up")},_changeView:function(e,t){e=e||this.focused||this.date;var s="up"==t?this.viewIndex+1:this.viewIndex-1;s>2&&(s=2),0>s&&(s=0),this.silent=!0,this.date=new Date(e.getFullYear(),e.getMonth(),1),this.silent=!1,this.view=this.viewIndexes[s]},_handleHotKey:function(e){var t,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(e){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),u>i&&(u=i),s.getTime()this.maxTime&&(s=this.maxDate),this.focused=s,t=n.getParsedDate(s),o&&h.onChangeMonth&&h.onChangeMonth(t.month,t.year),r&&h.onChangeYear&&h.onChangeYear(t.year),c&&h.onChangeDecade&&h.onChangeDecade(this.curDecade)},_registerKey:function(e){var t=this.keys.some(function(t){return t==e});t||this.keys.push(e)},_unRegisterKey:function(e){var t=this.keys.indexOf(e);this.keys.splice(t,1)},_isHotKeyPressed:function(){var e,t=!1,s=this,i=this.keys.sort();for(var a in l)e=l[a],i.length==e.length&&e.every(function(e,t){return e==i[t]})&&(s._trigger("hotKey",a),t=!0);return t},_trigger:function(e,t){this.$el.trigger(e,t)},_focusNextCell:function(e,t){t=t||this.cellType;var s=n.getParsedDate(this._getFocusedDate()),i=s.year,a=s.month,h=s.date;if(!this._isHotKeyPressed()){switch(e){case 37:"day"==t?h-=1:"","month"==t?a-=1:"","year"==t?i-=1:"";break;case 38:"day"==t?h-=7:"","month"==t?a-=3:"","year"==t?i-=4:"";break;case 39:"day"==t?h+=1:"","month"==t?a+=1:"","year"==t?i+=1:"";break;case 40:"day"==t?h+=7:"","month"==t?a+=3:"","year"==t?i+=4:""}var o=new Date(i,a,h);o.getTime()this.maxTime&&(o=this.maxDate),this.focused=o}},_getFocusedDate:function(){var e=this.focused||this.selectedDates[this.selectedDates.length-1],t=this.parsedDate;if(!e)switch(this.view){case"days":e=new Date(t.year,t.month,(new Date).getDate());break;case"months":e=new Date(t.year,t.month,1);break;case"years":e=new Date(t.year,0,1)}return e},_getCell:function(e,t){t=t||this.cellType;var s,i=n.getParsedDate(e),a='.datepicker--cell[data-year="'+i.year+'"]';switch(t){case"month":a='[data-month="'+i.month+'"]';break;case"day":a+='[data-month="'+i.month+'"][data-date="'+i.date+'"]'}return s=this.views[this.currentView].$el.find(a),s.length?s:""},destroy:function(){var e=this;e.$el.off(".adp").data("datepicker",""),e.selectedDates=[],e.focused="",e.views={},e.keys=[],e.minRange="",e.maxRange="",e.opts.inline||!e.elIsInput?e.$datepicker.closest(".datepicker-inline").remove():e.$datepicker.remove()},_onShowEvent:function(){this.visible||this.show()},_onBlur:function(){!this.inFocus&&this.visible&&this.hide()},_onMouseDownDatepicker:function(e){this.inFocus=!0},_onMouseUpDatepicker:function(e){this.inFocus=!1,this.$el.focus()},_onInput:function(){var e=this.$el.val();e||this.clear()},_onResize:function(){this.visible&&this.setPosition()},_onKeyDown:function(e){var t=e.which;if(this._registerKey(t),t>=37&&40>=t&&(e.preventDefault(),this._focusNextCell(t)),13==t&&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);s?s&&this.opts.toggleSelected&&this.removeDate(this.focused):this.selectDate(this.focused)}}27==t&&this.hide()},_onKeyUp:function(e){var t=e.which;this._unRegisterKey(t)},_onHotKey:function(e,t){this._handleHotKey(t)},_onMouseEnterCell:function(e){var s=t(e.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(e){var s=t(e.target).closest(".datepicker--cell");s.removeClass("-focus-"),this.silent=!0,this.focused="",this.silent=!1},set focused(e){if(!e&&this.focused){var t=this._getCell(this.focused);t.length&&t.removeClass("-focus-")}this._focused=e,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=e)},get focused(){return this._focused},get parsedDate(){return n.getParsedDate(this.date)},set date(e){return e instanceof Date?(this.currentDate=e,this.inited&&!this.silent&&(this.views[this.view]._render(),this.nav._render(),this.visible&&this.elIsInput&&this.setPosition()),e):void 0},get date(){return this.currentDate},set view(e){return this.viewIndex=this.viewIndexes.indexOf(e),this.viewIndex<0?void 0:(this.prevView=this.currentView,this.currentView=e,this.inited&&(this.views[e]?this.views[e]._render():this.views[e]=new Datepicker.Body(this,e,this.opts),this.views[this.prevView].hide(),this.views[e].show(),this.nav._render(),this.opts.onChangeView&&this.opts.onChangeView(e),this.elIsInput&&this.visible&&this.setPosition()),e)},get view(){return this.currentView},get cellType(){return this.view.substring(0,this.view.length-1)},get minTime(){var e=n.getParsedDate(this.minDate);return new Date(e.year,e.month,e.date).getTime()},get maxTime(){var e=n.getParsedDate(this.maxDate);return new Date(e.year,e.month,e.date).getTime()},get curDecade(){return n.getDecade(this.date)}},n.getDaysCount=function(e){return new Date(e.getFullYear(),e.getMonth()+1,0).getDate()},n.getParsedDate=function(e){return{year:e.getFullYear(),month:e.getMonth(),fullMonth:e.getMonth()+1<10?"0"+(e.getMonth()+1):e.getMonth()+1,date:e.getDate(),fullDate:e.getDate()<10?"0"+e.getDate():e.getDate(),day:e.getDay()}},n.getDecade=function(e){var t=10*Math.floor(e.getFullYear()/10);return[t,t+9]},n.template=function(e,t){return e.replace(/#\{([\w]+)\}/g,function(e,s){return t[s]||0===t[s]?t[s]:void 0})},n.isSame=function(e,t,s){if(!e||!t)return!1;var i=n.getParsedDate(e),a=n.getParsedDate(t),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(e,t,s){return e&&t?t.getTime()e.getTime():!1},Datepicker.language={ru:{days:["Воскресенье","Понедельник","Вторник","Среда","Четверг","Пятница","Суббота"],daysShort:["Вос","Пон","Вто","Сре","Чет","Пят","Суб"],daysMin:["Вс","Пн","Вт","Ср","Чт","Пт","Сб"],months:["Январь","Февраль","Март","Апрель","Май","Июнь","Июль","Август","Сентябрь","Октябрь","Ноябрь","Декабрь"],monthsShort:["Янв","Фев","Мар","Апр","Май","Июн","Июл","Авг","Сен","Окт","Ноя","Дек"],today:"Сегодня",clear:"Очистить",dateFormat:"dd.mm.yyyy",firstDay:1}},t.fn[h]=function(e){return this.each(function(){if(t.data(this,h)){var s=t.data(this,h);s.opts=t.extend(!0,s.opts,e),s.update()}else t.data(this,h,new Datepicker(this,e))})},t(function(){t(o).datepicker()})}(),function(){var e={days:'
',months:'
',years:'
'},i=Datepicker;i.Body=function(e,t,s){this.d=e,this.type=t,this.opts=s,this.init()},i.Body.prototype={init:function(){this._buildBaseHtml(),this._render(),this._bindEvents()},_bindEvents:function(){this.$el.on("click",".datepicker--cell",t.proxy(this._onClickCell,this))},_buildBaseHtml:function(){this.$el=t(e[this.type]).appendTo(this.d.$content),this.$names=t(".datepicker--days-names",this.$el),this.$cells=t(".datepicker--cells",this.$el)},_getDayNamesHtml:function(e,t,i,a){return t=t!=s?t:e,i=i?i:"",a=a!=s?a:0,a>7?i:7==t?this._getDayNamesHtml(e,0,i,++a):(i+='
'+this.d.loc.daysMin[t]+"
",this._getDayNamesHtml(e,++t,i,++a))},_getCellContents:function(e,t){var s="datepicker--cell datepicker--cell-"+t,a=new Date,n=this.d,h=n.opts,o=i.getParsedDate(e),r={},c=o.date;switch(h.onRenderCell&&(r=h.onRenderCell(e,t)||{},c=r.html?r.html:c,s+=r.classes?" "+r.classes:""),t){case"day":n.isWeekend(o.day)&&(s+=" -weekend-"),o.month!=this.d.parsedDate.month&&(s+=" -other-month-",h.selectOtherMonths||(s+=" -disabled-"),h.showOtherMonths||(c=""));break;case"month":c=n.loc[n.opts.monthsField][o.month];break;case"year":var d=n.curDecade;c=o.year,(o.yeard[1])&&(s+=" -other-decade-",h.selectOtherYears||(s+=" -disabled-"),h.showOtherYears||(c=""))}return h.onRenderCell&&(r=h.onRenderCell(e,t)||{},c=r.html?r.html:c,s+=r.classes?" "+r.classes:""),h.range&&(i.isSame(n.minRange,e,t)&&(s+=" -range-from-"),i.isSame(n.maxRange,e,t)&&(s+=" -range-to-"),1==n.selectedDates.length&&n.focused?((i.bigger(n.minRange,e)&&i.less(n.focused,e)||i.less(n.maxRange,e)&&i.bigger(n.focused,e))&&(s+=" -in-range-"),i.less(n.maxRange,e)&&i.isSame(n.focused,e)&&(s+=" -range-from-"),i.bigger(n.minRange,e)&&i.isSame(n.focused,e)&&(s+=" -range-to-")):2==n.selectedDates.length&&i.bigger(n.minRange,e)&&i.less(n.maxRange,e)&&(s+=" -in-range-")),i.isSame(a,e,t)&&(s+=" -current-"),n.focused&&i.isSame(e,n.focused,t)&&(s+=" -focus-"),n._isSelected(e,t)&&(s+=" -selected-"),(!n._isInRange(e,t)||r.disabled)&&(s+=" -disabled-"),{html:c,classes:s}},_getDaysHtml:function(e){var t=i.getDaysCount(e),s=new Date(e.getFullYear(),e.getMonth(),1).getDay(),a=new Date(e.getFullYear(),e.getMonth(),t).getDay(),n=s-this.d.loc.firstDay,h=6-a+this.d.loc.firstDay;n=0>n?n+7:n,h=h>6?h-7:h;for(var o,r,c=-n+1,d="",l=c,u=t+h;u>=l;l++)r=e.getFullYear(),o=e.getMonth(),d+=this._getDayHtml(new Date(r,o,l));return d},_getDayHtml:function(e){var t=this._getCellContents(e,"day");return'
'+t.html+"
"},_getMonthsHtml:function(e){for(var t="",s=i.getParsedDate(e),a=0;12>a;)t+=this._getMonthHtml(new Date(s.year,a)),a++;return t},_getMonthHtml:function(e){var t=this._getCellContents(e,"month");return'
'+t.html+"
"},_getYearsHtml:function(e){var t=(i.getParsedDate(e),i.getDecade(e)),s=t[0]-1,a="",n=s;for(n;n<=t[1]+1;n++)a+=this._getYearHtml(new Date(n,0));return a},_getYearHtml:function(e){var t=this._getCellContents(e,"year");return'
'+t.html+"
"},_renderTypes:{days:function(){var e=this._getDayNamesHtml(this.d.loc.firstDay),t=this._getDaysHtml(this.d.currentDate);this.$cells.html(t),this.$names.html(e)},months:function(){var e=this._getMonthsHtml(this.d.currentDate);this.$cells.html(e)},years:function(){var e=this._getYearsHtml(this.d.currentDate);this.$cells.html(e)}},_render:function(){this._renderTypes[this.type].bind(this)()},_update:function(){var e,s,i,a=t(".datepicker--cell",this.$cells),n=this;a.each(function(a,h){s=t(this),i=n.d._getDateFromCell(t(this)),e=n._getCellContents(i,n.d.cellType),s.attr("class",e.classes)})},show:function(){this.$el.addClass("active"),this.acitve=!0},hide:function(){this.$el.removeClass("active"),this.active=!1},_handleClick:function(e){var t=e.data("date")||1,s=e.data("month")||0,i=e.data("year")||this.d.parsedDate.year;if(this.d.view!=this.opts.minView)return void this.d.down(new Date(i,s,t));var a=new Date(i,s,t),n=this.d._isSelected(a,this.d.cellType);n?n&&this.opts.toggleSelected&&this.d.removeDate(a):this.d.selectDate(a)},_onClickCell:function(e){var s=t(e.target).closest(".datepicker--cell");s.hasClass("-disabled-")||this._handleClick.bind(this)(s)}}}(),function(){var e='
#{prevHtml}
#{title}
#{nextHtml}
',s='
',i='#{label}';Datepicker.Navigation=function(e,t){this.d=e,this.opts=t,this.$buttonsContainer="",this.init()},Datepicker.Navigation.prototype={init:function(){this._buildBaseHtml(),this._bindEvents()},_bindEvents:function(){this.d.$nav.on("click",".datepicker--nav-action",t.proxy(this._onClickNavButton,this)),this.d.$nav.on("click",".datepicker--nav-title",t.proxy(this._onClickNavTitle,this)),this.d.$datepicker.on("click",".datepicker--button",t.proxy(this._onClickNavButton,this))},_buildBaseHtml:function(){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=Datepicker.template(e,t.extend({title:s},this.opts));this.d.$nav.html(i),"years"==this.d.view&&t(".datepicker--nav-title",this.d.$nav).addClass("-disabled-"),this.setNavStatus()},_getTitle:function(e){return this.d.formatDate(this.opts.navTitles[this.d.view],e)},_addButton:function(e){this.$buttonsContainer.length||this._addButtonsContainer();var s={action:e,label:this.d.loc[e]},a=Datepicker.template(i,s);t("[data-action="+e+"]",this.$buttonsContainer).length||this.$buttonsContainer.append(a)},_addButtonsContainer:function(){this.d.$datepicker.append(s),this.$buttonsContainer=t(".datepicker--buttons",this.d.$datepicker)},setNavStatus:function(){if((this.opts.minDate||this.opts.maxDate)&&this.opts.disableNavWhenOutOfRange){var e=this.d.parsedDate,t=e.month,s=e.year,i=e.date;switch(this.d.view){case"days":this.d._isInRange(new Date(s,t-1,i),"month")||this._disableNav("prev"),this.d._isInRange(new Date(s,t+1,i),"month")||this._disableNav("next");break;case"months":this.d._isInRange(new Date(s-1,t,i),"year")||this._disableNav("prev"),this.d._isInRange(new Date(s+1,t,i),"year")||this._disableNav("next");break;case"years":this.d._isInRange(new Date(s-10,t,i),"year")||this._disableNav("prev"),this.d._isInRange(new Date(s+10,t,i),"year")||this._disableNav("next")}}},_disableNav:function(e){t('[data-action="'+e+'"]',this.d.$nav).addClass("-disabled-")},_activateNav:function(e){t('[data-action="'+e+'"]',this.d.$nav).removeClass("-disabled-")},_onClickNavButton:function(e){var s=t(e.target).closest("[data-action]"),i=s.data("action");this.d[i]()},_onClickNavTitle:function(e){return t(e.target).hasClass("-disabled-")?void 0:"days"==this.d.view?this.d.view="months":void(this.d.view="years")}}}()}(window,jQuery); \ No newline at end of file +!function(t,e,i){!function(){var s,a,n,h="datepicker",r=".datepicker-here",o=!1,c='
',d={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,dateTimeSeparator:" ",timeFormat:"",minHours:0,maxHours:24,minMinutes:0,maxMinutes:59,hoursStep:1,minutesStep:1,onSelect:"",onChangeMonth:"",onChangeYear:"",onChangeDecade:"",onChangeView:"",onRenderCell:""},l={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]},u=function(t,a){this.el=t,this.$el=e(t),this.opts=e.extend(!0,{},d,a,this.$el.data()),s==i&&(s=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=u,n.prototype={viewIndexes:["days","months","years"],init:function(){o||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._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.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-1!==this.opts.weekends.indexOf(t)},_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));var i=this._getWordBoundaryRegExp;(this.loc.timeFormat.match(i("aa"))||this.loc.timeFormat.match(i("AA")))&&(this.ampm=!0)},_buildDatepickersContainer:function(){o=!0,s.append('
'),a=e("#datepickers-container")},_buildBaseHtml:function(){var t,i=e('
');t="INPUT"==this.el.nodeName?this.opts.inline?i.insertAfter(this.$el):a:i.appendTo(this.$el),this.$datepicker=e(c).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,i=n.getParsedDate(e[0]),s=this,a=new Date(i.year,i.month,i.date,i.hours,i.minutes);t=e.map(function(t){return s.formatDate(s.loc.dateFormat,t)}).join(this.opts.multipleDatesSeparator),(this.opts.multipleDates||this.opts.range)&&(a=e.map(function(t){n.getParsedDate(t);return new Date(i.year,i.month,i.date,i.hours,i.minutes)})),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 i,s=t,a=this._getWordBoundaryRegExp,h=this.loc,r=n.getLeadingZeroNum,o=n.getDecade(e),c=n.getParsedDate(e),d=c.fullHours,l=c.hours,u="am";switch(this.opts.timepicker&&this.timepicker&&this.ampm&&(i=this.timepicker._getValidHoursFromDate(e),d=r(i.hours),l=i.hours,u=i.dayPeriod),!0){case/@/.test(s):s=s.replace(/@/,e.getTime());case/aa/.test(s):s=s.replace(a("aa"),u);case/AA/.test(s):s=s.replace(a("AA"),u.toUpperCase());case/dd/.test(s):s=s.replace(a("dd"),c.fullDate);case/d/.test(s):s=s.replace(a("d"),c.date);case/DD/.test(s):s=s.replace(a("DD"),h.days[c.day]);case/D/.test(s):s=s.replace(a("D"),h.daysShort[c.day]);case/mm/.test(s):s=s.replace(a("mm"),c.fullMonth);case/m/.test(s):s=s.replace(a("m"),c.month+1);case/MM/.test(s):s=s.replace(a("MM"),this.loc.months[c.month]);case/M/.test(s):s=s.replace(a("M"),h.monthsShort[c.month]);case/ii/.test(s):s=s.replace(a("ii"),c.fullMinutes);case/i/.test(s):s=s.replace(a("i"),c.minutes);case/hh/.test(s):s=s.replace(a("hh"),d);case/h/.test(s):s=s.replace(a("h"),l);case/yyyy/.test(s):s=s.replace(a("yyyy"),c.year);case/yyyy1/.test(s):s=s.replace(a("yyyy1"),o[0]);case/yyyy2/.test(s):s=s.replace(a("yyyy2"),o[1]);case/yy/.test(s):s=s.replace(a("yy"),c.year.toString().slice(-2))}return s},_getWordBoundaryRegExp:function(t){return new RegExp("\\b(?=[a-zA-Z0-9äöüßÄÖÜ<])"+t+"(?![>a-zA-Z0-9äöüßÄÖÜ])")},selectDate:function(t){var e=this,i=e.opts,s=e.parsedDate,a=e.selectedDates,h=a.length,r="";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)),"days"==e.view&&t.getMonth()!=s.month&&i.moveToOtherMonthsOnSelect&&(r=new Date(t.getFullYear(),t.getMonth(),1)),"years"==e.view&&t.getFullYear()!=s.year&&i.moveToOtherYearsOnSelect&&(r=new Date(t.getFullYear(),0,1)),r&&(e.silent=!0,e.date=r,e.silent=!1,e.nav._render()),i.multipleDates&&!i.range){if(h===i.multipleDates)return;e._isSelected(t)||e.selectedDates.push(t)}else i.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(),i.onSelect&&e._triggerOnChange(),i.autoClose&&!this.timepickerIsActive&&(i.multipleDates||i.range?i.range&&2==e.selectedDates.length&&e.hide():e.hide()),e.views[this.currentView]._render()}},removeDate:function(t){var e=this.selectedDates,i=this;if(t instanceof Date)return e.some(function(s,a){return n.isSame(s,t)?(e.splice(a,1),i.selectedDates.length?i.lastSelectedDate=i.selectedDates[i.selectedDates.length-1]:(i.minRange="",i.maxRange="",i.lastSelectedDate=""),i.views[i.currentView]._render(),i._setInputValue(),i.opts.onSelect&&i._triggerOnChange(),!0):void 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,i){var s=arguments.length;return 2==s?this.opts[t]=i:1==s&&"object"==typeof t&&(this.opts=e.extend(!0,this.opts,t)),this._createShortCuts(),this._syncWithMinMaxDates(),this._defineLocale(this.opts.language),this.nav._addButtonsIfNeed(),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.timepicker&&(this.timepicker._handleDate(this.lastSelectedDate),this.timepicker._updateRanges(),this.timepicker._updateCurrentTime(),this.lastSelectedDate&&(this.lastSelectedDate.setHours(this.timepicker.hours),this.lastSelectedDate.setMinutes(this.timepicker.minutes))),this._setInputValue(),this},_syncWithMinMaxDates:function(){var t=this.date.getTime();this.silent=!0,this.minTime>t&&(this.date=this.minDate),this.maxTime=this.minTime&&i<=this.maxTime,month:r>=this.minTime&&o<=this.maxTime,year:s.year>=a.year&&s.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,s=t.data("year")||e.year,a=t.data("month")==i?e.month:t.data("month"),n=t.data("date")||1;return new Date(s,a,n)},_setPositionClasses:function(t){t=t.split(" ");var e=t[0],i=t[1],s="datepicker -"+e+"-"+i+"- -from-"+e+"-";this.visible&&(s+=" active"),this.$datepicker.removeAttr("class").addClass(s)},setPosition:function(t){t=t||this.opts.position;var e,i,s=this._getDimensions(this.$el),a=this._getDimensions(this.$datepicker),n=t.split(" "),h=this.opts.offset,r=n[0],o=n[1];switch(r){case"top":e=s.top-a.height-h;break;case"right":i=s.left+s.width+h;break;case"bottom":e=s.top+s.height+h;break;case"left":i=s.left-a.width-h}switch(o){case"top":e=s.top;break;case"right":i=s.left+s.width-a.width;break;case"bottom":e=s.top+s.height-a.height;break;case"left":i=s.left;break;case"center":/left|right/.test(r)?e=s.top+s.height/2-a.height/2:i=s.left+s.width/2-a.width/2}this.$datepicker.css({left:i,top:e})},show:function(){this.setPosition(this.opts.position),this.$datepicker.addClass("active"),this.visible=!0},hide:function(){this.$datepicker.removeClass("active").css({left:"-100000px"}),this.focused="",this.keys=[],this.inFocus=!1,this.visible=!1,this.$el.blur()},down:function(t){this._changeView(t,"down")},up:function(t){this._changeView(t,"up")},_changeView:function(t,e){t=t||this.focused||this.date;var i="up"==e?this.viewIndex+1:this.viewIndex-1;i>2&&(i=2),0>i&&(i=0),this.silent=!0,this.date=new Date(t.getFullYear(),t.getMonth(),1),this.silent=!1,this.view=this.viewIndexes[i]},_handleHotKey:function(t){var e,i,s,a=n.getParsedDate(this._getFocusedDate()),h=this.opts,r=!1,o=!1,c=!1,d=a.year,l=a.month,u=a.date;switch(t){case"ctrlRight":case"ctrlUp":l+=1,r=!0;break;case"ctrlLeft":case"ctrlDown":l-=1,r=!0;break;case"shiftRight":case"shiftUp":o=!0,d+=1;break;case"shiftLeft":case"shiftDown":o=!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()}s=n.getDaysCount(new Date(d,l)),i=new Date(d,l,u),u>s&&(u=s),i.getTime()this.maxTime&&(i=this.maxDate),this.focused=i,e=n.getParsedDate(i),r&&h.onChangeMonth&&h.onChangeMonth(e.month,e.year),o&&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,i=this,s=this.keys.sort();for(var a in l)t=l[a],s.length==t.length&&t.every(function(t,e){return t==s[e]})&&(i._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 i=n.getParsedDate(this._getFocusedDate()),s=i.year,a=i.month,h=i.date;if(!this._isHotKeyPressed()){switch(t){case 37:"day"==e?h-=1:"","month"==e?a-=1:"","year"==e?s-=1:"";break;case 38:"day"==e?h-=7:"","month"==e?a-=3:"","year"==e?s-=4:"";break;case 39:"day"==e?h+=1:"","month"==e?a+=1:"","year"==e?s+=1:"";break;case 40:"day"==e?h+=7:"","month"==e?a+=3:"","year"==e?s+=4:""}var r=new Date(s,a,h);r.getTime()this.maxTime&&(r=this.maxDate),this.focused=r}},_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,e){e=e||this.cellType;var i,s=n.getParsedDate(t),a='.datepicker--cell[data-year="'+s.year+'"]';switch(e){case"month":a='[data-month="'+s.month+'"]';break;case"day":a+='[data-month="'+s.month+'"][data-date="'+s.date+'"]'}return i=this.views[this.currentView].$el.find(a),i.length?i:""},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()},_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&&40>=e&&(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 i=this._isSelected(this.focused,this.cellType);i?i&&this.opts.toggleSelected&&this.removeDate(this.focused):(this.timepicker&&(this.focused.setHours(this.timepicker.hours),this.focused.setMinutes(this.timepicker.minutes)),this.selectDate(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 i=e(t.target).closest(".datepicker--cell"),s=this._getDateFromCell(i);this.silent=!0,this.focused&&(this.focused=""),i.addClass("-focus-"),this.focused=s,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 i=e(t.target).closest(".datepicker--cell");i.removeClass("-focus-"),this.silent=!0,this.focused="",this.silent=!1},_onTimeChange:function(t,e,i){var s=new Date,a=this.selectedDates,n=!1;a.length&&(n=!0,s=this.lastSelectedDate),s.setHours(e),s.setMinutes(i),n||this._getCell(s).hasClass("-disabled-")?(this._setInputValue(),this.opts.onSelect&&this._triggerOnChange()):this.selectDate(s)},_onClickCell:function(t,e){this.timepicker&&(e.setHours(this.timepicker.hours),e.setMinutes(this.timepicker.minutes)),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){return t instanceof Date?(this.currentDate=t,this.inited&&!this.silent&&(this.views[this.view]._render(),this.nav._render(),this.visible&&this.elIsInput&&this.setPosition()),t):void 0},get date(){return this.currentDate},set view(t){return this.viewIndex=this.viewIndexes.indexOf(t),this.viewIndex<0?void 0:(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()}},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,i){return e[i]||0===e[i]?e[i]:void 0})},n.isSame=function(t,e,i){if(!t||!e)return!1;var s=n.getParsedDate(t),a=n.getParsedDate(e),h=i?i:"day",r={day:s.date==a.date&&s.month==a.month&&s.year==a.year,month:s.month==a.month&&s.year==a.year,year:s.year==a.year};return r[h]},n.less=function(t,e,i){return t&&e?e.getTime()t.getTime():!1},n.getLeadingZeroNum=function(t){return parseInt(t)<10?"0"+t:t},e.fn.datepicker=function(t){return this.each(function(){if(e.data(this,h)){var i=e.data(this,h);i.opts=e.extend(!0,i.opts,t),i.update()}else e.data(this,h,new u(this,t))})},e.fn.datepicker.Constructor=u,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:'
'},s=e.fn.datepicker,a=s.Constructor;s.Body=function(t,e,i){this.d=t,this.type=e,this.opts=i,this.init()},s.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,s,a){return e=e!=i?e:t,s=s?s:"",a=a!=i?a:0,a>7?s:7==e?this._getDayNamesHtml(t,0,s,++a):(s+='
'+this.d.loc.daysMin[e]+"
",this._getDayNamesHtml(t,++e,s,++a))},_getCellContents:function(t,e){var i="datepicker--cell datepicker--cell-"+e,s=new Date,n=this.d,h=n.opts,r=a.getParsedDate(t),o={},c=r.date;switch(h.onRenderCell&&(o=h.onRenderCell(t,e)||{},c=o.html?o.html:c,i+=o.classes?" "+o.classes:""),e){case"day":n.isWeekend(r.day)&&(i+=" -weekend-"),r.month!=this.d.parsedDate.month&&(i+=" -other-month-",h.selectOtherMonths||(i+=" -disabled-"),h.showOtherMonths||(c=""));break;case"month":c=n.loc[n.opts.monthsField][r.month];break;case"year":var d=n.curDecade;c=r.year,(r.yeard[1])&&(i+=" -other-decade-",h.selectOtherYears||(i+=" -disabled-"),h.showOtherYears||(c=""))}return h.onRenderCell&&(o=h.onRenderCell(t,e)||{},c=o.html?o.html:c,i+=o.classes?" "+o.classes:""),h.range&&(a.isSame(n.minRange,t,e)&&(i+=" -range-from-"),a.isSame(n.maxRange,t,e)&&(i+=" -range-to-"),1==n.selectedDates.length&&n.focused?((a.bigger(n.minRange,t)&&a.less(n.focused,t)||a.less(n.maxRange,t)&&a.bigger(n.focused,t))&&(i+=" -in-range-"),a.less(n.maxRange,t)&&a.isSame(n.focused,t)&&(i+=" -range-from-"),a.bigger(n.minRange,t)&&a.isSame(n.focused,t)&&(i+=" -range-to-")):2==n.selectedDates.length&&a.bigger(n.minRange,t)&&a.less(n.maxRange,t)&&(i+=" -in-range-")),a.isSame(s,t,e)&&(i+=" -current-"),n.focused&&a.isSame(t,n.focused,e)&&(i+=" -focus-"),n._isSelected(t,e)&&(i+=" -selected-"),(!n._isInRange(t,e)||o.disabled)&&(i+=" -disabled-"),{html:c,classes:i}},_getDaysHtml:function(t){var e=a.getDaysCount(t),i=new Date(t.getFullYear(),t.getMonth(),1).getDay(),s=new Date(t.getFullYear(),t.getMonth(),e).getDay(),n=i-this.d.loc.firstDay,h=6-s+this.d.loc.firstDay;n=0>n?n+7:n,h=h>6?h-7:h;for(var r,o,c=-n+1,d="",l=c,u=e+h;u>=l;l++)o=t.getFullYear(),r=t.getMonth(),d+=this._getDayHtml(new Date(o,r,l));return d},_getDayHtml:function(t){var e=this._getCellContents(t,"day");return'
'+e.html+"
"},_getMonthsHtml:function(t){for(var e="",i=a.getParsedDate(t),s=0;12>s;)e+=this._getMonthHtml(new Date(i.year,s)),s++;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)),i=e[0]-1,s="",n=i;for(n;n<=e[1]+1;n++)s+=this._getYearHtml(new Date(n,0));return s},_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._renderTypes[this.type].bind(this)()},_update:function(){var t,i,s,a=e(".datepicker--cell",this.$cells),n=this;a.each(function(a,h){i=e(this),s=n.d._getDateFromCell(e(this)),t=n._getCellContents(s,n.d.cellType),i.attr("class",t.classes)})},show:function(){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,i=t.data("month")||0,s=t.data("year")||this.d.parsedDate.year;if(this.d.view!=this.opts.minView)return void this.d.down(new Date(s,i,e));var a=new Date(s,i,e),n=this.d._isSelected(a,this.d.cellType);n?n&&this.opts.toggleSelected?this.d.removeDate(a):n&&!this.opts.toggleSelected&&(this.d.lastSelectedDate=n,this.d.opts.timepicker&&(this.d.timepicker._setTime(n),this.d.timepicker.update())):this.d._trigger("clickCell",a)},_onClickCell:function(t){var i=e(t.target).closest(".datepicker--cell");i.hasClass("-disabled-")||this._handleClick.bind(this)(i)}}}(),function(){var t='
#{prevHtml}
#{title}
#{nextHtml}
',i='
',s='#{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._render(),this._addButtonsIfNeed()},_addButtonsIfNeed:function(){this.opts.todayButton&&this._addButton("today"),this.opts.clearButton&&this._addButton("clear")},_render:function(){var i=this._getTitle(this.d.currentDate),s=n.template(t,e.extend({title:i},this.opts));this.d.$nav.html(s),"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 i={action:t,label:this.d.loc[t]},a=n.template(s,i);e("[data-action="+t+"]",this.$buttonsContainer).length||this.$buttonsContainer.append(a)},_addButtonsContainer:function(){this.d.$datepicker.append(i),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,i=t.year,s=t.date;switch(this.d.view){case"days":this.d._isInRange(new Date(i,e-1,s),"month")||this._disableNav("prev"),this.d._isInRange(new Date(i,e+1,s),"month")||this._disableNav("next");break;case"months":this.d._isInRange(new Date(i-1,e,s),"year")||this._disableNav("prev"),this.d._isInRange(new Date(i+1,e,s),"year")||this._disableNav("next");break;case"years":this.d._isInRange(new Date(i-10,e,s),"year")||this._disableNav("prev"),this.d._isInRange(new Date(i+10,e,s),"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 i=e(t.target).closest("[data-action]"),s=i.data("action");this.d[s]()},_onClickNavTitle:function(t){return e(t.target).hasClass("-disabled-")?void 0:"days"==this.d.view?this.d.view="months":void(this.d.view="years")}}}(),function(){var t='
#{hourValue} : #{minValue}
',i=e.fn.datepicker,s=i.Constructor;i.Timepicker=function(t,e){this.d=t,this.opts=e,this.init()},i.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=s.getParsedDate(t);this._handleDate(t),this.hours=e.hourst?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},_validateHoursMinutes:function(t){this.hoursthis.maxHours&&(this.hours=this.maxHours),this.minutesthis.maxMinutes&&(this.minutes=this.maxMinutes)},_buildHTML:function(){var i=s.getLeadingZeroNum,a={hourMin:this.minHours,hourMax:i(this.maxHours),hourStep:this.opts.hoursStep,hourValue:i(this.displayHours),minMin:this.minMinutes,minMax:i(this.maxMinutes),minStep:this.opts.minutesStep,minValue:i(this.minutes)},n=s.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.$hoursText=e(".datepicker--time-current-hours",this.$timepicker),this.$minutesText=e(".datepicker--time-current-minutes",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=s.getLeadingZeroNum(this.displayHours),e=s.getLeadingZeroNum(this.minutes);this.$hoursText.html(t),this.$minutesText.html(e),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)},_handleDate:function(t){this._setDefaultMinMaxTime(),t&&(s.isSame(t,this.d.opts.minDate)?this._setMinTimeFromDate(this.d.opts.minDate):s.isSame(t,this.d.opts.maxDate)&&this._setMaxTimeFromDate(this.d.opts.maxDate)),this._validateHoursMinutes(t)},update:function(){this._updateRanges(),this._updateCurrentTime()},_getValidHoursFromDate:function(t){var e=t,i=t;t instanceof Date&&(e=s.getParsedDate(t),i=e.hours);var a=this.d.ampm,n="am";if(a)switch(!0){case 0==i:i=12;break;case 12==i:n="pm";break;case i>11:i-=12,n="pm"}return{hours:i,dayPeriod:n}},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 i=e(t.target),s=i.attr("name");this.d.timepickerIsActive=!0,this[s]=i.val(),this._updateCurrentTime(),this.d._trigger("timeChange",[this.hours,this.minutes])},_onSelectDate:function(t,e){this._handleDate(e),this.update()},_onMouseEnterRange:function(t){var i=e(t.target).attr("name");e(".datepicker--time-current-"+i,this.$timepicker).addClass("-focus-")},_onMouseOutRange:function(t){var i=e(t.target).attr("name");this.d.inFocus||e(".datepicker--time-current-"+i,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.da.js b/dist/js/i18n/datepicker.da.js new file mode 100644 index 00000000..f34456e4 --- /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 index 1ec294d8..fd9f8ff3 100644 --- a/dist/js/i18n/datepicker.de.js +++ b/dist/js/i18n/datepicker.de.js @@ -1,4 +1,4 @@ -Datepicker.language['de'] = { +;(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'], @@ -7,5 +7,7 @@ Datepicker.language['de'] = { 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 index 38dcdd0c..5857127d 100644 --- a/dist/js/i18n/datepicker.en.js +++ b/dist/js/i18n/datepicker.en.js @@ -1,4 +1,5 @@ -Datepicker.language['en'] = { +;(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'], @@ -6,6 +7,8 @@ Datepicker.language['en'] = { monthsShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], today: 'Today', clear: 'Clear', - dateFormat: 'mm/dd/yy', + dateFormat: 'mm/dd/yyyy', + timeFormat: 'hh:ii aa', firstDay: 0 -}; \ No newline at end of file +}; +})(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 00000000..8d29a5ac --- /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.pt-BR.js b/dist/js/i18n/datepicker.pt-BR.js new file mode 100644 index 00000000..13a79f54 --- /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 00000000..92a3a08a --- /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 00000000..0034204d --- /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.zh.js b/dist/js/i18n/datepicker.zh.js index db3a4b40..08633ccc 100644 --- a/dist/js/i18n/datepicker.zh.js +++ b/dist/js/i18n/datepicker.zh.js @@ -1,4 +1,4 @@ -Datepicker.language['zh'] = { +;(function ($) { $.fn.datepicker.language['zh'] = { days: ['周日', '周一', '周二', '周三', '周四', '周五', '周六'], daysShort: ['日', '一', '二', '三', '四', '五', '六'], daysMin: ['日', '一', '二', '三', '四', '五', '六'], @@ -7,5 +7,6 @@ Datepicker.language['zh'] = { today: '今天', clear: '清除', dateFormat: 'yyyy-mm-dd', + timeFormat: 'hh:ii', firstDay: 1 -}; \ No newline at end of file +}; })(jQuery); \ No newline at end of file diff --git a/docs/css/style.css b/docs/css/style.css index 14ea9398..02f4d7e5 100644 --- a/docs/css/style.css +++ b/docs/css/style.css @@ -1 +1 @@ -.-text-center-,.datepicker-promo,.promo-header{text-align:center}a,abbr,acronym,address,applet,article,aside,audio,big,blockquote,canvas,caption,center,cite,code,dd,del,details,dfn,dl,dt,em,embed,fieldset,figcaption,figure,footer,form,header,i,iframe,img,ins,kbd,label,legend,li,mark,menu,nav,object,ol,output,p,pre,q,ruby,s,samp,section,small,strike,sub,summary,sup,table,tbody,td,tfoot,th,thead,time,tr,tt,u,ul,var,video{margin:0;padding:0;border:0;font:inherit;vertical-align:baseline}body{margin:0}body,html{width:100%;height:100%}*,:after,:before{box-sizing:border-box}article,aside,details,figcaption,figure,footer,header,main,menu,nav,section,summary{display:block}b,strong{font-weight:700}i{font-style:italic}a{outline:0;color:#47A6EC}textarea{overflow:auto}html{color:#333;font-family:Tahoma,sans-serif;font-size:14px;min-width:320px}p{line-height:1.3;margin-bottom:14px}h1,h2,h3,h4{font-family:'Fira Sans',sans-serif;line-height:1}h2{font-weight:100;font-size:32px;margin:48px 0 8px}h3{font-weight:500;font-size:18px;margin:24px 0 8px}h4{font-weight:400;color:#939393;font-size:16px;margin:24px 0 0}article h2,article h3{position:relative;z-index:1}article h2:after,article h3:after{content:'';background:rgba(67,156,255,.2);border-radius:4px;opacity:0;left:-8px;right:-8px;top:-10px;bottom:-4px;position:absolute;z-index:-1;transition:all .4s .3s linear}.nav,.nav-wrap{bottom:0;top:0}article h2.-hilited-:after,article h3.-hilited-:after{opacity:1;transition:all .4s .7s linear}.container{max-width:960px;margin:0 auto;padding:1px 0;position:relative}.buttons,.example--label,.lang-link{position:absolute}.container article{margin:60px 0 30px}@media all and (max-width:1525px){.container{margin-left:270px}}@media all and (max-width:1280px){.container{margin-right:20px}}@media all and (max-width:650px){.container{margin-right:20px;margin-left:20px}}.list-inline{display:-webkit-flex;display:-ms-flexbox;display:flex;margin:-8px -8px 0}.list-inline>*{margin:8px 8px 0}.buttons{top:19px}.lang-link{display:-webkit-inline-flex;display:-ms-inline-flexbox;display:inline-flex;-webkit-align-items:center;-ms-flex-align:center;align-items:center;right:0;top:15px}.lang-link img{margin-right:5px}@media all and (max-width:650px){.lang-link span{display:none}}input[type=text]{outline:0;height:32px;border:1px solid #b5b5b5;padding:0 8px;margin:0 0 14px;color:#444;font-family:Tahoma,sans-serif;transition:all .2s;width:250px}.hljs,.param-inline{font-family:Consolas,monospace}input[type=text]:focus{border-color:#ffd75c}ul{margin:0 0 16px}ul li{list-style:none;margin-bottom:8px}.example--label{background:#ececec;border-radius:0 0 4px 4px;padding:4px 12px;right:8px;top:0}.hljs{line-height:1.2;-moz-tab-size:4;tab-size:4}.example{border:1px solid #ececec;border-radius:4px;position:relative;margin:16px 0}.example .example-code{border:none;border-radius:0 0 4px 4px;border-top:1px solid #ececec;margin:0}.example-inline{background:red;display:inline-block;vertical-align:middle;margin:0 4px}.example-inline .hljs{padding:0 4px}.example-content{padding:32px}@media all and (max-width:650px){.example-content{padding-left:4%;padding-right:4%}}.example-content h1:first-child,.example-content h2:first-child,.example-content h3:first-child{margin-top:0}.example-content>:last-child{margin-bottom:0!important}a:hover{color:#ff767e}.example-code{border:1px solid #ddd;border-radius:4px;overflow:hidden;margin:16px 0;font-size:13px}.param-inline i,.param-inline strong{display:inline-block;margin-right:4px;vertical-align:middle}.example-code code{padding:16px 32px}.param-inline strong{background:#efefef;color:#333;border-radius:4px;font-weight:400;padding:3px 6px 4px}.param-inline i{color:#838383;font-size:.95em;font-style:normal;font-weight:100;font-family:'Fira Sans',sans-serif}.promo-header{font-size:48px;font-weight:100;margin-top:54px}.promo-header span{display:block;font-size:.5em}.datepicker-promo .datepicker-inline,.param-header--label,.range-example span{display:inline-block}.range-example input[type=text]{width:150px}.range-example span{margin:0 8px}.param-header{margin-bottom:8px}.param-header h3{margin-bottom:2px}.param-header p{margin:0;font-size:13px}.param{margin-bottom:32px}.param-header--label{color:#707070;vertical-align:middle}.nav-wrap{background:#fff;position:fixed;overflow:hidden;width:250px;left:0;box-shadow:0 0 4px rgba(0,0,0,.3)}.dp-note,.nav{position:absolute}@media all and (max-width:650px){.nav-wrap{display:none}}.nav-wrap:after,.nav-wrap:before{content:'';pointer-events:none;position:absolute;left:0;right:0;height:28px}.nav-wrap:after{background:linear-gradient(to top,#fff,rgba(255,255,255,0));bottom:0}.nav{padding:18px;right:0;left:0;overflow-y:scroll;-webkit-overflow-scrolling:touch}.nav--section{margin-bottom:20px}.nav--section-title{line-height:1;font-size:22px;margin:0 0 8px}.nav--section-title a{color:#000;text-decoration:none}.nav--section-title a:hover{color:#ff767e}.nav--subsection{margin-left:2px}.nav--subsection-title{font-size:13px;margin:0 0 8px;font-weight:400;font-family:Tahoma,sans-serif}.nav--subsection-title a{color:#787878;text-decoration:none}.nav--subsection-title a:hover{color:#ff767e}.dp-note{background:#ccc;width:4px;height:4px;border-radius:50%;left:50%;bottom:1px;-webkit-transform:translateX(-50%);transform:translateX(-50%)}.-selected- .dp-note{bottom:2px;background:#fff;opacity:.5} \ No newline at end of file +.-text-center-,.datepicker-promo,.promo-header,.vt-tile h2{text-align:center}a,abbr,acronym,address,applet,article,aside,audio,big,blockquote,canvas,caption,center,cite,code,dd,del,details,dfn,dl,dt,em,embed,fieldset,figcaption,figure,footer,form,header,i,iframe,img,ins,kbd,label,legend,li,mark,menu,nav,object,ol,output,p,pre,q,ruby,s,samp,section,small,strike,sub,summary,sup,table,tbody,td,tfoot,th,thead,time,tr,tt,u,ul,var,video{margin:0;padding:0;border:0;font:inherit;vertical-align:baseline}body{margin:0}body,html{width:100%;height:100%}*,:after,:before{box-sizing:border-box}article,aside,details,figcaption,figure,footer,header,main,menu,nav,section,summary{display:block}b,strong{font-weight:700}i{font-style:italic}a{outline:0;color:#47A6EC}textarea{overflow:auto}html{color:#333;font-family:Tahoma,sans-serif;font-size:14px;min-width:320px}p{line-height:1.3;margin-bottom:14px}h1,h2,h3,h4{font-family:'Fira Sans',sans-serif;line-height:1}h2{font-weight:100;font-size:32px;margin:48px 0 8px}h3{font-weight:500;font-size:18px;margin:24px 0 8px}h4{font-weight:400;color:#939393;font-size:16px;margin:24px 0 0}article h2,article h3{position:relative;z-index:1}article h2:after,article h3:after{content:'';background:rgba(67,156,255,.2);border-radius:4px;opacity:0;left:-8px;right:-8px;top:-10px;bottom:-4px;position:absolute;z-index:-1;transition:all .4s .3s linear}.nav,.nav-wrap{bottom:0;top:0}article h2.-hilited-:after,article h3.-hilited-:after{opacity:1;transition:all .4s .7s linear}.container{max-width:960px;margin:0 auto;padding:1px 0;position:relative}.buttons,.example--label,.lang-link{position:absolute}.container article{margin:60px 0 30px}@media all and (max-width:1525px){.container{margin-left:270px}}@media all and (max-width:1280px){.container{margin-right:20px}}@media all and (max-width:650px){.container{margin-right:20px;margin-left:20px}}.list-inline{display:-webkit-flex;display:-ms-flexbox;display:flex;margin:-8px -8px 0}.list-inline>*{margin:8px 8px 0}.buttons{top:19px}.lang-link{display:-webkit-inline-flex;display:-ms-inline-flexbox;display:inline-flex;-webkit-align-items:center;-ms-flex-align:center;align-items:center;right:0;top:15px}.lang-link img{margin-right:5px}@media all and (max-width:650px){.lang-link span{display:none}}input[type=text]{outline:0;height:32px;border:1px solid #b5b5b5;padding:0 8px;margin:0 0 14px;color:#444;font-family:Tahoma,sans-serif;transition:all .2s;width:250px}.hljs,.param-inline{font-family:Consolas,monospace}input[type=text]:focus{border-color:#ffd75c}ul{margin:0 0 16px}ul li{list-style:none;margin-bottom:8px}.example--label{background:#ececec;border-radius:0 0 4px 4px;padding:4px 12px;right:8px;top:0}.hljs{line-height:1.2;-moz-tab-size:4;tab-size:4}.example{border:1px solid #ececec;border-radius:4px;position:relative;margin:16px 0}.example .example-code{border:none;border-radius:0 0 4px 4px;border-top:1px solid #ececec;margin:0}.example-inline{background:red;display:inline-block;vertical-align:middle;margin:0 4px}.example-inline .hljs{padding:0 4px}.example-content{padding:32px}@media all and (max-width:650px){.example-content{padding-left:4%;padding-right:4%}}.example-content h1:first-child,.example-content h2:first-child,.example-content h3:first-child{margin-top:0}.example-content>:last-child{margin-bottom:0!important}a:hover{color:#ff767e}.example-code{border:1px solid #ddd;border-radius:4px;overflow:hidden;margin:16px 0;font-size:13px}.param-inline i,.param-inline strong{display:inline-block;margin-right:4px;vertical-align:middle}.example-code code{padding:16px 32px}.param-inline strong{background:#efefef;color:#333;border-radius:4px;font-weight:400;padding:3px 6px 4px}.param-inline i{color:#838383;font-size:.95em;font-style:normal;font-weight:100;font-family:'Fira Sans',sans-serif}.promo-header{font-size:48px;font-weight:100;margin-top:54px}.promo-header span{display:block;font-size:.5em}.datepicker-promo .datepicker-inline,.param-header--label,.range-example span{display:inline-block}.range-example input[type=text]{width:150px}.range-example span{margin:0 8px}.param-header{margin-bottom:8px}.param-header h3{margin-bottom:2px}.param-header p{margin:0;font-size:13px}.param{margin-bottom:32px}.param-header--label{color:#707070;vertical-align:middle}.nav-wrap{background:#fff;position:fixed;overflow:hidden;width:250px;left:0;box-shadow:0 0 4px rgba(0,0,0,.3)}.dp-note,.nav{position:absolute}@media all and (max-width:650px){.nav-wrap{display:none}}.nav-wrap:after,.nav-wrap:before{content:'';pointer-events:none;position:absolute;left:0;right:0;height:28px}.nav-wrap:after{background:linear-gradient(to top,#fff,rgba(255,255,255,0));bottom:0}.nav{padding:18px;right:0;left:0;overflow-y:scroll;-webkit-overflow-scrolling:touch}.nav--section{margin-bottom:20px}.nav--section-title{line-height:1;font-size:22px;margin:0 0 8px}.nav--section-title a{color:#000;text-decoration:none}.nav--section-title a:hover{color:#ff767e}.nav--subsection{margin-left:2px}.nav--subsection-title{font-size:13px;margin:0 0 8px;font-weight:400;font-family:Tahoma,sans-serif}.v-log,.vt-tile h2{font-family:monospace}.nav--subsection-title a{color:#787878;text-decoration:none}.nav--subsection-title a:hover{color:#ff767e}.dp-note{background:#ccc;width:4px;height:4px;border-radius:50%;left:50%;bottom:1px;-webkit-transform:translateX(-50%);transform:translateX(-50%)}.-selected- .dp-note{bottom:2px;background:#fff;opacity:.5}.visual-tests{padding-top:12px;padding-bottom:120px}.visual-tests h1{color:#555;font-size:20px;margin:0;padding-left:16px}.visual-tests .row{border-bottom:1px solid #eee;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;margin-bottom:16px}.visual-tests article:last-child .row{border:none}.vt-tile{padding:16px;width:284px}.v-log,.vt-tile input{width:100%}.vt-tile h2{font-size:14px;margin:0 0 8px}.v-log{position:fixed;padding:8px;font-size:12px;background:rgba(0,0,0,.7);height:100px;bottom:0;overflow:auto;z-index:10}.v-log p{margin:0;color:#adff2f}.v-log span{color:#ddd} \ No newline at end of file diff --git a/docs/img/promo-img.png b/docs/img/promo-img.png index 09938589..aa628091 100644 Binary files a/docs/img/promo-img.png and b/docs/img/promo-img.png differ diff --git a/docs/index-ru.html b/docs/index-ru.html index 31fdceb7..0604e24f 100644 --- a/docs/index-ru.html +++ b/docs/index-ru.html @@ -1,5 +1,5 @@ Air Datepicker
In English

AIR DATEPICKERлегкий кроссбраузерный jQuery календарь

Описание

Легкий (~26kb минифицированный js файл и ~7kb gziped), кастомизируемый, кроссбраузерный календарь, написан с использованиемes5иcss flexbox. Работает во всех современных браузерах: +

Описание

Легкий (~34kb минифицированный js файл и ~9kb gziped), кастомизируемый, кроссбраузерный календарь, написан с использованиемes5иcss flexbox. Работает во всех современных браузерах: IE 10+, Chrome, Firefox, Safari 8+, Opera 17+.

Установка

bower i --save air-datepicker

Либо можно скачать файлы напрямую с GitHub

Использование

Подключите стили и скрипты из папки/dist:

<html>
 	<head>
 		<link href="dist/css/datepicker.min.css" rel="stylesheet" type="text/css">
@@ -125,6 +125,88 @@
 // Сразу выберем какую-ниудь дату из `eventDates`
 var currentDate = currentDate = new Date();
 $picker.data('datepicker').selectDate(new Date(currentDate.getFullYear(), currentDate.getMonth(), 10))
+

Выбор времени

Для выбора времени используйте опцию{timepicker: true}- она добавит время и пару ползунков, с помощью которых можно уставноить часы и минуты.

По умолчанию будет установлено текущее время на компьюетере пользователя, это значение можно изменять параметромstartDate.

Пример
<div class="datepicker-here" data-timepicker="true"></div>

Подробнее о параметрах выбора времени можно почитать в Опциях.

Формат времени

Формат времени задается в объекте локализации, либо в парамтреtimeFormat. По умолчанию используется 24-х часовой формат. Для выбора 12-ти часового формата вtimeFormatнужно добавить символaaилиAA. После чего в виджете появятся обозочения 'AM' или 'PM', в зависимости от выбранного периода времени.

Пример
<div class="datepicker-here" data-timepicker="true" data-time-format='hh:ii aa'></div>
+

Действия со временем

Для задания максимально/минимально возможных значений часов или минут используйте параметрыmaxHours,minHours,maxMinutes,minMinutes. Также время можно указывать в парамтерахminDateиmaxDate

Давайте создадим календарь, где пользователь может выбрать время с 09:00 до 18:00, а в субботу и воскресенье с 10:00 до 16:00.

Пример
<input type='text' id='timepicker-actions-exmpl' />
+<script>
+	// Зададим стартовую дату
+	var start = new Date(),
+		startHours = 9;
+
+	// 09:00
+	start.setHours(9);
+	start.setMinutes(0);
+
+	// Если сегодня суббота или воскресенье - 10:00
+	if ([6,0].indexOf(start.getDay()) != -1) {
+		start.setHours(10);
+		startHours = 10
+	}
+
+	$('#timepicker-actions-exmpl').datepicker({
+		timepicker: true,
+		startDate: start,
+		minHours: startHours,
+		maxHours: 18,
+		onSelect: function(fd, d, picker) {
+			// Ничего не делаем если выделение было снято
+			if (!d) return;
+
+			var day = d.getDay();
+			// Если выбранный день суббота или воскресенье, то устанавливаем
+			// часы для выходных, в противном случае восстанавливаем начальные значения
+			if (day == 6 || day == 0) {
+				picker.update({
+					minHours: 10,
+					maxHours: 16
+				})
+			} else {
+				picker.update({
+					minHours: 9,
+					maxHours: 18
+				})
+			}
+		}
+	})
+</script>
+
 

Локализация

Вы можете добавить свою локализацию в объектDatepicker.language["my-lang"]и при вызове календаря передать название языка в параметрlanguage

Datepicker.language['my-lang'] = {...}
 
 $('.my-datepicker').datepicker({
@@ -145,13 +227,18 @@
 	today: 'Сегодня',
 	clear: 'Очистить',
 	dateFormat: 'dd.mm.yyyy',
+	timeFormat: 'hh:ii',
 	firstDay: 1
 };
 

Опции

classes

Типstring

Значение по умолчанию""

Дополнительные классы для календаря.

inline

Типboolean

Значение по умолчаниюfalse

Если true, то календарь будет виден постоянно.

language

Типstring|object

Значение по умолчанию"ru"

Язык календаря. Если передается строка, то поиск языка будет осуществляться в объектеDatepicker.languageЕсли передан объект, то данные будут браться из него.

Если в объекте локализации не будет хватать каких то полей, то они будут взяты из языка по умолчанию.

startDate

ТипDate

Значение по умолчаниюnew Date()

Дата, которая будет отображаться при инициализации календаря.

firstDay

Типnumber

Значение по умолчанию""

Индекс дня, с которого начинается неделя. Возможные значение от 0 до 6, где 0 - воскресенье и 6 - суббота. По умолчанию берется из локализации, если значение передать сюда, то оно будет иметь больший приоритет.

weekends

Типarray

Значение по умолчанию[6, 0]

Массив индексов дней, которые будут считаться выходными днями. Им будет добавлен класс.-weekend-. По умолчанию это суббота и воскресенье.

dateFormat

Типstring

Значение по умолчанию""

Желаемый формат даты, кобминация из d, m, yyyy, D, M, и т.д. По умолчанию берется из локализации, если передать значение сюда, то оно будет иметь больший приоритет.

  • @- время в миллесекундах
  • d- дата
  • dd- дата с лидирующем нулем
  • D- сокращенное наименование дня
  • DD- полное наименование дня
  • m- номер мясяца
  • mm- номер месяца с лидирующем нулем
  • M- сокращенное наименовение месяца
  • MM- полное наименовение месяца
  • yy- сокращенный номер года
  • yyyy- полный номер года
  • yyyy1- первый год декады, в которую входит текущий год
  • yyyy2- последний год декады, в которую входит текущий год

altField

Типstring|jQuery

Значение по умолчанию""

Альтернативное поле воода в значение которого будут попадать выбранные даты с форматомaltFieldDateFormat.

altFieldDateFormat

Типstring

Значение по умолчанию"@"

Формат даты для альтернативного поля.

toggleSelected

Типboolean

Значение по умолчаниюtrue

Если true, то клик на выделенной дате снимет выделение.

keyboardNav

Типboolean

Значение по умолчаниюtrue

Если true, то по календарю можно будет осуществлять навигацию с помощью клавиатуры.

Сочетания клавиш:

  • Ctrl + → | ↑- переход на месяц вперед
  • Ctrl + ← | ↓- переход на месяц назад
  • Shift + → | ↑- переход на год вперед
  • Shift + ← | ↓- переход на год назад
  • Alt + → | ↑- переход на 10 лет вперед
  • Alt + ← | ↓- переход на 10 лет назад
  • Ctrl + Shift + ↑- переход на следующий вид
  • Esc- закрывает календарь

position

Типstring

Значение по умолчанию"bottom left"

Позиционирование календаря отностиельно текстового поля. Первым значением задается основная ось позиционирования, воторым - положение на этой оси. Например{position: "right top"}- утсановит позицию клаендаря справа вверху от текстового поля.

offset

Типnumber

Значение по умолчанию12

Отступ от основной оси позиционирования.

view

Типstring

Значение по умолчанию"days"

Начальный вид календаря. Возможноые значения:

  • days- отображение дней месяца
  • months- отображение месяцев одного года
  • years- отображение годов одной декады

minView

Типstring

Значение по умолчанию"days"

Минимальное представление календаря, по наступлению которого, выбор ячейки приведет к ее активации, а не переходу к следующему виду. -Возможные значения такие же как и у параметраview.

showOtherMonths

Типboolean

Значение по умолчаниюtrue

Если true, то будут отображаться дни других месяцев.

selectOtherMonths

Типboolean

Значение по умолчаниюtrue

Если true, то можно будет выбрать дни из других месяцев.

moveToOtherMonthsOnSelect

Типboolean

Значение по умолчаниюtrue

Если true, то при выборе дней из других месяца, будет осуществялться переход к этому месяцу.

showOtherYears

Типboolean

Значение по умолчаниюtrue

Если true, то при отображении декады, будут показаны годы из других декад.

selectOtherYears

Типboolean

Значение по умолчаниюtrue

Если true, то можно будет выбрать года из других декад

moveToOtherYearsOnSelect

Типboolean

Значение по умолчаниюtrue

Если true, то при выборе года из другой декады, будет осуществлен переход к этой декаде.

minDate

ТипDate

Значение по умолчанию""

Минимальная дата для возможности выбора. Все даты, идущее до нее нельзя будет активировать.

maxDate

ТипDate

Значение по умолчанию""

Максимальная дата для возможности выбора. Все даты, идущее после нее нельзя будет выбрать.

disableNavWhenOutOfRange

Типboolean

Значение по умолчаниюtrue

Если true, то при наступлении даты, которая была бы меньше минимально возможной или больше максимально возможной, деактвировались бы кнопки навигации 'вперед', 'назад'

multipleDates

Типboolean|number

Значение по умолчаниюfalse

Если true, то можно будет выбрать неограниченное количество дат. Если передать число, то количество выбираемых дат будет ограниченно этим числом.

multipleDatesSeparator

Типstring

Значение по умолчанию","

Разделитель дат, который будет использован при объеденения нескольких дат в одну строку.

range

Типboolean

Значение по умолчаниюfalse

Если true, то будет включен режим выбора диапазона дат. В качестве разделителя будет использованmultipleDatesSeparator

todayButton

Типboolean

Значение по умолчаниюfalse

Если true, то будет отображена кнопка "Сегодня".

clearButton

Типboolean

Значение по умолчаниюfalse

Если true, то будет отображена кнопка "Очистить".

showEvent

Типstring

Значение по умолчанию"focus"

Тип события, по наступлению которого будет показан календарь.

autoClose

Типboolean

Значение по умолчаниюfalse

Если true, то при активации даты, календарь закроется.

prevHtml

Типstring

Значение по умолчанию<svg><path d="M 17,12 l -5,5 l 5,5"></path></svg>

Контент кнопки 'предыдущий месяц|год|декада'.

nextHtml

Типstring

Значение по умолчанию<svg><path d="M 14,12 l 5,5 l -5,5"></path></svg>

Контент кнопки 'следующий месяц|год|декада'.

navTitles

Типobject

Значение по умолчанию

navTitles = {
+Возможные значения такие же как и у параметраview.

showOtherMonths

Типboolean

Значение по умолчаниюtrue

Если true, то будут отображаться дни других месяцев.

selectOtherMonths

Типboolean

Значение по умолчаниюtrue

Если true, то можно будет выбрать дни из других месяцев.

moveToOtherMonthsOnSelect

Типboolean

Значение по умолчаниюtrue

Если true, то при выборе дней из других месяца, будет осуществялться переход к этому месяцу.

showOtherYears

Типboolean

Значение по умолчаниюtrue

Если true, то при отображении декады, будут показаны годы из других декад.

selectOtherYears

Типboolean

Значение по умолчаниюtrue

Если true, то можно будет выбрать года из других декад

moveToOtherYearsOnSelect

Типboolean

Значение по умолчаниюtrue

Если true, то при выборе года из другой декады, будет осуществлен переход к этой декаде.

minDate

ТипDate

Значение по умолчанию""

Минимальная дата для возможности выбора. Все даты, идущее до нее нельзя будет активировать.

maxDate

ТипDate

Значение по умолчанию""

Максимальная дата для возможности выбора. Все даты, идущее после нее нельзя будет выбрать.

disableNavWhenOutOfRange

Типboolean

Значение по умолчаниюtrue

Если true, то при наступлении даты, которая была бы меньше минимально возможной или больше максимально возможной, деактвировались бы кнопки навигации 'вперед', 'назад'

multipleDates

Типboolean|number

Значение по умолчаниюfalse

Если true, то можно будет выбрать неограниченное количество дат. Если передать число, то количество выбираемых дат будет ограниченно этим числом.

multipleDatesSeparator

Типstring

Значение по умолчанию","

Разделитель дат, который будет использован при объеденения нескольких дат в одну строку.

range

Типboolean

Значение по умолчаниюfalse

Если true, то будет включен режим выбора диапазона дат. В качестве разделителя будет использованmultipleDatesSeparator

todayButton

Типboolean|Date

Значение по умолчаниюfalse

Если true, то будет отображена кнопка "Сегодня". Если передать объект даты, то при клике по кнопке будет осуществлен переход и последующий выбор этой даты.

// Выбор сегодняшнего дня
+$('.datepicker').datepicker({
+	todayButton: new Date()
+})
+

clearButton

Типboolean

Значение по умолчаниюfalse

Если true, то будет отображена кнопка "Очистить".

showEvent

Типstring

Значение по умолчанию"focus"

Тип события, по наступлению которого будет показан календарь.

autoClose

Типboolean

Значение по умолчаниюfalse

Если true, то при активации даты, календарь закроется.

prevHtml

Типstring

Значение по умолчанию<svg><path d="M 17,12 l -5,5 l 5,5"></path></svg>

Контент кнопки 'предыдущий месяц|год|декада'.

nextHtml

Типstring

Значение по умолчанию<svg><path d="M 14,12 l 5,5 l -5,5"></path></svg>

Контент кнопки 'следующий месяц|год|декада'.

navTitles

Типobject

Значение по умолчанию

navTitles = {
 	days: 'MM, <i>yyyy</i>',
 	months: 'yyyy',
 	years: 'yyyy1 - yyyy2'
@@ -159,7 +246,8 @@
 	navTitles: {
 		days: '<h3>Выберете дату заезда</h3> MM, yyyy'
 	}
-})

monthsField

Типstring

Значение по умолчанию"monthsShort"

Какое поле из объекта локализации использовать в качестве названий месяцев, когдаview = "months".

События

onSelect(formattedDate, date, inst)

Типfunction

Значение по умолчаниюnull

Функция обратного вызова при выборе даты.

  • formattedDatestring- отформатированная дата.
  • dateDate|array- объектDateвыбранной даты, если{multipleDates: true}, то будет передан массив таких объектов.
  • instobject- экземпляр плагина.

onChangeMonth(month, year)

Типfunction

Значение по умолчаниюnull

Функция обратного вызова при изменении месяца.

  • monthnumber- номер месяца (от 0 до 12), к которому осуществлен переход.
  • yearnumber- номер года, к которому осуществлен переход.

onChangeYear(year)

Типfunction

Значение по умолчаниюnull

Функция обратного вызова при изменении года.

  • yearnumber- номер года, к которому осуществлен переход

onChangeDecade(decade)

Типfunction

Значение по умолчаниюnull

Функция обратного вызова при изменении декады.

  • decadearray- массив, состоящий из номера года с которого начинается декада, и года на котором она заканчивается.

onChangeView(view)

Типfunction

Значение по умолчаниюnull

Функция обратного вызова при изменении вида календаря

  • viewstring- вид, к которому осуществлен переход (days, months, years).

onRenderCell(date, cellType)

Типfunction

Значение по умолчаниюnull

Функция обратного вызова при отрисовке ячейки календаря.

  • dateDate- объект даты текущей ячейки
  • cellTypestring- тип текущей ячейки (day, month, year).

Функция должна возвращать объект, которой может состоять из трех полей:

{
+})

monthsField

Типstring

Значение по умолчанию"monthsShort"

Какое поле из объекта локализации использовать в качестве названий месяцев, когдаview = "months".

timepicker

Типboolean

Значение по умолчаниюfalse

Еслиtrue, то будет добавлена возомжность выбора времени.

dateTimeSeparator

Типstring

Значение по умолчанию" "

Разделитель между датой и временем.

timeFormat

Типstring

Значение по умолчаниюnull

Формат времени. По умолчанию берется из локализации. Если передать значение сюда, то оно будет иметь больший приоритет. +Для включения 12-ти часового режима добавьте 'aa' или 'AA' в параметрtimeFormat, например{timeFormat: "hh:ii AA"}Возможные варианты:

  • h- часы
  • hh- часы, с лидирующим нулем
  • i- минуты
  • ii- минуты, с лидирующим нулем
  • aa- период дня - 'am' или 'pm'
  • AA- период дня заглавными буквами

minHours

Типnumber

Значение по умолчанию0

Минимальное значение часов от 0 до 23. Нельзя выбрать час меньше, чем переданное значение.

maxHours

Типnumber

Значение по умолчанию23

Максимальное значение часов от 0 до 23. Нельзя выбрать час больше, чем переданное значение.

minMinutes

Типnumber

Значение по умолчанию0

Минимальное значение часов от 0 до 59. Нельзя вустановить значение минут меньше, чем переданное значение.

maxMinutes

Типnumber

Значение по умолчанию59

Максимальное значение минут от 0 до 59. Нельзя вустановить значение минут больше, чем переданное значение.

hoursStep

Типnumber

Значение по умолчанию1

Шаг выбора часов.

minutesStep

Типnumber

Значение по умолчанию1

Шаг выбора минут.

События

onSelect(formattedDate, date, inst)

Типfunction

Значение по умолчаниюnull

Функция обратного вызова при выборе даты.

  • formattedDatestring- отформатированная дата.
  • dateDate|array- объектDateвыбранной даты, если{multipleDates: true}, то будет передан массив таких объектов.
  • instobject- экземпляр плагина.

onChangeMonth(month, year)

Типfunction

Значение по умолчаниюnull

Функция обратного вызова при изменении месяца.

  • monthnumber- номер месяца (от 0 до 12), к которому осуществлен переход.
  • yearnumber- номер года, к которому осуществлен переход.

onChangeYear(year)

Типfunction

Значение по умолчаниюnull

Функция обратного вызова при изменении года.

  • yearnumber- номер года, к которому осуществлен переход

onChangeDecade(decade)

Типfunction

Значение по умолчаниюnull

Функция обратного вызова при изменении декады.

  • decadearray- массив, состоящий из номера года с которого начинается декада, и года на котором она заканчивается.

onChangeView(view)

Типfunction

Значение по умолчаниюnull

Функция обратного вызова при изменении вида календаря

  • viewstring- вид, к которому осуществлен переход (days, months, years).

onRenderCell(date, cellType)

Типfunction

Значение по умолчаниюnull

Функция обратного вызова при отрисовке ячейки календаря.

  • dateDate- объект даты текущей ячейки
  • cellTypestring- тип текущей ячейки (day, month, year).

Функция должна возвращать объект, которой может состоять из трех полей:

{
 	html: '', // Кастомный контент ячейки
 	classes: '', // Дополнительные классы для ячейки
 	disabled: '' // true/false, если true, то ячейку нельзя будет выбрать
diff --git a/docs/index.html b/docs/index.html
index c2970808..d972c3cb 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -1,7 +1,7 @@
 Air Datepicker
На русском языке

AIR DATEPICKERlightweight cross-browser jQuery datepicker

Description

Light (~26kb minified js file and ~7kb gziped) customizable cross-browser calendar, built withes5andcss flexbox.Works in all modern browsers: +})

Description

Light (~34kb minified js file and ~9kb gziped) customizable cross-browser calendar, built withes5andcss flexbox.Works in all modern browsers: IE 10+, Chrome, Firefox, Safari 8+, Opera 17+.

Installation

bower i --save air-datepicker

Or you can download files directly from GitHub

Usage

Include styles and scripts from/distdirectory:

<html>
 	<head>
 		<link href="dist/css/datepicker.min.css" rel="stylesheet" type="text/css">
@@ -128,6 +128,89 @@
 // Select initial date from `eventDates`
 var currentDate = currentDate = new Date();
 $picker.data('datepicker').selectDate(new Date(currentDate.getFullYear(), currentDate.getMonth(), 10))
+

Timepicker

To enable timepicker use option{timepicker: true}- it will add current time and a couple of range sliders by which one can pick time.

By default current user time will be set. This value can be changed bystartDateparameter.

Example
<div class="datepicker-here" data-timepicker="true" data-language='en'></div>

More detailed info about timepicker parameters you can find in Options.

Time format

Time format is defined in localization object or intimeFormatparameter. By default (in Russian language) 24 hours format is used. For enabling 12 hours mode you must addaaorAAsymbol intimeFormat. After what 'AM' and 'PM' sings will appear in timepicker widget.

Lets use 12 hours mode in Russian language:

Example
<div class="datepicker-here" data-timepicker="true" data-time-format='hh:ii aa'></div>
+

Actions with time

For setting max/min hours or minutes values usemaxHours,minHours,maxMinutes,minMinutes. You also could set time inminDateandmaxDate. For setting hours you must use values between 0 and 23, event if 12 hours mode is on. Plugin will automatically transform given values to 12 hours format.

Lets create calendar where user can choose time between 09:00 am and 06:00 pm on working days and on Saturday and Sunday between from 10:00 am to 04:00 pm.

Example
<input type='text' id='timepicker-actions-exmpl' />
+<script>
+	// Create start date
+	var start = new Date(),
+		startHours = 9;
+
+	// 09:00 AM
+	start.setHours(9);
+	start.setMinutes(0);
+
+	// If today is Saturday or Sunday set 10:00 AM
+	if ([6, 0].indexOf(start.getDay()) != -1) {
+		start.setHours(10);
+		startHours = 10
+	}
+
+	$('#timepicker-actions-exmpl').datepicker({
+		timepicker: true,
+		language: 'en',
+		startDate: start,
+		minHours: startHours,
+		maxHours: 18,
+		onSelect: function (fd, d, picker) {
+			// Do nothing if selection was cleared
+			if (!d) return;
+
+			var day = d.getDay();
+			// If chosen day is Saturday or Sunday when set
+			// hour value for weekends, else restore defaults
+			if (day == 6 || day == 0) {
+				picker.update({
+					minHours: 10,
+					maxHours: 16
+				})
+			} else {
+				picker.update({
+					minHours: 9,
+					maxHours: 18
+				})
+			}
+		}
+	})
+</script>
 

Localization

You can add your localization to objectDatepicker.language["my-lang"]and pass it name to parameterlanguage

// Add custom localization
 Datepicker.language['my-lang'] = {...}
 
@@ -147,14 +230,18 @@
 	monthsShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
 	today: 'Today',
 	clear: 'Clear',
-	dateFormat: 'mm/dd/yy',
+	dateFormat: 'mm/dd/yyyy',
+	timeFormat: 'hh:ii aa'
 	firstDay: 0
 };

Available localizations located indist/js/i18ndirectory.

Options

classes

Typestring

Defaults""

Extra css classes for datepicker.

inline

Typeboolean

Defaultsfalse

If true, then datepicker will be always visible.

language

Typestring|object

Defaults"ru"

Datepicker's language. If string is passed, then language will be searched inDatepicker.languageobject. If object is passed, then data will be taken from this object directly.

If some fields are missing, they will be taken from default localization object ('Russian').

startDate

TypeDate

Defaultsnew Date()

This date will be shown at first initialization.

firstDay

Typenumber

Defaults""

Day index from which week will be started. Possible values are from 0 to 6, where 0 - Sunday and 6 - Saturday. By default value is taken from current localization, but if it passed here then it will have higher priority.

weekends

Typearray

Defaults[6, 0]

Array of day's indexes which will be considered as weekends. Class.-weekend-will be added to relevant cells. . By default its Saturday and Sunday.

dateFormat

Typestring

Defaults""

Desirable date format. It's combination of d, m, yyyy, D, M, etc. By default value is taken from current localization, but if it passed here, then it will have higher priority.

  • @- time in milliseconds
  • d- date number
  • dd- date with leading zero
  • D- short day name
  • DD- full day name
  • m- month number
  • mm- month number with leading zero
  • M- short month name
  • MM- full month name
  • yy- two digit year number
  • yyyy- four digit year number
  • yyyy1- first year of decade, which included current year
  • yyyy2- last year of decade, which included current year

altField

Typestring|jQuery

Defaults""

Alternative text input. UsealtFieldDateFormatfor date formatting.

altFieldDateFormat

Typestring

Defaults"@"

Date format for alternative field.

toggleSelected

Typeboolean

Defaultstrue

If true, then clicking on selected cell will remove selection.

keyboardNav

Typeboolean

Defaultstrue

If true, then one can navigate through calendar by keyboard.

Hot keys:

  • Ctrl + → | ↑- move one month forwards
  • Ctrl + ← | ↓- move one month backwards
  • Shift + → | ↑- move one year forwards
  • Shift + ← | ↓- move one year backwards
  • Alt + → | ↑- move 10 years forwards
  • Alt + ← | ↓- move 10 years backwards
  • Ctrl + Shift + ↑- move to next view
  • Esc- hides datepicker

position

Typestring

Defaults"bottom left"

Position of datepicker relative to text input. First value is name of main axis, and second is position on that axis. For example{position: "right top"}- will set datepicker's position from right side on top of text input.

offset

Typenumber

Defaults12

Offset from the main positioning axes.

view

Typestring

Defaults"days"

Start datepicker view. Possible values are:

  • days- display days of one month
  • months- display months of one year
  • years- display years of one decade

minView

Typestring

Defaults"days"

Minimal datepicker's view, on that view selecting cells will not trigger rendering next view, instead it will activate it. -Possible values are the same as inview.

showOtherMonths

Typeboolean

Defaultstrue

If true, then days from other months will be visible.

selectOtherMonths

Typeboolean

Defaultstrue

If true, then one can select days form other months.

moveToOtherMonthsOnSelect

Typeboolean

Defaultstrue

If true, then selecting days from other month, will cause transition to that month.

showOtherYears

Typeboolean

Defaultstrue

If true, then years from other decades will be visible.

selectOtherYears

Typeboolean

Defaultstrue

If true, then on can select years from other decades

moveToOtherYearsOnSelect

Typeboolean

Defaultstrue

If true, then selecting year from other decade, will cause transition to that decade.

minDate

TypeDate

Defaults""

The minimum date for selection. All dates, running before it can't be activated.

maxDate

TypeDate

Defaults""

The maximum date for selection. All dates which comes after it cannot be selected.

disableNavWhenOutOfRange

Typeboolean

Defaultstrue

If true, then at the date, which would be less than minimum possible or more then maximum possible, navigation buttons ('forward', 'back') will be deactivated.

multipleDates

Typeboolean|number

Defaultsfalse

If true, then one can select unlimited dates. If number is passed, then amount of selected dates will be limited by it.

multipleDatesSeparator

Typestring

Defaults","

Dates separator, which will be used when concatenating dates to string.

range

Typeboolean

Defaultsfalse

For selecting dates range, turn this option to true.multipleDatesSeparatorwill be used as dates separator.

todayButton

Typeboolean

Defaultsfalse

If true, then button "Today" will be visible.

clearButton

Typeboolean

Defaultsfalse

If true, then button "Clear" will be visible.

showEvent

Typestring

Defaults"focus"

Event type, on which datepicker should be shown.

autoClose

Typeboolean

Defaultsfalse

If true, then after date selection, datepicker will be closed.

prevHtml

Typestring

Defaults<svg><path d="M 17,12 l -5,5 l 5,5"></path></svg>

Contents of 'next' button.

nextHtml

Typestring

Defaults<svg><path d="M 14,12 l 5,5 l -5,5"></path></svg>

Contents of 'prev' button.

navTitles

Typeobject

Defaults

navTitles = {
+Possible values are the same as inview.

showOtherMonths

Typeboolean

Defaultstrue

If true, then days from other months will be visible.

selectOtherMonths

Typeboolean

Defaultstrue

If true, then one can select days form other months.

moveToOtherMonthsOnSelect

Typeboolean

Defaultstrue

If true, then selecting days from other month, will cause transition to that month.

showOtherYears

Typeboolean

Defaultstrue

If true, then years from other decades will be visible.

selectOtherYears

Typeboolean

Defaultstrue

If true, then on can select years from other decades

moveToOtherYearsOnSelect

Typeboolean

Defaultstrue

If true, then selecting year from other decade, will cause transition to that decade.

minDate

TypeDate

Defaults""

The minimum date for selection. All dates, running before it can't be activated.

maxDate

TypeDate

Defaults""

The maximum date for selection. All dates which comes after it cannot be selected.

disableNavWhenOutOfRange

Typeboolean

Defaultstrue

If true, then at the date, which would be less than minimum possible or more then maximum possible, navigation buttons ('forward', 'back') will be deactivated.

multipleDates

Typeboolean|number

Defaultsfalse

If true, then one can select unlimited dates. If number is passed, then amount of selected dates will be limited by it.

multipleDatesSeparator

Typestring

Defaults","

Dates separator, which will be used when concatenating dates to string.

range

Typeboolean

Defaultsfalse

For selecting dates range, turn this option to true.multipleDatesSeparatorwill be used as dates separator.

todayButton

Typeboolean|Date

Defaultsfalse

If true, then button "Today" will be visible. If Date is passed then click event will also select passed date.

// Select today
+$('.datepicker').datepicker({
+	todayButton: new Date()
+})

clearButton

Typeboolean

Defaultsfalse

If true, then button "Clear" will be visible.

showEvent

Typestring

Defaults"focus"

Event type, on which datepicker should be shown.

autoClose

Typeboolean

Defaultsfalse

If true, then after date selection, datepicker will be closed.

prevHtml

Typestring

Defaults<svg><path d="M 17,12 l -5,5 l 5,5"></path></svg>

Contents of 'next' button.

nextHtml

Typestring

Defaults<svg><path d="M 14,12 l 5,5 l -5,5"></path></svg>

Contents of 'prev' button.

navTitles

Typeobject

Defaults

navTitles = {
 	  days: 'MM, <i>yyyy</i>',
 	  months: 'yyyy',
 	  years: 'yyyy1 - yyyy2'
@@ -162,7 +249,8 @@
 	   navTitles: {
 		   days: '<h3>Check in date:</h3> MM, yyyy'
 	   }
-   })

monthsField

Typestring

Defaults"monthsShort"

Field name from localization object which should be used as months names, when view is 'months'.

Events

onSelect(formattedDate, date, inst)

Typefunction

Defaultsnull

Callback when selecting date

  • formattedDatestring- formatted date.
  • dateDate|array- JavaScript Date object + })

monthsField

Typestring

Defaults"monthsShort"

Field name from localization object which should be used as months names, when view is 'months'.

timepicker

Typeboolean

Defaultsfalse

Iftrue, when timepicker widget will be added.

dateTimeSeparator

Typestring

Defaults" "

Separator between date and time

timeFormat

Typestring

Defaultsnull

Desirable time format. Taken from localization by default. If value passed here, then it will be used instead. +For using 12 hours mode, add "aa" or "AA" to yourtimeFormatparameter, e.g.{timeFormat: "hh:ii AA"}Possible values are:

  • h- hours
  • hh- hours with leading zero
  • i- minutes
  • ii- minutes with leading zero
  • aa- day period - 'am' or 'pm'
  • AA- day period capitalized

minHours

Typenumber

Defaults0

Minimal hours value, must be between 0 and 23. You will not be able to choose value lower than this.

maxHours

Typenumber

Defaults23

Maximum hours value, must be between 0 and 23. You will not be able to choose value higher than this.

minMinutes

Typenumber

Defaults0

Minimal minutes value, must be between 0 and 59. You will not be able to choose value lower than this.

maxMinutes

Typenumber

Defaults59

Maximum minutes value, must be between 0 and 59. You will not be able to choose value higher than this.

hoursStep

Typenumber

Defaults1

Hours step in slider.

minutesStep

Typenumber

Defaults1

Minutes step in slider.

Events

onSelect(formattedDate, date, inst)

Typefunction

Defaultsnull

Callback when selecting date

  • formattedDatestring- formatted date.
  • dateDate|array- JavaScript Date object if{multipleDates: true}, then it will be an array of js dates.
  • instobject- plugin instance.

onChangeMonth(month, year)

Typefunction

Defaultsnull

Callback when months are changed.

  • monthnumber- month number (from 0 to 12), to which transition is done.
  • yearnumber- year, to which transition is done.

onChangeYear(year)

Typefunction

Defaultsnull

Callback when year is changed

  • yearnumber- year, to which transition is done.

onChangeDecade(decade)

Typefunction

Defaultsnull

Callback when decade is changed

  • decadearray- array which consists of two years: first year in decade and last year in decade.

onChangeView(view)

Typefunction

Defaultsnull

Callback when datepicker's view is changed

  • viewstring- view name, to which transition is done (days, months, years).

onRenderCell(date, cellType)

Typefunction

Defaultsnull

Callback when datepicker's cell is rendered.

  • dateDate- current cell date
  • cellTypestring- current cell type (day, month, year).

The callback must return object which may consists of three fields:

{
 	html: '', // Custom cell content
 	classes: '', // Extra css classes to cell
diff --git a/docs/jade/mixins/param-header.jade b/docs/jade/mixins/param-header.jade
index 325d0374..c3b1a74d 100644
--- a/docs/jade/mixins/param-header.jade
+++ b/docs/jade/mixins/param-header.jade
@@ -1,10 +1,10 @@
-mixin param-header(name, type, defaults)
+mixin param-header(name, type, defaults, id)
 	-var typeLabel = 'Тип';
 	-var defaultLabel = 'Значение по умолчанию';
 	-if (lang == 'en') {typeLabel = 'Type'; defaultLabel = 'Defaults'};
 
 	header.param-header
-			h3= name
+			h3(id = id)= name
 			if type
 				p.param-header--row
 					span.param-header--label= typeLabel
diff --git a/docs/jade/pages/index-ru.jade b/docs/jade/pages/index-ru.jade
index 9e94d03c..c7791514 100644
--- a/docs/jade/pages/index-ru.jade
+++ b/docs/jade/pages/index-ru.jade
@@ -17,7 +17,7 @@ block content
 	article
 		h2#intro Описание
 		p
-			| Легкий (~26kb минифицированный js файл и ~7kb gziped), кастомизируемый, кроссбраузерный календарь, написан с использованием
+			| Легкий (~34kb минифицированный js файл и ~9kb gziped), кастомизируемый, кроссбраузерный календарь, написан с использованием
 			+example-inline('es5')
 			| и
 			+example-inline('css flexbox', 'js')
@@ -277,6 +277,147 @@ block content
 					var currentDate = currentDate = new Date();
 					$picker.data('datepicker').selectDate(new Date(currentDate.getFullYear(), currentDate.getMonth(), 10))
 
+	article
+		h2#timepicker Выбор времени
+		p Для выбора времени используйте опцию
+			+example-inline('{timepicker: true}', 'js')
+			| - она добавит время и пару ползунков, с помощью которых можно уставноить часы и минуты.
+		p По умолчанию будет установлено текущее время на компьюетере пользователя, это значение можно изменять параметром
+			+example-inline('startDate', 'js')
+			|.
+
+		+example
+			+example-content
+				div.datepicker-here(data-timepicker='true')
+			+example-code
+				:code
+					
+ p + i Подробнее о параметрах выбора времени можно почитать в Опциях. + + + h3#timepicker-format Формат времени + p Формат времени задается в объекте локализации, либо в парамтре + +example-inline('timeFormat', 'js') + |. По умолчанию используется 24-х часовой формат. Для выбора 12-ти часового формата в + +example-inline('timeFormat', 'js') + | нужно добавить символ + +example-inline('aa', 'js') + | или + +example-inline('AA', 'js') + | . После чего в виджете появятся обозочения 'AM' или 'PM', в зависимости от выбранного периода времени. + + +example + +example-content + input.datepicker-here(type='text' data-timepicker='true', data-time-format='hh:ii aa') + +example-code + :code +
+ + h3#timeformat-actions Действия со временем + p Для задания максимально/минимально возможных значений часов или минут используйте параметры + +example-inline('maxHours','js') + |, + +example-inline('minHours','js') + |, + +example-inline('maxMinutes','js') + |, + +example-inline('minMinutes','js') + |. Также время можно указывать в парамтерах + +example-inline('minDate','js') + | и + +example-inline('maxDate','js') + p Давайте создадим календарь, где пользователь может выбрать время с 09:00 до 18:00, а в субботу и воскресенье с 10:00 до 16:00. + + +example + +example-content + input(type='text')#timepicker-actions-exmpl + script. + // Зададим стартовую дату + var start = new Date(), + startHours = 9; + + // 09:00 + start.setHours(9); + start.setMinutes(0); + + // Если сегодня суббота или воскресенье - 10:00 + if ([6,0].indexOf(start.getDay()) != -1) { + start.setHours(10); + startHours = 10 + } + + $('#timepicker-actions-exmpl').datepicker({ + timepicker: true, + startDate: start, + minHours: startHours, + maxHours: 18, + onSelect: function(fd, d, picker) { + // Ничего не делаем если выделение было снято + if (!d) return; + + var day = d.getDay(); + // Если выбранный день суббота или воскресенье, то устанавливаем + // часы для выходных, в противном случае восстанавливаем начальные значения + if (day == 6 || day == 0) { + picker.update({ + minHours: 10, + maxHours: 16 + }) + } else { + picker.update({ + minHours: 9, + maxHours: 18 + }) + } + } + }) + +example-code + :code + + + + article h2#localization Локализация p @@ -317,6 +458,7 @@ block content today: 'Сегодня', clear: 'Очистить', dateFormat: 'dd.mm.yyyy', + timeFormat: 'hh:ii', firstDay: 1 }; @@ -526,8 +668,13 @@ block content p Если true, то будет включен режим выбора диапазона дат. В качестве разделителя будет использован +example-inline('multipleDatesSeparator') .param - +param-header('todayButton', 'boolean', 'false') - p Если true, то будет отображена кнопка "Сегодня". + +param-header('todayButton', 'boolean|Date', 'false') + p Если true, то будет отображена кнопка "Сегодня". Если передать объект даты, то при клике по кнопке будет осуществлен переход и последующий выбор этой даты. + +example-code('js'). + // Выбор сегодняшнего дня + $('.datepicker').datepicker({ + todayButton: new Date() + }) .param +param-header('clearButton', 'boolean', 'false') @@ -575,6 +722,69 @@ block content +example-inline('view = "months"', 'js') | . + .param + +param-header('timepicker', 'boolean', 'false', 'opts-timepicker') + p Если + +example-inline('true') + | , то будет добавлена возомжность выбора времени. + + .param + +param-header('dateTimeSeparator', 'string', '" "', 'opts-dateTimeSeparator') + p Разделитель между датой и временем. + + .param + +param-header('timeFormat', 'string', 'null', 'opts-timeFormat') + p Формат времени. По умолчанию берется из локализации. Если передать значение сюда, то оно будет иметь больший приоритет. + | Для включения 12-ти часового режима добавьте 'aa' или 'AA' в параметр + +example-inline('timeFormat','js') + |, например + +example-inline('{timeFormat: "hh:ii AA"}','js') + | Возможные варианты: + ul + li + +param('h') + | - часы + li + +param('hh') + | - часы, с лидирующим нулем + li + +param('i') + | - минуты + li + +param('ii') + | - минуты, с лидирующим нулем + li + +param('aa') + | - период дня - 'am' или 'pm' + li + +param('AA') + | - период дня заглавными буквами + + .param + +param-header('minHours', 'number', '0', 'opts-minHours') + p Минимальное значение часов от 0 до 23. Нельзя выбрать час меньше, чем переданное значение. + + .param + +param-header('maxHours', 'number', '23', 'opts-maxHours') + p Максимальное значение часов от 0 до 23. Нельзя выбрать час больше, чем переданное значение. + + .param + +param-header('minMinutes', 'number', '0', 'opts-minMinutes') + p Минимальное значение часов от 0 до 59. Нельзя вустановить значение минут меньше, чем переданное значение. + + .param + +param-header('maxMinutes', 'number', '59', 'opts-maxMinutes') + p Максимальное значение минут от 0 до 59. Нельзя вустановить значение минут больше, чем переданное значение. + + .param + +param-header('hoursStep', 'number', '1', 'opts-hoursStep') + p Шаг выбора часов. + + .param + +param-header('minutesStep', 'number', '1', 'opts-minutesStep') + p Шаг выбора минут. + + article h2#events События .param diff --git a/docs/jade/pages/index.jade b/docs/jade/pages/index.jade index edd8b720..430139d4 100644 --- a/docs/jade/pages/index.jade +++ b/docs/jade/pages/index.jade @@ -17,7 +17,7 @@ block content article h2#intro Description p - | Light (~26kb minified js file and ~7kb gziped) customizable cross-browser calendar, built with + | Light (~34kb minified js file and ~9kb gziped) customizable cross-browser calendar, built with +example-inline('es5') | and +example-inline('css flexbox', 'js') @@ -270,6 +270,151 @@ block content var currentDate = currentDate = new Date(); $picker.data('datepicker').selectDate(new Date(currentDate.getFullYear(), currentDate.getMonth(), 10)) + article + h2#timepicker Timepicker + p To enable timepicker use option + +example-inline('{timepicker: true}', 'js') + | - it will add current time and a couple of range sliders by which one can pick time. + p By default current user time will be set. This value can be changed by + +example-inline('startDate', 'js') + | parameter. + + +example + +example-content + div.datepicker-here(data-timepicker='true', data-language='en') + +example-code + :code +
+ p + i More detailed info about timepicker parameters you can find in Options. + + + h3#timepicker-format Time format + p Time format is defined in localization object or in + +example-inline('timeFormat', 'js') + | parameter. By default (in Russian language) 24 hours format is used. For enabling 12 hours mode you must add + +example-inline('aa', 'js') + | or + +example-inline('AA', 'js') + | symbol in + +example-inline('timeFormat', 'js') + |. After what 'AM' and 'PM' sings will appear in timepicker widget. + + p Lets use 12 hours mode in Russian language: + + +example + +example-content + input.datepicker-here(type='text' data-timepicker='true', data-time-format='hh:ii aa') + +example-code + :code +
+ + h3#timeformat-actions Actions with time + p For setting max/min hours or minutes values use + +example-inline('maxHours','js') + | , + +example-inline('minHours','js') + | , + +example-inline('maxMinutes','js') + | , + +example-inline('minMinutes','js') + | . You also could set time in + +example-inline('minDate','js') + | and + +example-inline('maxDate','js') + |. For setting hours you must use values between 0 and 23, event if 12 hours mode is on. Plugin will automatically transform given values to 12 hours format. + p Lets create calendar where user can choose time between 09:00 am and 06:00 pm on working days and on Saturday and Sunday between from 10:00 am to 04:00 pm. + + +example + +example-content + input(type='text')#timepicker-actions-exmpl + script. + // Create start date + var start = new Date(), + startHours = 9; + + // 09:00 AM + start.setHours(9); + start.setMinutes(0); + + // If today is Saturday or Sunday set 10:00 AM + if ([6, 0].indexOf(start.getDay()) != -1) { + start.setHours(10); + startHours = 10 + } + + $('#timepicker-actions-exmpl').datepicker({ + timepicker: true, + language: 'en', + startDate: start, + minHours: startHours, + maxHours: 18, + onSelect: function (fd, d, picker) { + // Do nothing if selection was cleared + if (!d) return; + + var day = d.getDay(); + // If chosen day is Saturday or Sunday when set + // hour value for weekends, else restore defaults + if (day == 6 || day == 0) { + picker.update({ + minHours: 10, + maxHours: 16 + }) + } else { + picker.update({ + minHours: 9, + maxHours: 18 + }) + } + } + }) + +example-code + :code + + + article h2#localization Localization p @@ -306,7 +451,8 @@ block content monthsShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], today: 'Today', clear: 'Clear', - dateFormat: 'mm/dd/yy', + dateFormat: 'mm/dd/yyyy', + timeFormat: 'hh:ii aa' firstDay: 0 }; p Available localizations located in @@ -499,8 +645,13 @@ block content +example-inline('multipleDatesSeparator') | will be used as dates separator. .param - +param-header('todayButton', 'boolean', 'false') - p If true, then button "Today" will be visible. + +param-header('todayButton', 'boolean|Date', 'false') + p If true, then button "Today" will be visible. If Date is passed then click event will also select passed date. + +example-code('js'). + // Select today + $('.datepicker').datepicker({ + todayButton: new Date() + }) .param +param-header('clearButton', 'boolean', 'false') p If true, then button "Clear" will be visible. @@ -540,6 +691,69 @@ block content +param-header('monthsField','string','"monthsShort"') p Field name from localization object which should be used as months names, when view is 'months'. + .param + +param-header('timepicker', 'boolean', 'false', 'opts-timepicker') + p If + +example-inline('true') + | , when timepicker widget will be added. + + .param + +param-header('dateTimeSeparator', 'string', '" "', 'opts-dateTimeSeparator') + p Separator between date and time + + .param + +param-header('timeFormat', 'string', 'null', 'opts-timeFormat') + p + | Desirable time format. Taken from localization by default. If value passed here, then it will be used instead. + | For using 12 hours mode, add "aa" or "AA" to your + +example-inline('timeFormat','js') + | parameter, e.g. + +example-inline('{timeFormat: "hh:ii AA"}','js') + | Possible values are: + ul + li + +param('h') + | - hours + li + +param('hh') + | - hours with leading zero + li + +param('i') + | - minutes + li + +param('ii') + | - minutes with leading zero + li + +param('aa') + | - day period - 'am' or 'pm' + li + +param('AA') + | - day period capitalized + + .param + +param-header('minHours', 'number', '0', 'opts-minHours') + p Minimal hours value, must be between 0 and 23. You will not be able to choose value lower than this. + + .param + +param-header('maxHours', 'number', '23', 'opts-maxHours') + p Maximum hours value, must be between 0 and 23. You will not be able to choose value higher than this. + + .param + +param-header('minMinutes', 'number', '0', 'opts-minMinutes') + p Minimal minutes value, must be between 0 and 59. You will not be able to choose value lower than this. + + .param + +param-header('maxMinutes', 'number', '59', 'opts-maxMinutes') + p Maximum minutes value, must be between 0 and 59. You will not be able to choose value higher than this. + + .param + +param-header('hoursStep', 'number', '1', 'opts-hoursStep') + p Hours step in slider. + + .param + +param-header('minutesStep', 'number', '1', 'opts-minutesStep') + p Minutes step in slider. + article h2#events Events .param diff --git a/docs/js/navigation.js b/docs/js/navigation.js index 93d6286c..935b7ff0 100644 --- a/docs/js/navigation.js +++ b/docs/js/navigation.js @@ -60,7 +60,6 @@ var navigation; var id, title, subTitles, - subId, $subTitle, $current; @@ -80,8 +79,13 @@ var navigation; cache[id].subSections = {}; subTitles.each(function () { - subId = idPrefix + idCounter++; - $subTitle = $(this).attr('id', subId); + var $subTitle = $(this), + subId = $(this).attr('id'); + + if (!subId) { + subId = idPrefix + idCounter++; + $subTitle.attr('id', subId); + } cache[id].subSections[subId] = { title: $subTitle.text(), diff --git a/docs/sass/_docs.scss b/docs/sass/_docs.scss index dc5e92c3..1a6f79d8 100644 --- a/docs/sass/_docs.scss +++ b/docs/sass/_docs.scss @@ -438,4 +438,72 @@ a { background: #fff; opacity: .5; } +} + +// Visual tests +// ------------------------------------------------- + +.visual-tests { + padding-top: 12px; + padding-bottom: 120px; + + h1 { + color: #555; + font-size: 20px; + margin: 0; + padding-left: 16px; + } + + .row { + border-bottom: 1px solid #eee; + display: flex; + flex-wrap: wrap; + margin-bottom: 16px; + + + } + + article:last-child { + .row { + border: none; + } + } +} + +.vt-tile { + padding: 16px; + width: 284px; + + input { + width: 100%; + } + + h2 { + font-family: monospace; + font-size: 14px; + margin: 0 0 8px; + text-align: center; + } +} + +.v-log { + position: fixed; + padding: 8px; + font-size: 12px; + font-family: monospace; + background: rgba(0, 0, 0, .7); + height: 100px; + width: 100%; + bottom: 0; + overflow: auto; + z-index: 10; + + p { + margin: 0; + color: greenyellow; + } + + span { + color: #ddd; + } } \ No newline at end of file diff --git a/gulpfile.js b/gulpfile.js index 8b76f394..94e8da2b 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -30,6 +30,9 @@ gulp.task('watch', function () { }); }); +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 index 57ab18ec..564b0281 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,9 @@ { "name": "air-datepicker", - "version": "1.2.1", + "version": "2.0.0", "devDependencies": { "autoprefixer": "^6.1.0", + "browserify": "^13.0.0", "chai": "^3.4.1", "gulp": "^3.9.0", "gulp-clone": "^1.0.0", @@ -19,6 +20,34 @@ "gulp-watch": "^4.3.5", "gulp-wrap": "^0.11.0", "jade": "^1.11.0", - "mocha": "^2.3.4" - } + "mocha": "^2.3.4", + "node-static": "^0.7.7", + "vinyl-source-stream": "^1.1.0" + }, + "dependencies": { + "jquery": "^2.2.3" + }, + "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)", + "main": "src/js/air-datepicker.js", + "directories": { + "doc": "docs", + "test": "tests" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/t1m0n/air-datepicker.git" + }, + "keywords": [ + "datepicker", + "timepicker", + "plugin", + "customizable", + "powerful" + ], + "author": "t1m0n ", + "license": "MIT", + "bugs": { + "url": "https://github.com/t1m0n/air-datepicker/issues" + }, + "homepage": "http://t1m0n.name/air-datepicker/docs/" } diff --git a/src/js/air-datepicker.js b/src/js/air-datepicker.js new file mode 100644 index 00000000..4c617835 --- /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 index f219b810..52bc158a 100644 --- a/src/js/body.js +++ b/src/js/body.js @@ -14,9 +14,10 @@ '
' + '
' }, - D = Datepicker; + datepicker = $.fn.datepicker, + dp = datepicker.Constructor; - D.Body = function (d, type, opts) { + datepicker.Body = function (d, type, opts) { this.d = d; this.type = type; this.opts = opts; @@ -24,7 +25,7 @@ this.init(); }; - D.Body.prototype = { + datepicker.Body.prototype = { init: function () { this._buildBaseHtml(); this._render(); @@ -60,7 +61,7 @@ currentDate = new Date(), parent = this.d, opts = parent.opts, - d = D.getParsedDate(date), + d = dp.getParsedDate(date), render = {}, html = d.date; @@ -104,34 +105,34 @@ } if (opts.range) { - if (D.isSame(parent.minRange, date, type)) classes += ' -range-from-'; - if (D.isSame(parent.maxRange, date, type)) classes += ' -range-to-'; + if (dp.isSame(parent.minRange, date, type)) classes += ' -range-from-'; + if (dp.isSame(parent.maxRange, date, type)) classes += ' -range-to-'; if (parent.selectedDates.length == 1 && parent.focused) { if ( - (D.bigger(parent.minRange, date) && D.less(parent.focused, date)) || - (D.less(parent.maxRange, date) && D.bigger(parent.focused, date))) + (dp.bigger(parent.minRange, date) && dp.less(parent.focused, date)) || + (dp.less(parent.maxRange, date) && dp.bigger(parent.focused, date))) { classes += ' -in-range-' } - if (D.less(parent.maxRange, date) && D.isSame(parent.focused, date)) { + if (dp.less(parent.maxRange, date) && dp.isSame(parent.focused, date)) { classes += ' -range-from-' } - if (D.bigger(parent.minRange, date) && D.isSame(parent.focused, date)) { + if (dp.bigger(parent.minRange, date) && dp.isSame(parent.focused, date)) { classes += ' -range-to-' } } else if (parent.selectedDates.length == 2) { - if (D.bigger(parent.minRange, date) && D.less(parent.maxRange, date)) { + if (dp.bigger(parent.minRange, date) && dp.less(parent.maxRange, date)) { classes += ' -in-range-' } } } - if (D.isSame(currentDate, date, type)) classes += ' -current-'; - if (parent.focused && D.isSame(date, parent.focused, type)) classes += ' -focus-'; + 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-'; @@ -148,7 +149,7 @@ * @private */ _getDaysHtml: function (date) { - var totalMonthDays = D.getDaysCount(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, @@ -188,7 +189,7 @@ */ _getMonthsHtml: function (date) { var html = '', - d = D.getParsedDate(date), + d = dp.getParsedDate(date), i = 0; while(i < 12) { @@ -206,8 +207,8 @@ }, _getYearsHtml: function (date) { - var d = D.getParsedDate(date), - decade = D.getDecade(date), + var d = dp.getParsedDate(date), + decade = dp.getDecade(date), firstYear = decade[0] - 1, html = '', i = firstYear; @@ -290,9 +291,15 @@ alreadySelected = this.d._isSelected(selectedDate, this.d.cellType); if (!alreadySelected) { - this.d.selectDate(selectedDate); + this.d._trigger('clickCell', selectedDate); } else if (alreadySelected && this.opts.toggleSelected){ this.d.removeDate(selectedDate); + } else if (alreadySelected && !this.opts.toggleSelected) { + this.d.lastSelectedDate = alreadySelected; + if (this.d.opts.timepicker) { + this.d.timepicker._setTime(alreadySelected); + this.d.timepicker.update(); + } } }, diff --git a/src/js/datepicker.js b/src/js/datepicker.js index 6bf9c765..388f95e1 100644 --- a/src/js/datepicker.js +++ b/src/js/datepicker.js @@ -1,6 +1,4 @@ -window.Datepicker = ''; - -(function () { +;(function () { var pluginName = 'datepicker', autoInitSelector = '.datepicker-here', $body, $datepickersContainer, @@ -62,6 +60,17 @@ window.Datepicker = ''; years: 'yyyy1 - yyyy2' }, + // timepicker + timepicker: false, + dateTimeSeparator: ' ', + timeFormat: '', + minHours: 0, + maxHours: 24, + minMinutes: 0, + maxMinutes: 59, + hoursStep: 1, + minutesStep: 1, + // events onSelect: '', onChangeMonth: '', @@ -87,7 +96,7 @@ window.Datepicker = ''; }, datepicker; - Datepicker = function (el, options) { + var Datepicker = function (el, options) { this.el = el; this.$el = $(el); @@ -121,6 +130,7 @@ window.Datepicker = ''; this.keys = []; this.minRange = ''; this.maxRange = ''; + this._prevOnSelectValue = ''; this.init() }; @@ -155,11 +165,17 @@ window.Datepicker = ''; this.$datepicker.addClass(this.opts.classes) } - this.views[this.currentView] = new Datepicker.Body(this, this.currentView, this.opts); + if (this.opts.timepicker) { + this.timepicker = new $.fn.datepicker.Timepicker(this, this.opts); + this._bindTimepickerEvents(); + } + + this.views[this.currentView] = new $.fn.datepicker.Body(this, this.currentView, this.opts); this.views[this.currentView].show(); - this.nav = new Datepicker.Navigation(this, this.opts); + 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)); @@ -173,9 +189,11 @@ window.Datepicker = ''; _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('input.adp', this._onInput.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 () { @@ -184,30 +202,49 @@ window.Datepicker = ''; 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 = Datepicker.language[lang]; + 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, {}, Datepicker.language.ru) + this.loc = $.extend(true, {}, $.fn.datepicker.language.ru) } - this.loc = $.extend(true, {}, Datepicker.language.ru, Datepicker.language[lang]) + this.loc = $.extend(true, {}, $.fn.datepicker.language.ru, $.fn.datepicker.language[lang]) } else { - this.loc = $.extend(true, {}, Datepicker.language.ru, lang) + 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); + } + + var boundary = this._getWordBoundaryRegExp; + if (this.loc.timeFormat.match(boundary('aa')) || + this.loc.timeFormat.match(boundary('AA')) + ) { + this.ampm = true; + } }, _buildDatepickersContainer: function () { @@ -237,6 +274,9 @@ window.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); } @@ -244,7 +284,13 @@ window.Datepicker = ''; parsedSelected = datepicker.getParsedDate(selectedDates[0]), formattedDates, _this = this, - dates = new Date(parsedSelected.year, parsedSelected.month, parsedSelected.date); + dates = new Date( + parsedSelected.year, + parsedSelected.month, + parsedSelected.date, + parsedSelected.hours, + parsedSelected.minutes + ); formattedDates = selectedDates.map(function (date) { return _this.formatDate(_this.loc.dateFormat, date) @@ -254,10 +300,17 @@ window.Datepicker = ''; 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) + return new Date( + parsedSelected.year, + parsedSelected.month, + parsedSelected.date, + parsedSelected.hours, + parsedSelected.minutes + ); }) } + this._prevOnSelectValue = formattedDates; this.opts.onSelect(formattedDates, dates, this); }, @@ -304,12 +357,28 @@ window.Datepicker = ''; var result = string, boundary = this._getWordBoundaryRegExp, locale = this.loc, + leadingZero = datepicker.getLeadingZeroNum, decade = datepicker.getDecade(date), - d = datepicker.getParsedDate(date); + d = datepicker.getParsedDate(date), + fullHours = d.fullHours, + hours = d.hours, + dayPeriod = 'am', + validHours; + + if (this.opts.timepicker && this.timepicker && this.ampm) { + validHours = this.timepicker._getValidHoursFromDate(date); + 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 = result.replace(boundary('aa'), dayPeriod); + case /AA/.test(result): + result = result.replace(boundary('AA'), dayPeriod.toUpperCase()); case /dd/.test(result): result = result.replace(boundary('dd'), d.fullDate); case /d/.test(result): @@ -326,6 +395,14 @@ window.Datepicker = ''; result = result.replace(boundary('MM'), this.loc.months[d.month]); case /M/.test(result): result = result.replace(boundary('M'), locale.monthsShort[d.month]); + case /ii/.test(result): + result = result.replace(boundary('ii'), d.fullMinutes); + case /i/.test(result): + result = result.replace(boundary('i'), d.minutes); + case /hh/.test(result): + result = result.replace(boundary('hh'), fullHours); + case /h/.test(result): + result = result.replace(boundary('h'), hours); case /yyyy/.test(result): result = result.replace(boundary('yyyy'), d.year); case /yyyy1/.test(result): @@ -351,8 +428,33 @@ window.Datepicker = ''; 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) + } + if (_this.view == 'days') { if (date.getMonth() != d.month && opts.moveToOtherMonthsOnSelect) { newDate = new Date(date.getFullYear(), date.getMonth(), 1); @@ -389,6 +491,11 @@ window.Datepicker = ''; } 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 { @@ -405,7 +512,7 @@ window.Datepicker = ''; _this._triggerOnChange(); } - if (opts.autoClose) { + if (opts.autoClose && !this.timepickerIsActive) { if (!opts.multipleDates && !opts.range) { _this.hide(); } else if (opts.range && _this.selectedDates.length == 2) { @@ -429,6 +536,9 @@ window.Datepicker = ''; if (!_this.selectedDates.length) { _this.minRange = ''; _this.maxRange = ''; + _this.lastSelectedDate = ''; + } else { + _this.lastSelectedDate = _this.selectedDates[_this.selectedDates.length - 1]; } _this.views[_this.currentView]._render(); @@ -448,6 +558,10 @@ window.Datepicker = ''; 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 () { @@ -468,6 +582,7 @@ window.Datepicker = ''; */ update: function (param, value) { var len = arguments.length; + if (len == 2) { this.opts[param] = value; } else if (len == 1 && typeof param == 'object') { @@ -492,6 +607,19 @@ window.Datepicker = ''; this.$datepicker.addClass(this.opts.classes) } + if (this.opts.timepicker) { + this.timepicker._handleDate(this.lastSelectedDate); + this.timepicker._updateRanges(); + this.timepicker._updateCurrentTime(); + // Change hours and minutes if it's values have been changed through min/max hours/minutes + if (this.lastSelectedDate) { + this.lastSelectedDate.setHours(this.timepicker.hours); + this.lastSelectedDate.setMinutes(this.timepicker.minutes); + } + } + + this._setInputValue(); + return this; }, @@ -509,9 +637,14 @@ window.Datepicker = ''; }, _isSelected: function (checkDate, cellType) { - return this.selectedDates.some(function (date) { - return datepicker.isSame(date, checkDate, cellType) - }) + var res = false; + this.selectedDates.some(function (date) { + if (datepicker.isSame(date, checkDate, cellType)) { + res = date; + return true; + } + }); + return res; }, _setInputValue: function () { @@ -911,7 +1044,7 @@ window.Datepicker = ''; } }, - _onShowEvent: function () { + _onShowEvent: function (e) { if (!this.visible) { this.show(); } @@ -929,10 +1062,11 @@ window.Datepicker = ''; _onMouseUpDatepicker: function (e) { this.inFocus = false; - this.$el.focus() + e.originalEvent.inFocus = true; + if (!e.originalEvent.timepickerFocus) this.$el.focus(); }, - _onInput: function () { + _onKeyUpGeneral: function (e) { var val = this.$el.val(); if (!val) { @@ -946,6 +1080,19 @@ window.Datepicker = ''; } }, + _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); @@ -966,6 +1113,10 @@ window.Datepicker = ''; 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.selectDate(this.focused); } else if (alreadySelected && this.opts.toggleSelected){ this.removeDate(this.focused); @@ -1026,6 +1177,37 @@ window.Datepicker = ''; this.silent = false; }, + _onTimeChange: function (e, h, m) { + var date = new Date(), + selectedDates = this.selectedDates, + selected = false; + + if (selectedDates.length) { + selected = true; + date = this.lastSelectedDate; + } + + date.setHours(h); + date.setMinutes(m); + + 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); + } + this.selectDate(date); + }, + set focused(val) { if (!val && this.focused) { var $cell = this._getCell(this.focused); @@ -1086,7 +1268,7 @@ window.Datepicker = ''; if (this.inited) { if (!this.views[val]) { - this.views[val] = new Datepicker.Body(this, val, this.opts) + this.views[val] = new $.fn.datepicker.Body(this, val, this.opts) } else { this.views[val]._render(); } @@ -1141,7 +1323,11 @@ window.Datepicker = ''; 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() + 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() } }; @@ -1184,21 +1370,11 @@ window.Datepicker = ''; return date.getTime() > dateCompareTo.getTime(); }; - Datepicker.language = { - ru: { - days: ['Воскресенье', 'Понедельник', 'Вторник', 'Среда', 'Четверг', 'Пятница', 'Суббота'], - daysShort: ['Вос','Пон','Вто','Сре','Чет','Пят','Суб'], - daysMin: ['Вс','Пн','Вт','Ср','Чт','Пт','Сб'], - months: ['Январь', 'Февраль', 'Март', 'Апрель', 'Май', 'Июнь', 'Июль', 'Август', 'Сентябрь', 'Октябрь', 'Ноябрь', 'Декабрь'], - monthsShort: ['Янв', 'Фев', 'Мар', 'Апр', 'Май', 'Июн', 'Июл', 'Авг', 'Сен', 'Окт', 'Ноя', 'Дек'], - today: 'Сегодня', - clear: 'Очистить', - dateFormat: 'dd.mm.yyyy', - firstDay: 1 - } + datepicker.getLeadingZeroNum = function (num) { + return parseInt(num) < 10 ? '0' + num : num; }; - $.fn[pluginName] = function ( options ) { + $.fn.datepicker = function ( options ) { return this.each(function () { if (!$.data(this, pluginName)) { $.data(this, pluginName, @@ -1212,8 +1388,25 @@ window.Datepicker = ''; }); }; + $.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(); }) -})(); \ 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 00000000..fc63e281 --- /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 index 1ec294d8..6472863a 100644 --- a/src/js/i18n/datepicker.de.js +++ b/src/js/i18n/datepicker.de.js @@ -1,4 +1,4 @@ -Datepicker.language['de'] = { +$.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'], @@ -7,5 +7,6 @@ Datepicker.language['de'] = { 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 index 38dcdd0c..5963553a 100644 --- a/src/js/i18n/datepicker.en.js +++ b/src/js/i18n/datepicker.en.js @@ -1,4 +1,4 @@ -Datepicker.language['en'] = { +$.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'], @@ -6,6 +6,7 @@ Datepicker.language['en'] = { monthsShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], today: 'Today', clear: 'Clear', - dateFormat: 'mm/dd/yy', + dateFormat: 'mm/dd/yyyy', + timeFormat: 'hh:ii aa', firstDay: 0 }; \ 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 00000000..08cfe417 --- /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.pt-BR.js b/src/js/i18n/datepicker.pt-BR.js new file mode 100644 index 00000000..bb076ab9 --- /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 00000000..b9f6a276 --- /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 00000000..f4583416 --- /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.zh.js b/src/js/i18n/datepicker.zh.js index db3a4b40..464bbd52 100644 --- a/src/js/i18n/datepicker.zh.js +++ b/src/js/i18n/datepicker.zh.js @@ -1,4 +1,4 @@ -Datepicker.language['zh'] = { +$.fn.datepicker.language['zh'] = { days: ['周日', '周一', '周二', '周三', '周四', '周五', '周六'], daysShort: ['日', '一', '二', '三', '四', '五', '六'], daysMin: ['日', '一', '二', '三', '四', '五', '六'], @@ -7,5 +7,6 @@ Datepicker.language['zh'] = { 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 index 352c1058..acd0a023 100644 --- a/src/js/navigation.js +++ b/src/js/navigation.js @@ -4,9 +4,11 @@ '
#{title}
' + '
#{nextHtml}
', buttonsContainerTemplate = '
', - button = '#{label}'; + button = '#{label}', + datepicker = $.fn.datepicker, + dp = datepicker.Constructor; - Datepicker.Navigation = function (d, opts) { + datepicker.Navigation = function (d, opts) { this.d = d; this.opts = opts; @@ -15,7 +17,7 @@ this.init(); }; - Datepicker.Navigation.prototype = { + datepicker.Navigation.prototype = { init: function () { this._buildBaseHtml(); this._bindEvents(); @@ -43,7 +45,7 @@ _render: function () { var title = this._getTitle(this.d.currentDate), - html = Datepicker.template(template, $.extend({title: title}, this.opts)); + 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-'); @@ -64,7 +66,7 @@ action: type, label: this.d.loc[type] }, - html = Datepicker.template(button, data); + html = dp.template(button, data); if ($('[data-action=' + type + ']', this.$buttonsContainer).length) return; this.$buttonsContainer.append(html); diff --git a/src/js/timepicker.js b/src/js/timepicker.js new file mode 100644 index 00000000..2a6cb649 --- /dev/null +++ b/src/js/timepicker.js @@ -0,0 +1,259 @@ +;(function () { + var template = '
' + + '
' + + ' #{hourValue}' + + ' :' + + ' #{minValue}' + + '
' + + '
' + + '
' + + ' ' + + '
' + + '
' + + ' ' + + '
' + + '
' + + '
', + 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; + }, + + _setMinTimeFromDate: function (date) { + this.minHours = date.getHours(); + this.minMinutes = date.getMinutes(); + }, + + _setMaxTimeFromDate: function (date) { + this.maxHours = date.getHours(); + this.maxMinutes = date.getMinutes(); + }, + + _setDefaultMinMaxTime: function () { + var maxHours = 23, + maxMinutes = 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; + }, + + /** + * 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; + } + }, + + _buildHTML: function () { + var lz = dp.getLeadingZeroNum, + data = { + hourMin: this.minHours, + hourMax: lz(this.maxHours), + hourStep: this.opts.hoursStep, + hourValue: lz(this.displayHours), + minMin: this.minMinutes, + minMax: lz(this.maxMinutes), + minStep: this.opts.minutesStep, + minValue: lz(this.minutes) + }, + _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.$hoursText = $('.datepicker--time-current-hours', this.$timepicker); + this.$minutesText = $('.datepicker--time-current-minutes', 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); + + this.$hoursText.html(h); + this.$minutesText.html(m); + + 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) + }, + + /** + * 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 + * @returns {{hours: *, dayPeriod: string}} + * @private + */ + _getValidHoursFromDate: function (date) { + var d = date, + hours = date; + + if (date instanceof Date) { + d = dp.getParsedDate(date); + hours = d.hours; + } + + var 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]) + }, + + _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.scss b/src/sass/datepicker.scss index 250d9a49..be5f8fd9 100644 --- a/src/sass/datepicker.scss +++ b/src/sass/datepicker.scss @@ -8,6 +8,10 @@ position: absolute; left: 0; top: 0; + + @media print { + display: none; + } } .datepicker { diff --git a/src/sass/timepicker.scss b/src/sass/timepicker.scss new file mode 100644 index 00000000..21ba20c6 --- /dev/null +++ b/src/sass/timepicker.scss @@ -0,0 +1,247 @@ +@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($borderColor, nav); + display: flex; + align-items: center; + + padding: $datepickerPadding; + position: relative; + + &.-am-pm- { + .datepicker--time-sliders { + flex: 0 1 138px; + max-width: 138px; + } + } +} + +.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 0 0 10px; +} + +.datepicker--time-current-colon { + margin: 0 2px 3px; + line-height: 1; +} + +.datepicker--time-current-hours, +.datepicker--time-current-minutes { + line-height: 1; + font-size: 19px; + font-family: "Century Gothic", CenturyGothic, AppleGothic, sans-serif; + position: relative; + z-index: 1; + + &:after { + content: ''; + background: map_get($bg, 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-end; + color: map_get($textColor, 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($bg, selected); + border-color: map_get($bg, 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($textColor, 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/static-server.js b/static-server.js new file mode 100644 index 00000000..b1cc4c1c --- /dev/null +++ b/static-server.js @@ -0,0 +1,10 @@ +var static = require('node-static'), + http = require('http'); + +var file = new static.Server('.'); + +http.createServer(function (request, response) { + request.addListener('end', function () { + file.serve(request, response); + }).resume(); +}).listen(3000); diff --git a/tasks/i18n.js b/tasks/i18n.js index 011d37f4..c928bafa 100644 --- a/tasks/i18n.js +++ b/tasks/i18n.js @@ -1,11 +1,12 @@ var gulp = require('gulp'), rename = require('gulp-rename'), - uglify = require('gulp-uglify'), + 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/js.js b/tasks/js.js index f2ccd0d6..4cf5f300 100644 --- a/tasks/js.js +++ b/tasks/js.js @@ -9,7 +9,8 @@ module.exports = function () { var stream = gulp.src([ 'src/js/datepicker.js', 'src/js/body.js', - 'src/js/navigation.js' + 'src/js/navigation.js', + 'src/js/timepicker.js' ]) .pipe(concat('datepicker.js')) .pipe(wrap(';(function (window, $, undefined) { <%=contents%> })(window, jQuery);')); diff --git a/tests/index.html b/tests/index.html index d7887599..5052cc60 100644 --- a/tests/index.html +++ b/tests/index.html @@ -19,6 +19,7 @@ +