diff --git a/README.md b/README.md index d5f4668..be905ee 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,6 @@ - [Website](https://fengyuanchen.github.io/datepicker) - - ## Table of contents - [Features](#features) @@ -20,8 +18,6 @@ - [Versioning](#versioning) - [License](#license) - - ## Features - Supports [options](#options) @@ -32,33 +28,25 @@ - Supports internationalization - Cross-browser support - - ## Main -``` +```text dist/ -├── datepicker.css ( 4 KB) -├── datepicker.min.css ( 4 KB) -├── datepicker.js (40 KB) -└── datepicker.min.js (16 KB) +├── datepicker.css ( 5 KB) +├── datepicker.min.css ( 4 KB) +├── datepicker.js (40 KB, UMD) +├── datepicker.min.js (18 KB, UMD, compressed) +├── datepicker.common.js (40 KB, CommonJS, default) +└── datepicker.esm.js (40 KB, ES Module) ``` - - ## Getting started -### Quick start - -Three quick start options are available: - -- [Download the latest release](https://github.com/fengyuanchen/datepicker/archive/master.zip). -- Clone the repository: `git clone https://github.com/fengyuanchen/datepicker.git`. -- Install with [NPM](http://npmjs.org): `npm install fengyuanchen/datepicker`. -- Install with [Bower](http://bower.io): `bower install fengyuanchen/datepicker`. +### Install - -### Installation +```shell +npm install @fengyuanchen/datepicker +``` Include files: @@ -68,7 +56,6 @@ Include files: ``` - ### Usage Initialize with `$.fn.datepicker` method. @@ -83,17 +70,13 @@ Initialize with `$.fn.datepicker` method. $('[data-toggle="datepicker"]').datepicker(); ``` - [⬆ back to top](#table-of-contents) - - ## Options You may set datepicker options with `$().datepicker(options)`. If you want to change the global default options, You may use `$.fn.datepicker.setDefaults(options)`. - ### autoShow - Type: `Boolean` @@ -101,7 +84,6 @@ If you want to change the global default options, You may use `$.fn.datepicker.s Show the datepicker automatically when initialized. - ### autoHide - Type: `Boolean` @@ -109,7 +91,6 @@ Show the datepicker automatically when initialized. Hide the datepicker automatically when picked. - ### autoPick - Type: `Boolean` @@ -117,7 +98,6 @@ Hide the datepicker automatically when picked. Pick the initial date automatically when initialized. - ### inline - Type: `Boolean` @@ -128,7 +108,6 @@ Enable inline mode. If the element is not an input element, will append the datepicker to the element. If the `container` option is set, will append the datepicker to the container. - ### container - Type: `Element` or `String`(selector) @@ -138,7 +117,6 @@ A element for putting the datepicker. If not set, the datepicker will be appende > Only works when the `inline` option set to `true`. - ### trigger - Type: `Element` or `String`(selector) @@ -146,7 +124,6 @@ A element for putting the datepicker. If not set, the datepicker will be appende A element for triggering the datepicker. - ### language - Type: `String` @@ -160,7 +137,6 @@ $().datepicker({ }); ``` - ### format - Type: `String` @@ -178,7 +154,6 @@ $().datepicker({ }); ``` - ### date - Type: `Date` or `String` @@ -192,7 +167,6 @@ $().datepicker({ }); ``` - ### startDate - Type: `Date` or `String` @@ -200,7 +174,6 @@ $().datepicker({ The start view date. All the dates before this date will be disabled. - ### endDate - Type: `Date` or `String` @@ -208,7 +181,6 @@ The start view date. All the dates before this date will be disabled. The end view date. All the dates after this date will be disabled. - ### startView - Type: `Number` @@ -220,7 +192,6 @@ The end view date. All the dates after this date will be disabled. The start view when initialized. - ### weekStart - Type: `Number` @@ -236,7 +207,6 @@ The start view when initialized. The start day of the week. - ### yearFirst - Type: `Boolean` @@ -244,7 +214,6 @@ The start day of the week. Show year before month on the datepicker header - ### yearSuffix - Type: `String` @@ -265,7 +234,6 @@ $().datepicker({ Days' name of the week. - ### daysShort - Type: `Array` @@ -273,7 +241,6 @@ Days' name of the week. Shorter days' name. - ### daysMin - Type: `Array` @@ -281,7 +248,6 @@ Shorter days' name. Shortest days' name. - ### months - Type: `Array` @@ -289,7 +255,6 @@ Shortest days' name. Months' name. - ### monthsShort - Type: `Array` @@ -297,7 +262,6 @@ Months' name. Shorter months' name. - ### itemTag - Type: `String` @@ -305,7 +269,6 @@ Shorter months' name. A element tag for each item of years, months and days. - ### mutedClass - Type: `String` @@ -313,7 +276,6 @@ A element tag for each item of years, months and days. A class (CSS) for muted item. - ### pickedClass - Type: `String` @@ -321,7 +283,6 @@ A class (CSS) for muted item. A class (CSS) for picked item. - ### disabledClass - Type: `String` @@ -329,7 +290,6 @@ A class (CSS) for picked item. A class (CSS) for disabled item. - ### highlightedClass - Type: `String` @@ -337,7 +297,6 @@ A class (CSS) for disabled item. A class (CSS) for highlight date item. - ### template - Type: `String` @@ -377,7 +336,6 @@ The template of the datepicker. **Note:** All the `data-view` attributes must be set when you customize it. - ### offset - Type: `Number` @@ -385,7 +343,6 @@ The template of the datepicker. The offset top or bottom of the datepicker from the element. - ### zIndex - Type: `Number` @@ -393,7 +350,6 @@ The offset top or bottom of the datepicker from the element. The CSS `z-index` style for the datepicker. - ### filter - Type: `Function` @@ -413,7 +369,6 @@ $().datepicker({ }); ``` - ### show - Type: `Function` @@ -421,7 +376,6 @@ $().datepicker({ A shortcut of the "show.datepicker" event. - ### hide - Type: `Function` @@ -429,7 +383,6 @@ A shortcut of the "show.datepicker" event. A shortcut of the "hide.datepicker" event. - ### pick - Type: `Function` @@ -437,11 +390,8 @@ A shortcut of the "hide.datepicker" event. A shortcut of the "pick.datepicker" event. - [⬆ back to top](#table-of-contents) - - ## Methods Common usage: @@ -450,32 +400,26 @@ Common usage: $().datepicker('method', argument1, , argument2, ..., argumentN); ``` - ### show() Show the datepicker. - ### hide() Hide the datepicker. - ### update() Update the datepicker with the value or text of the current element. - ### pick() Pick the current date to the element. - ### reset() Reset the datepicker. - ### getMonthName([month[, short]]) - **month** (optional): @@ -499,7 +443,6 @@ $().datepicker('getMonthName', 11); // 'December' $().datepicker('getMonthName', 11, true); // 'Dec' ``` - ### getDayName([day[, short[, min]]) - **day** (optional): @@ -530,7 +473,6 @@ $().datepicker('getDayName', 6, true); // 'Sat' $().datepicker('getDayName', 6, true, true); // 'Sa' ``` - ### getDate([formatted]) - **formatted** (optional): @@ -548,7 +490,6 @@ $().datepicker('getDate'); // date object $().datepicker('getDate', true); // '02/14/2014' ``` - ### setDate(date) - **date**: @@ -561,7 +502,6 @@ $().datepicker('setDate', new Date(2014, 1, 14)); $().datepicker('setDate', '02/14/2014'); ``` - ### setStartDate(date) - **date**: @@ -569,7 +509,6 @@ $().datepicker('setDate', '02/14/2014'); Set the start view date with a new date. - ### setEndDate(date) - **date**: @@ -577,7 +516,6 @@ Set the start view date with a new date. Set the end view date with a new date. - ### parseDate(date) - **date**: @@ -589,7 +527,6 @@ Parse a date string with the set date format. $().datepicker('parseDate', '02/14/2014'); // date object ``` - ### formatDate(date) - **date**: @@ -601,28 +538,22 @@ Format a date object to a string with the set date format. $().datepicker('formatDate', new Date(2014, 1, 14)); // '02/14/2014' ``` - ### destroy() Destroy the datepicker and remove the instance from the target element. - [⬆ back to top](#table-of-contents) - - ## Events ### show.datepicker This event fires when starts to show the datepicker. - ### hide.datepicker This event fires when starts to hide the datepicker. - ### pick.datepicker - **event.date**: @@ -645,15 +576,10 @@ $().on('pick.datepicker', function (e) { }); ``` - [⬆ back to top](#table-of-contents) - - ## I18n -### Config - ```js // datepicker.zh-CN.js $.fn.datepicker.languages['zh-CN'] = { @@ -670,8 +596,6 @@ $.fn.datepicker.languages['zh-CN'] = { }; ``` -### Usage - ```html @@ -682,11 +606,8 @@ $.fn.datepicker.languages['zh-CN'] = { ``` - [⬆ back to top](#table-of-contents) - - ## No conflict If you have to use other plugin with the same namespace, just call the `$.fn.datepicker.noConflict` method to revert to it. @@ -700,8 +621,6 @@ If you have to use other plugin with the same namespace, just call the `$.fn.dat ``` - - ## Browser support - Chrome (latest 2) @@ -713,17 +632,12 @@ If you have to use other plugin with the same namespace, just call the `$.fn.dat As a jQuery plugin, you also need to see the [jQuery Browser Support](http://jquery.com/browser-support/). - - ## Versioning Maintained under the [Semantic Versioning guidelines](http://semver.org/). - - ## License [MIT](http://opensource.org/licenses/MIT) © [Fengyuan Chen](http://chenfengyuan.com) - [⬆ back to top](#table-of-contents) diff --git a/dist/datepicker.common.js b/dist/datepicker.common.js new file mode 100644 index 0000000..28172d2 --- /dev/null +++ b/dist/datepicker.common.js @@ -0,0 +1,1513 @@ +/*! + * Datepicker v0.6.0 + * https://github.com/fengyuanchen/datepicker + * + * Copyright (c) 2014-2017 Fengyuan Chen + * Released under the MIT license + * + * Date: 2017-09-24T11:42:13.421Z + */ +'use strict'; + +function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; } + +var $ = _interopDefault(require('jquery')); + +var DEFAULTS = { + // Show the datepicker automatically when initialized + autoShow: false, + + // Hide the datepicker automatically when picked + autoHide: false, + + // Pick the initial date automatically when initialized + autoPick: false, + + // Enable inline mode + inline: false, + + // A element (or selector) for putting the datepicker + container: null, + + // A element (or selector) for triggering the datepicker + trigger: null, + + // The ISO language code (built-in: en-US) + language: '', + + // The date string format + format: 'mm/dd/yyyy', + + // The initial date + date: null, + + // The start view date + startDate: null, + + // The end view date + endDate: null, + + // The start view when initialized + startView: 0, // 0 for days, 1 for months, 2 for years + + // The start day of the week + // 0 for Sunday, 1 for Monday, 2 for Tuesday, 3 for Wednesday, + // 4 for Thursday, 5 for Friday, 6 for Saturday + weekStart: 0, + + // Show year before month on the datepicker header + yearFirst: false, + + // A string suffix to the year number. + yearSuffix: '', + + // Days' name of the week. + days: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], + + // Shorter days' name + daysShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], + + // Shortest days' name + daysMin: ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'], + + // Months' name + months: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'], + + // Shorter months' name + monthsShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], + + // A element tag for each item of years, months and days + itemTag: 'li', + + // A class (CSS) for muted date item + mutedClass: 'muted', + + // A class (CSS) for picked date item + pickedClass: 'picked', + + // A class (CSS) for disabled date item + disabledClass: 'disabled', + + // A class (CSS) for highlight date item + highlightedClass: 'highlighted', + + // The template of the datepicker + template: '
' + '
' + '' + '' + '
' + '
' + '' + '' + '
' + '
' + '' + '' + '' + '
' + '
', + + // The offset top or bottom of the datepicker from the element + offset: 10, + + // The `z-index` of the datepicker + zIndex: 1000, + + // Filter each date item (return `false` to disable a date item) + filter: null, + + // Event shortcuts + show: null, + hide: null, + pick: null +}; + +var NAMESPACE = 'datepicker'; +var EVENT_CLICK = 'click.' + NAMESPACE; +var EVENT_FOCUS = 'focus.' + NAMESPACE; +var EVENT_HIDE = 'hide.' + NAMESPACE; +var EVENT_KEYUP = 'keyup.' + NAMESPACE; +var EVENT_PICK = 'pick.' + NAMESPACE; +var EVENT_RESIZE = 'resize.' + NAMESPACE; +var EVENT_SHOW = 'show.' + NAMESPACE; +var CLASS_HIDE = NAMESPACE + '-hide'; +var LANGUAGES = {}; +var VIEWS = { + DAYS: 0, + MONTHS: 1, + YEARS: 2 +}; + +var toString = Object.prototype.toString; + + +function typeOf(obj) { + return toString.call(obj).slice(8, -1).toLowerCase(); +} + +function isString(value) { + return typeof value === 'string'; +} + +var isNaN = Number.isNaN || window.isNaN; + +function isNumber(value) { + return typeof value === 'number' && !isNaN(value); +} + +function isUndefined(value) { + return typeof value === 'undefined'; +} + +function isDate(value) { + return typeOf(value) === 'date'; +} + +function proxy(fn, context) { + for (var _len = arguments.length, args = Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) { + args[_key - 2] = arguments[_key]; + } + + return function () { + for (var _len2 = arguments.length, args2 = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { + args2[_key2] = arguments[_key2]; + } + + return fn.apply(context, args.concat(args2)); + }; +} + +function selectorOf(view) { + return '[data-view="' + view + '"]'; +} + +function isLeapYear(year) { + return year % 4 === 0 && year % 100 !== 0 || year % 400 === 0; +} + +function getDaysInMonth(year, month) { + return [31, isLeapYear(year) ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month]; +} + +function getMinDay(year, month, day) { + return Math.min(day, getDaysInMonth(year, month)); +} + +var formatParts = /(y|m|d)+/g; + +function parseFormat(format) { + var source = String(format).toLowerCase(); + var parts = source.match(formatParts); + + if (!parts || parts.length === 0) { + throw new Error('Invalid date format.'); + } + + format = { + source: source, + parts: parts + }; + + $.each(parts, function (i, part) { + switch (part) { + case 'dd': + case 'd': + format.hasDay = true; + break; + + case 'mm': + case 'm': + format.hasMonth = true; + break; + + case 'yyyy': + case 'yy': + format.hasYear = true; + break; + + default: + } + }); + + return format; +} + +var _window$1 = window; +var document$2 = _window$1.document; + +var $window = $(window); +var $document$1 = $(document$2); +var REGEXP_DIGITS = /\d+/g; + +var methods = { + // Show the datepicker + show: function show() { + if (!this.built) { + this.build(); + } + + if (this.shown) { + return; + } + + if (this.trigger(EVENT_SHOW).isDefaultPrevented()) { + return; + } + + this.shown = true; + this.$picker.removeClass(CLASS_HIDE).on(EVENT_CLICK, $.proxy(this.click, this)); + this.showView(this.options.startView); + + if (!this.inline) { + $window.on(EVENT_RESIZE, this.onResize = proxy(this.place, this)); + $document$1.on(EVENT_CLICK, this.onGlobalClick = proxy(this.globalClick, this)); + $document$1.on(EVENT_KEYUP, this.onGlobalKeyup = proxy(this.globalKeyup, this)); + this.place(); + } + }, + + + // Hide the datepicker + hide: function hide() { + if (!this.shown) { + return; + } + + if (this.trigger(EVENT_HIDE).isDefaultPrevented()) { + return; + } + + this.shown = false; + this.$picker.addClass(CLASS_HIDE).off(EVENT_CLICK, this.click); + + if (!this.inline) { + $window.off(EVENT_RESIZE, this.onResize); + $document$1.off(EVENT_CLICK, this.onGlobalClick); + $document$1.off(EVENT_KEYUP, this.onGlobalKeyup); + } + }, + toggle: function toggle() { + if (this.shown) { + this.hide(); + } else { + this.show(); + } + }, + + + // Update the datepicker with the current input value + update: function update() { + var value = this.getValue(); + + if (value === this.oldValue) { + return; + } + + this.setDate(value, true); + this.oldValue = value; + }, + + + /** + * Pick the current date to the element + * + * @param {String} _view (private) + */ + pick: function pick(_view) { + var $this = this.$element; + var date = this.date; + + + if (this.trigger(EVENT_PICK, { + view: _view || '', + date: date + }).isDefaultPrevented()) { + return; + } + + date = this.formatDate(this.date); + this.setValue(date); + + if (this.isInput) { + $this.trigger('input'); + $this.trigger('change'); + } + }, + + + // Reset the datepicker + reset: function reset() { + this.setDate(this.initialDate, true); + this.setValue(this.initialValue); + + if (this.shown) { + this.showView(this.options.startView); + } + }, + + + /** + * Get the month name with given argument or the current date + * + * @param {Number} month (optional) + * @param {Boolean} short (optional) + * @return {String} (month name) + */ + getMonthName: function getMonthName(month, short) { + var options = this.options; + var monthsShort = options.monthsShort; + var months = options.months; + + + if ($.isNumeric(month)) { + month = Number(month); + } else if (isUndefined(short)) { + short = month; + } + + if (short === true) { + months = monthsShort; + } + + return months[isNumber(month) ? month : this.date.getMonth()]; + }, + + + /** + * Get the day name with given argument or the current date + * + * @param {Number} day (optional) + * @param {Boolean} short (optional) + * @param {Boolean} min (optional) + * @return {String} (day name) + */ + getDayName: function getDayName(day, short, min) { + var options = this.options; + var days = options.days; + + + if ($.isNumeric(day)) { + day = Number(day); + } else { + if (isUndefined(min)) { + min = short; + } + + if (isUndefined(short)) { + short = day; + } + } + + if (min) { + days = options.daysMin; + } else if (short) { + days = options.daysShort; + } + + return days[isNumber(day) ? day : this.date.getDay()]; + }, + + + /** + * Get the current date + * + * @param {Boolean} formatted (optional) + * @return {Date|String} (date) + */ + getDate: function getDate(formatted) { + var date = this.date; + + + return formatted ? this.formatDate(date) : new Date(date); + }, + + + /** + * Set the current date with a new date + * + * @param {Date} date + * @param {Boolean} _updated (private) + */ + setDate: function setDate(date, _updated) { + var filter = this.options.filter; + + + if (isDate(date) || isString(date)) { + date = this.parseDate(date); + + if ($.isFunction(filter) && filter.call(this.$element, date) === false) { + return; + } + + this.date = date; + this.viewDate = new Date(date); + + if (!_updated) { + this.pick(); + } + + if (this.built) { + this.render(); + } + } + }, + + + /** + * Set the start view date with a new date + * + * @param {Date} date + */ + setStartDate: function setStartDate(date) { + if (isDate(date) || isString(date)) { + this.startDate = this.parseDate(date); + + if (this.built) { + this.render(); + } + } + }, + + + /** + * Set the end view date with a new date + * + * @param {Date} date + */ + setEndDate: function setEndDate(date) { + if (isDate(date) || isString(date)) { + this.endDate = this.parseDate(date); + + if (this.built) { + this.render(); + } + } + }, + + + /** + * Parse a date string with the set date format + * + * @param {String} date + * @return {Date} (parsed date) + */ + parseDate: function parseDate(date) { + var format = this.format; + + var parts = []; + + if (isDate(date)) { + return new Date(date.getFullYear(), date.getMonth(), date.getDate()); + } else if (isString(date)) { + parts = date.match(REGEXP_DIGITS) || []; + } + + date = new Date(); + + var length = format.parts.length; + + var year = date.getFullYear(); + var day = date.getDate(); + var month = date.getMonth(); + + if (parts.length === length) { + $.each(parts, function (i, part) { + var value = parseInt(part, 10) || 1; + + switch (format.parts[i]) { + case 'dd': + case 'd': + day = value; + break; + + case 'mm': + case 'm': + month = value - 1; + break; + + case 'yy': + year = 2000 + value; + break; + + case 'yyyy': + year = value; + break; + + default: + } + }); + } + + return new Date(year, month, day); + }, + + + /** + * Format a date object to a string with the set date format + * + * @param {Date} date + * @return {String} (formatted date) + */ + formatDate: function formatDate(date) { + var format = this.format; + + var formatted = ''; + + if (isDate(date)) { + var year = date.getFullYear(); + var values = { + d: date.getDate(), + m: date.getMonth() + 1, + yy: year.toString().substring(2), + yyyy: year + }; + + values.dd = (values.d < 10 ? '0' : '') + values.d; + values.mm = (values.m < 10 ? '0' : '') + values.m; + formatted = format.source; + $.each(format.parts, function (i, part) { + formatted = formatted.replace(part, values[part]); + }); + } + + return formatted; + }, + + + // Destroy the datepicker and remove the instance from the target element + destroy: function destroy() { + this.unbind(); + this.unbuild(); + this.$element.removeData(NAMESPACE); + } +}; + +var handlers = { + click: function click(e) { + var $target = $(e.target); + var options = this.options, + viewDate = this.viewDate, + format = this.format; + + + e.stopPropagation(); + e.preventDefault(); + + if ($target.hasClass('disabled')) { + return; + } + + var view = $target.data('view'); + var viewYear = viewDate.getFullYear(); + var viewMonth = viewDate.getMonth(); + var viewDay = viewDate.getDate(); + + switch (view) { + case 'years prev': + case 'years next': + { + viewYear = view === 'years prev' ? viewYear - 10 : viewYear + 10; + this.viewDate = new Date(viewYear, viewMonth, getMinDay(viewYear, viewMonth, viewDay)); + this.renderYears(); + break; + } + + case 'year prev': + case 'year next': + viewYear = view === 'year prev' ? viewYear - 1 : viewYear + 1; + this.viewDate = new Date(viewYear, viewMonth, getMinDay(viewYear, viewMonth, viewDay)); + this.renderMonths(); + break; + + case 'year current': + if (format.hasYear) { + this.showView(VIEWS.YEARS); + } + + break; + + case 'year picked': + if (format.hasMonth) { + this.showView(VIEWS.MONTHS); + } else { + $target.addClass(options.pickedClass).siblings().removeClass(options.pickedClass); + this.hideView(); + } + + this.pick('year'); + break; + + case 'year': + viewYear = parseInt($target.text(), 10); + this.date = new Date(viewYear, viewMonth, getMinDay(viewYear, viewMonth, viewDay)); + + if (format.hasMonth) { + this.viewDate = new Date(this.date); + this.showView(VIEWS.MONTHS); + } else { + $target.addClass(options.pickedClass).siblings().removeClass(options.pickedClass); + this.hideView(); + } + + this.pick('year'); + break; + + case 'month prev': + case 'month next': + viewMonth = view === 'month prev' ? viewMonth - 1 : viewMonth + 1; + this.viewDate = new Date(viewYear, viewMonth, getMinDay(viewYear, viewMonth, viewDay)); + this.renderDays(); + break; + + case 'month current': + if (format.hasMonth) { + this.showView(VIEWS.MONTHS); + } + + break; + + case 'month picked': + if (format.hasDay) { + this.showView(VIEWS.DAYS); + } else { + $target.addClass(options.pickedClass).siblings().removeClass(options.pickedClass); + this.hideView(); + } + + this.pick('month'); + break; + + case 'month': + viewMonth = $.inArray($target.text(), options.monthsShort); + this.date = new Date(viewYear, viewMonth, getMinDay(viewYear, viewMonth, viewDay)); + + if (format.hasDay) { + this.viewDate = new Date(viewYear, viewMonth, getMinDay(viewYear, viewMonth, viewDay)); + this.showView(VIEWS.DAYS); + } else { + $target.addClass(options.pickedClass).siblings().removeClass(options.pickedClass); + this.hideView(); + } + + this.pick('month'); + break; + + case 'day prev': + case 'day next': + case 'day': + if (view === 'day prev') { + viewMonth -= 1; + } else if (view === 'day next') { + viewMonth += 1; + } + + viewDay = parseInt($target.text(), 10); + this.date = new Date(viewYear, viewMonth, viewDay); + this.viewDate = new Date(viewYear, viewMonth, viewDay); + this.renderDays(); + + if (view === 'day') { + this.hideView(); + } + + this.pick('day'); + break; + + case 'day picked': + this.hideView(); + this.pick('day'); + break; + + default: + } + }, + globalClick: function globalClick(_ref) { + var target = _ref.target; + var element = this.element, + $trigger = this.$trigger; + + var trigger = $trigger[0]; + var hidden = true; + + while (target !== document) { + if (target === trigger || target === element) { + hidden = false; + break; + } + + target = target.parentNode; + } + + if (hidden) { + this.hide(); + } + }, + keyup: function keyup() { + this.update(); + }, + globalKeyup: function globalKeyup(_ref2) { + var target = _ref2.target, + key = _ref2.key, + keyCode = _ref2.keyCode; + + if (this.isInput && target !== this.element && this.shown && (key === 'Tab' || keyCode === 9)) { + this.hide(); + } + } +}; + +var render = { + render: function render() { + this.renderYears(); + this.renderMonths(); + this.renderDays(); + }, + renderWeek: function renderWeek() { + var _this = this; + + var items = []; + var _options = this.options, + weekStart = _options.weekStart, + daysMin = _options.daysMin; + + + weekStart = parseInt(weekStart, 10) % 7; + daysMin = daysMin.slice(weekStart).concat(daysMin.slice(0, weekStart)); + $.each(daysMin, function (i, day) { + items.push(_this.createItem({ + text: day + })); + }); + + this.$week.html(items.join('')); + }, + renderYears: function renderYears() { + var options = this.options, + startDate = this.startDate, + endDate = this.endDate; + var disabledClass = options.disabledClass, + filter = options.filter, + yearSuffix = options.yearSuffix; + + var viewYear = this.viewDate.getFullYear(); + var now = new Date(); + var thisYear = now.getFullYear(); + var year = this.date.getFullYear(); + var start = -5; + var end = 6; + var items = []; + var prevDisabled = false; + var nextDisabled = false; + var i = void 0; + + for (i = start; i <= end; i += 1) { + var date = new Date(viewYear + i, 1, 1); + var disabled = false; + + if (startDate) { + disabled = date.getFullYear() < startDate.getFullYear(); + + if (i === start) { + prevDisabled = disabled; + } + } + + if (!disabled && endDate) { + disabled = date.getFullYear() > endDate.getFullYear(); + + if (i === end) { + nextDisabled = disabled; + } + } + + if (!disabled && filter) { + disabled = filter.call(this.$element, date) === false; + } + + var picked = viewYear + i === year; + var view = picked ? 'year picked' : 'year'; + + items.push(this.createItem({ + picked: picked, + disabled: disabled, + muted: i === start || i === end, + text: viewYear + i, + view: disabled ? 'year disabled' : view, + highlighted: date.getFullYear() === thisYear + })); + } + + this.$yearsPrev.toggleClass(disabledClass, prevDisabled); + this.$yearsNext.toggleClass(disabledClass, nextDisabled); + this.$yearsCurrent.toggleClass(disabledClass, true).html(viewYear + start + yearSuffix + ' - ' + (viewYear + end) + yearSuffix); + this.$years.html(items.join('')); + }, + renderMonths: function renderMonths() { + var options = this.options, + startDate = this.startDate, + endDate = this.endDate, + viewDate = this.viewDate; + + var disabledClass = options.disabledClass || ''; + var months = options.monthsShort; + var filter = $.isFunction(options.filter) && options.filter; + var viewYear = viewDate.getFullYear(); + var now = new Date(); + var thisYear = now.getFullYear(); + var thisMonth = now.getMonth(); + var year = this.date.getFullYear(); + var month = this.date.getMonth(); + var items = []; + var prevDisabled = false; + var nextDisabled = false; + var i = void 0; + + for (i = 0; i <= 11; i += 1) { + var date = new Date(viewYear, i, 1); + var disabled = false; + + if (startDate) { + prevDisabled = date.getFullYear() === startDate.getFullYear(); + disabled = prevDisabled && date.getMonth() < startDate.getMonth(); + } + + if (!disabled && endDate) { + nextDisabled = date.getFullYear() === endDate.getFullYear(); + disabled = nextDisabled && date.getMonth() > endDate.getMonth(); + } + + if (!disabled && filter) { + disabled = filter.call(this.$element, date) === false; + } + + var picked = viewYear === year && i === month; + var view = picked ? 'month picked' : 'month'; + + items.push(this.createItem({ + disabled: disabled, + picked: picked, + highlighted: viewYear === thisYear && date.getMonth() === thisMonth, + index: i, + text: months[i], + view: disabled ? 'month disabled' : view + })); + } + + this.$yearPrev.toggleClass(disabledClass, prevDisabled); + this.$yearNext.toggleClass(disabledClass, nextDisabled); + this.$yearCurrent.toggleClass(disabledClass, prevDisabled && nextDisabled).html(viewYear + options.yearSuffix || ''); + this.$months.html(items.join('')); + }, + renderDays: function renderDays() { + var $element = this.$element, + options = this.options, + startDate = this.startDate, + endDate = this.endDate, + viewDate = this.viewDate, + currentDate = this.date; + var disabledClass = options.disabledClass, + filter = options.filter, + monthsShort = options.monthsShort, + weekStart = options.weekStart, + yearSuffix = options.yearSuffix; + + var viewYear = viewDate.getFullYear(); + var viewMonth = viewDate.getMonth(); + var now = new Date(); + var thisYear = now.getFullYear(); + var thisMonth = now.getMonth(); + var thisDay = now.getDate(); + var year = currentDate.getFullYear(); + var month = currentDate.getMonth(); + var day = currentDate.getDate(); + var length = void 0; + var i = void 0; + var n = void 0; + + // Days of prev month + // ----------------------------------------------------------------------- + + var prevItems = []; + var prevViewYear = viewYear; + var prevViewMonth = viewMonth; + var prevDisabled = false; + + if (viewMonth === 0) { + prevViewYear -= 1; + prevViewMonth = 11; + } else { + prevViewMonth -= 1; + } + + // The length of the days of prev month + length = getDaysInMonth(prevViewYear, prevViewMonth); + + // The first day of current month + var firstDay = new Date(viewYear, viewMonth, 1); + + // The visible length of the days of prev month + // [0,1,2,3,4,5,6] - [0,1,2,3,4,5,6] => [-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6] + n = firstDay.getDay() - parseInt(weekStart, 10) % 7; + + // [-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6] => [1,2,3,4,5,6,7] + if (n <= 0) { + n += 7; + } + + if (startDate) { + prevDisabled = firstDay.getTime() <= startDate.getTime(); + } + + for (i = length - (n - 1); i <= length; i += 1) { + var prevViewDate = new Date(prevViewYear, prevViewMonth, i); + var disabled = false; + + if (startDate) { + disabled = prevViewDate.getTime() < startDate.getTime(); + } + + if (!disabled && filter) { + disabled = filter.call($element, prevViewDate) === false; + } + + prevItems.push(this.createItem({ + disabled: disabled, + highlighted: prevViewYear === thisYear && prevViewMonth === thisMonth && prevViewDate.getDate() === thisDay, + muted: true, + picked: prevViewYear === year && prevViewMonth === month && i === day, + text: i, + view: 'day prev' + })); + } + + // Days of next month + // ----------------------------------------------------------------------- + + var nextItems = []; + var nextViewYear = viewYear; + var nextViewMonth = viewMonth; + var nextDisabled = false; + + if (viewMonth === 11) { + nextViewYear += 1; + nextViewMonth = 0; + } else { + nextViewMonth += 1; + } + + // The length of the days of current month + length = getDaysInMonth(viewYear, viewMonth); + + // The visible length of next month (42 means 6 rows and 7 columns) + n = 42 - (prevItems.length + length); + + // The last day of current month + var lastDate = new Date(viewYear, viewMonth, length); + + if (endDate) { + nextDisabled = lastDate.getTime() >= endDate.getTime(); + } + + for (i = 1; i <= n; i += 1) { + var date = new Date(nextViewYear, nextViewMonth, i); + var picked = nextViewYear === year && nextViewMonth === month && i === day; + var _disabled = false; + + if (endDate) { + _disabled = date.getTime() > endDate.getTime(); + } + + if (!_disabled && filter) { + _disabled = filter.call($element, date) === false; + } + + nextItems.push(this.createItem({ + disabled: _disabled, + picked: picked, + highlighted: nextViewYear === thisYear && nextViewMonth === thisMonth && date.getDate() === thisDay, + muted: true, + text: i, + view: 'day next' + })); + } + + // Days of current month + // ----------------------------------------------------------------------- + + var items = []; + + for (i = 1; i <= length; i += 1) { + var _date = new Date(viewYear, viewMonth, i); + var _disabled2 = false; + + if (startDate) { + _disabled2 = _date.getTime() < startDate.getTime(); + } + + if (!_disabled2 && endDate) { + _disabled2 = _date.getTime() > endDate.getTime(); + } + + if (!_disabled2 && filter) { + _disabled2 = filter.call($element, _date) === false; + } + + var _picked = viewYear === year && viewMonth === month && i === day; + var view = _picked ? 'day picked' : 'day'; + + items.push(this.createItem({ + disabled: _disabled2, + picked: _picked, + highlighted: viewYear === thisYear && viewMonth === thisMonth && _date.getDate() === thisDay, + text: i, + view: _disabled2 ? 'day disabled' : view + })); + } + + // Render days picker + // ----------------------------------------------------------------------- + + this.$monthPrev.toggleClass(disabledClass, prevDisabled); + this.$monthNext.toggleClass(disabledClass, nextDisabled); + this.$monthCurrent.toggleClass(disabledClass, prevDisabled && nextDisabled).html(options.yearFirst ? viewYear + yearSuffix + ' ' + monthsShort[viewMonth] : monthsShort[viewMonth] + ' ' + viewYear + yearSuffix); + this.$days.html(prevItems.join('') + items.join('') + nextItems.join('')); + } +}; + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +var _window = window; +var document$1 = _window.document; + +var $document = $(document$1); + +// Classes +var CLASS_TOP_LEFT = NAMESPACE + '-top-left'; +var CLASS_TOP_RIGHT = NAMESPACE + '-top-right'; +var CLASS_BOTTOM_LEFT = NAMESPACE + '-bottom-left'; +var CLASS_BOTTOM_RIGHT = NAMESPACE + '-bottom-right'; +var CLASS_PLACEMENTS = [CLASS_TOP_LEFT, CLASS_TOP_RIGHT, CLASS_BOTTOM_LEFT, CLASS_BOTTOM_RIGHT].join(' '); + +var Datepicker = function () { + function Datepicker(element) { + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + + _classCallCheck(this, Datepicker); + + this.$element = $(element); + this.element = element; + this.options = $.extend({}, DEFAULTS, LANGUAGES[options.language], options); + this.built = false; + this.shown = false; + this.isInput = false; + this.inline = false; + this.initialValue = ''; + this.initialDate = null; + this.startDate = null; + this.endDate = null; + this.init(); + } + + _createClass(Datepicker, [{ + key: 'init', + value: function init() { + var $this = this.$element, + options = this.options; + var startDate = options.startDate, + endDate = options.endDate, + date = options.date; + + + this.$trigger = $(options.trigger); + this.isInput = $this.is('input') || $this.is('textarea'); + this.inline = options.inline && (options.container || !this.isInput); + this.format = parseFormat(options.format); + + var initialValue = this.getValue(); + + this.initialValue = initialValue; + this.oldValue = initialValue; + date = this.parseDate(date || initialValue); + + if (startDate) { + startDate = this.parseDate(startDate); + + if (date.getTime() < startDate.getTime()) { + date = new Date(startDate); + } + + this.startDate = startDate; + } + + if (endDate) { + endDate = this.parseDate(endDate); + + if (startDate && endDate.getTime() < startDate.getTime()) { + endDate = new Date(startDate); + } + + if (date.getTime() > endDate.getTime()) { + date = new Date(endDate); + } + + this.endDate = endDate; + } + + this.date = date; + this.viewDate = new Date(date); + this.initialDate = new Date(this.date); + this.bind(); + + if (options.autoShow || this.inline) { + this.show(); + } + + if (options.autoPick) { + this.pick(); + } + } + }, { + key: 'build', + value: function build() { + if (this.built) { + return; + } + + this.built = true; + + var $this = this.$element, + options = this.options; + + var $picker = $(options.template); + + this.$picker = $picker; + this.$week = $picker.find(selectorOf('week')); + + // Years view + this.$yearsPicker = $picker.find(selectorOf('years picker')); + this.$yearsPrev = $picker.find(selectorOf('years prev')); + this.$yearsNext = $picker.find(selectorOf('years next')); + this.$yearsCurrent = $picker.find(selectorOf('years current')); + this.$years = $picker.find(selectorOf('years')); + + // Months view + this.$monthsPicker = $picker.find(selectorOf('months picker')); + this.$yearPrev = $picker.find(selectorOf('year prev')); + this.$yearNext = $picker.find(selectorOf('year next')); + this.$yearCurrent = $picker.find(selectorOf('year current')); + this.$months = $picker.find(selectorOf('months')); + + // Days view + this.$daysPicker = $picker.find(selectorOf('days picker')); + this.$monthPrev = $picker.find(selectorOf('month prev')); + this.$monthNext = $picker.find(selectorOf('month next')); + this.$monthCurrent = $picker.find(selectorOf('month current')); + this.$days = $picker.find(selectorOf('days')); + + if (this.inline) { + $(options.container || $this).append($picker.addClass(NAMESPACE + '-inline')); + } else { + $(document$1.body).append($picker.addClass(NAMESPACE + '-dropdown')); + $picker.addClass(CLASS_HIDE); + } + + this.renderWeek(); + } + }, { + key: 'unbuild', + value: function unbuild() { + if (!this.built) { + return; + } + + this.built = false; + this.$picker.remove(); + } + }, { + key: 'bind', + value: function bind() { + var options = this.options, + $this = this.$element; + + + if ($.isFunction(options.show)) { + $this.on(EVENT_SHOW, options.show); + } + + if ($.isFunction(options.hide)) { + $this.on(EVENT_HIDE, options.hide); + } + + if ($.isFunction(options.pick)) { + $this.on(EVENT_PICK, options.pick); + } + + if (this.isInput) { + $this.on(EVENT_KEYUP, $.proxy(this.keyup, this)); + } + + if (!this.inline) { + if (options.trigger) { + this.$trigger.on(EVENT_CLICK, $.proxy(this.toggle, this)); + } else if (this.isInput) { + $this.on(EVENT_FOCUS, $.proxy(this.show, this)); + } else { + $this.on(EVENT_CLICK, $.proxy(this.show, this)); + } + } + } + }, { + key: 'unbind', + value: function unbind() { + var $this = this.$element, + options = this.options; + + + if ($.isFunction(options.show)) { + $this.off(EVENT_SHOW, options.show); + } + + if ($.isFunction(options.hide)) { + $this.off(EVENT_HIDE, options.hide); + } + + if ($.isFunction(options.pick)) { + $this.off(EVENT_PICK, options.pick); + } + + if (this.isInput) { + $this.off(EVENT_KEYUP, this.keyup); + } + + if (!this.inline) { + if (options.trigger) { + this.$trigger.off(EVENT_CLICK, this.toggle); + } else if (this.isInput) { + $this.off(EVENT_FOCUS, this.show); + } else { + $this.off(EVENT_CLICK, this.show); + } + } + } + }, { + key: 'showView', + value: function showView(view) { + var $yearsPicker = this.$yearsPicker, + $monthsPicker = this.$monthsPicker, + $daysPicker = this.$daysPicker, + format = this.format; + + + if (format.hasYear || format.hasMonth || format.hasDay) { + switch (Number(view)) { + case VIEWS.YEARS: + $monthsPicker.addClass(CLASS_HIDE); + $daysPicker.addClass(CLASS_HIDE); + + if (format.hasYear) { + this.renderYears(); + $yearsPicker.removeClass(CLASS_HIDE); + this.place(); + } else { + this.showView(VIEWS.DAYS); + } + + break; + + case VIEWS.MONTHS: + $yearsPicker.addClass(CLASS_HIDE); + $daysPicker.addClass(CLASS_HIDE); + + if (format.hasMonth) { + this.renderMonths(); + $monthsPicker.removeClass(CLASS_HIDE); + this.place(); + } else { + this.showView(VIEWS.YEARS); + } + + break; + + // case VIEWS.DAYS: + default: + $yearsPicker.addClass(CLASS_HIDE); + $monthsPicker.addClass(CLASS_HIDE); + + if (format.hasDay) { + this.renderDays(); + $daysPicker.removeClass(CLASS_HIDE); + this.place(); + } else { + this.showView(VIEWS.MONTHS); + } + } + } + } + }, { + key: 'hideView', + value: function hideView() { + if (!this.inline && this.options.autoHide) { + this.hide(); + } + } + }, { + key: 'place', + value: function place() { + if (this.inline) { + return; + } + + var $this = this.$element, + options = this.options, + $picker = this.$picker; + + var containerWidth = $document.outerWidth(); + var containerHeight = $document.outerHeight(); + var elementWidth = $this.outerWidth(); + var elementHeight = $this.outerHeight(); + var width = $picker.width(); + var height = $picker.height(); + + var _$this$offset = $this.offset(), + left = _$this$offset.left, + top = _$this$offset.top; + + var offset = parseFloat(options.offset); + var placement = CLASS_TOP_LEFT; + + if (isNaN(offset)) { + offset = 10; + } + + if (top > height && top + elementHeight + height > containerHeight) { + top -= height + offset; + placement = CLASS_BOTTOM_LEFT; + } else { + top += elementHeight + offset; + } + + if (left + width > containerWidth) { + left += elementWidth - width; + placement = placement.replace('left', 'right'); + } + + $picker.removeClass(CLASS_PLACEMENTS).addClass(placement).css({ + top: top, + left: left, + zIndex: parseInt(options.zIndex, 10) + }); + } + + // A shortcut for triggering custom events + + }, { + key: 'trigger', + value: function trigger(type, data) { + var e = $.Event(type, data); + + this.$element.trigger(e); + + return e; + } + }, { + key: 'createItem', + value: function createItem(data) { + var options = this.options; + var itemTag = options.itemTag; + + var item = { + text: '', + view: '', + muted: false, + picked: false, + disabled: false, + highlighted: false + }; + var classes = []; + + $.extend(item, data); + + if (item.muted) { + classes.push(options.mutedClass); + } + + if (item.highlighted) { + classes.push(options.highlightedClass); + } + + if (item.picked) { + classes.push(options.pickedClass); + } + + if (item.disabled) { + classes.push(options.disabledClass); + } + + return '<' + itemTag + ' class="' + classes.join(' ') + '" data-view="' + item.view + '">' + item.text + ''; + } + }, { + key: 'getValue', + value: function getValue() { + var $this = this.$element; + + return this.isInput ? $this.val() : $this.text(); + } + }, { + key: 'setValue', + value: function setValue() { + var value = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ''; + + var $this = this.$element; + + if (this.isInput) { + $this.val(value); + } else { + $this.text(value); + } + } + }], [{ + key: 'setDefaults', + value: function setDefaults() { + var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + + $.extend(DEFAULTS, LANGUAGES[options.language], options); + } + }]); + + return Datepicker; +}(); + +$.extend(Datepicker.prototype, render, handlers, methods); + +var AnotherDatepicker = $.fn.datepicker; + +$.fn.datepicker = function jQueryDatepicker(option) { + for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { + args[_key - 1] = arguments[_key]; + } + + var result = void 0; + + this.each(function each() { + var $this = $(this); + var data = $this.data('datepicker'); + + if (!data) { + if (/destroy/.test(option)) { + return; + } + + var options = $.extend({}, $this.data(), $.isPlainObject(option) && option); + + data = new Datepicker(this, options); + $this.data('datepicker', data); + } + + if (typeof option === 'string') { + var fn = data[option]; + + if ($.isFunction(fn)) { + result = fn.apply(data, args); + } + } + }); + + return typeof result !== 'undefined' ? result : this; +}; + +$.fn.datepicker.Constructor = Datepicker; +$.fn.datepicker.languages = LANGUAGES; +$.fn.datepicker.setDefaults = Datepicker.setDefaults; +$.fn.datepicker.noConflict = function noConflict() { + $.fn.datepicker = AnotherDatepicker; + return this; +}; diff --git a/dist/datepicker.css b/dist/datepicker.css index c3d1328..7d5fc20 100644 --- a/dist/datepicker.css +++ b/dist/datepicker.css @@ -1,62 +1,50 @@ /*! - * Datepicker v0.5.3 + * Datepicker v0.6.0 * https://github.com/fengyuanchen/datepicker - * + * * Copyright (c) 2014-2017 Fengyuan Chen * Released under the MIT license - * - * Date: 2017-06-15T11:00:53.699Z + * + * Date: 2017-09-24T11:42:09.338Z */ .datepicker-container { + background-color: #fff; + direction: ltr; font-size: 12px; + left: 0; line-height: 30px; - position: fixed; - z-index: -1; top: 0; - left: 0; - - width: 210px; - - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - - background-color: #fff; - - direction: ltr !important; -ms-touch-action: none; - touch-action: none; + touch-action: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + width: 210px; + z-index: -1; -webkit-tap-highlight-color: transparent; -webkit-touch-callout: none; } -.datepicker-container:before, -.datepicker-container:after { - position: absolute; - +.datepicker-container::before, +.datepicker-container::after { + border: 5px solid transparent; + content: " "; display: block; - - width: 0; height: 0; - - content: ' '; - - border: 5px solid transparent; + position: absolute; + width: 0; } .datepicker-dropdown { - position: absolute; - z-index: 1; - - -webkit-box-sizing: content-box; - -moz-box-sizing: content-box; - box-sizing: content-box; - border: 1px solid #ccc; -webkit-box-shadow: 0 3px 6px #ccc; - box-shadow: 0 3px 6px #ccc; + box-shadow: 0 3px 6px #ccc; + -webkit-box-sizing: content-box; + box-sizing: content-box; + position: absolute; + z-index: 1; } .datepicker-inline { @@ -68,26 +56,24 @@ border-top-color: #39f; } -.datepicker-top-left:before, -.datepicker-top-left:after, -.datepicker-top-right:before, -.datepicker-top-right:after { - top: -5px; - left: 10px; - +.datepicker-top-left::before, +.datepicker-top-left::after, +.datepicker-top-right::before, +.datepicker-top-right::after { border-top: 0; + left: 10px; + top: -5px; } -.datepicker-top-left:before, -.datepicker-top-right:before { +.datepicker-top-left::before, +.datepicker-top-right::before { border-bottom-color: #39f; } -.datepicker-top-left:after, -.datepicker-top-right:after { - top: -4px; - +.datepicker-top-left::after, +.datepicker-top-right::after { border-bottom-color: #fff; + top: -4px; } .datepicker-bottom-left, @@ -95,71 +81,64 @@ border-bottom-color: #39f; } -.datepicker-bottom-left:before, -.datepicker-bottom-left:after, -.datepicker-bottom-right:before, -.datepicker-bottom-right:after { +.datepicker-bottom-left::before, +.datepicker-bottom-left::after, +.datepicker-bottom-right::before, +.datepicker-bottom-right::after { + border-bottom: 0; bottom: -5px; left: 10px; - - border-bottom: 0; } -.datepicker-bottom-left:before, -.datepicker-bottom-right:before { +.datepicker-bottom-left::before, +.datepicker-bottom-right::before { border-top-color: #39f; } -.datepicker-bottom-left:after, -.datepicker-bottom-right:after { - bottom: -4px; - +.datepicker-bottom-left::after, +.datepicker-bottom-right::after { border-top-color: #fff; + bottom: -4px; } -.datepicker-top-right:before, -.datepicker-top-right:after, -.datepicker-bottom-right:before, -.datepicker-bottom-right:after { - right: 10px; +.datepicker-top-right::before, +.datepicker-top-right::after, +.datepicker-bottom-right::before, +.datepicker-bottom-right::after { left: auto; + right: 10px; } -.datepicker-panel > ul:before, -.datepicker-panel > ul:after { - display: table; - - content: ' '; +.datepicker-panel > ul { + margin: 0; + padding: 0; + width: 102%; } -.datepicker-panel > ul:after { - clear: both; +.datepicker-panel > ul::before, +.datepicker-panel > ul::after { + content: " "; + display: table; } -.datepicker-panel > ul { - width: 102%; - margin: 0; - padding: 0; +.datepicker-panel > ul::after { + clear: both; } .datepicker-panel > ul > li { + background-color: #fff; + cursor: pointer; float: left; - - width: 30px; height: 30px; + list-style: none; margin: 0; padding: 0; - - list-style: none; - - cursor: pointer; text-align: center; - - background-color: #fff; + width: 30px; } .datepicker-panel > ul > li:hover { - background-color: #e6f2ff; + background-color: lighten(#39f 35%); } .datepicker-panel > ul > li.muted, @@ -168,11 +147,11 @@ } .datepicker-panel > ul > li.highlighted { - background-color: #e6f2ff; + background-color: lighten(#39f 35%); } .datepicker-panel > ul > li.highlighted:hover { - background-color: #cce6ff; + background-color: lighten(#39f 30%); } .datepicker-panel > ul > li.picked, @@ -182,46 +161,43 @@ .datepicker-panel > ul > li.disabled, .datepicker-panel > ul > li.disabled:hover { - cursor: default; - - color: #ccc; background-color: #fff; + color: #ccc; + cursor: default; } .datepicker-panel > ul > li.disabled.highlighted, .datepicker-panel > ul > li.disabled:hover.highlighted { - background-color: #e6f2ff; + background-color: lighten(#39f 35%); } -.datepicker-panel > ul > li[data-view='years prev'], -.datepicker-panel > ul > li[data-view='year prev'], -.datepicker-panel > ul > li[data-view='month prev'], -.datepicker-panel > ul > li[data-view='years next'], -.datepicker-panel > ul > li[data-view='year next'], -.datepicker-panel > ul > li[data-view='month next'], -.datepicker-panel > ul > li[data-view='next'] { +.datepicker-panel > ul > li[data-view="years prev"], +.datepicker-panel > ul > li[data-view="year prev"], +.datepicker-panel > ul > li[data-view="month prev"], +.datepicker-panel > ul > li[data-view="years next"], +.datepicker-panel > ul > li[data-view="year next"], +.datepicker-panel > ul > li[data-view="month next"], +.datepicker-panel > ul > li[data-view="next"] { font-size: 18px; } -.datepicker-panel > ul > li[data-view='years current'], -.datepicker-panel > ul > li[data-view='year current'], -.datepicker-panel > ul > li[data-view='month current'] { +.datepicker-panel > ul > li[data-view="years current"], +.datepicker-panel > ul > li[data-view="year current"], +.datepicker-panel > ul > li[data-view="month current"] { width: 150px; } -.datepicker-panel > ul[data-view='years'] > li, -.datepicker-panel > ul[data-view='months'] > li { +.datepicker-panel > ul[data-view="years"] > li, +.datepicker-panel > ul[data-view="months"] > li { + height: 52.5px; line-height: 52.5px; - width: 52.5px; - height: 52.5px; } -.datepicker-panel > ul[data-view='week'] > li, -.datepicker-panel > ul[data-view='week'] > li:hover { - cursor: default; - +.datepicker-panel > ul[data-view="week"] > li, +.datepicker-panel > ul[data-view="week"] > li:hover { background-color: #fff; + cursor: default; } .datepicker-hide { diff --git a/dist/datepicker.esm.js b/dist/datepicker.esm.js new file mode 100644 index 0000000..2f93404 --- /dev/null +++ b/dist/datepicker.esm.js @@ -0,0 +1,1509 @@ +/*! + * Datepicker v0.6.0 + * https://github.com/fengyuanchen/datepicker + * + * Copyright (c) 2014-2017 Fengyuan Chen + * Released under the MIT license + * + * Date: 2017-09-24T11:42:13.421Z + */ +import $ from 'jquery'; + +var DEFAULTS = { + // Show the datepicker automatically when initialized + autoShow: false, + + // Hide the datepicker automatically when picked + autoHide: false, + + // Pick the initial date automatically when initialized + autoPick: false, + + // Enable inline mode + inline: false, + + // A element (or selector) for putting the datepicker + container: null, + + // A element (or selector) for triggering the datepicker + trigger: null, + + // The ISO language code (built-in: en-US) + language: '', + + // The date string format + format: 'mm/dd/yyyy', + + // The initial date + date: null, + + // The start view date + startDate: null, + + // The end view date + endDate: null, + + // The start view when initialized + startView: 0, // 0 for days, 1 for months, 2 for years + + // The start day of the week + // 0 for Sunday, 1 for Monday, 2 for Tuesday, 3 for Wednesday, + // 4 for Thursday, 5 for Friday, 6 for Saturday + weekStart: 0, + + // Show year before month on the datepicker header + yearFirst: false, + + // A string suffix to the year number. + yearSuffix: '', + + // Days' name of the week. + days: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], + + // Shorter days' name + daysShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], + + // Shortest days' name + daysMin: ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'], + + // Months' name + months: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'], + + // Shorter months' name + monthsShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], + + // A element tag for each item of years, months and days + itemTag: 'li', + + // A class (CSS) for muted date item + mutedClass: 'muted', + + // A class (CSS) for picked date item + pickedClass: 'picked', + + // A class (CSS) for disabled date item + disabledClass: 'disabled', + + // A class (CSS) for highlight date item + highlightedClass: 'highlighted', + + // The template of the datepicker + template: '
' + '
' + '' + '' + '
' + '
' + '' + '' + '
' + '
' + '' + '' + '' + '
' + '
', + + // The offset top or bottom of the datepicker from the element + offset: 10, + + // The `z-index` of the datepicker + zIndex: 1000, + + // Filter each date item (return `false` to disable a date item) + filter: null, + + // Event shortcuts + show: null, + hide: null, + pick: null +}; + +var NAMESPACE = 'datepicker'; +var EVENT_CLICK = 'click.' + NAMESPACE; +var EVENT_FOCUS = 'focus.' + NAMESPACE; +var EVENT_HIDE = 'hide.' + NAMESPACE; +var EVENT_KEYUP = 'keyup.' + NAMESPACE; +var EVENT_PICK = 'pick.' + NAMESPACE; +var EVENT_RESIZE = 'resize.' + NAMESPACE; +var EVENT_SHOW = 'show.' + NAMESPACE; +var CLASS_HIDE = NAMESPACE + '-hide'; +var LANGUAGES = {}; +var VIEWS = { + DAYS: 0, + MONTHS: 1, + YEARS: 2 +}; + +var toString = Object.prototype.toString; + + +function typeOf(obj) { + return toString.call(obj).slice(8, -1).toLowerCase(); +} + +function isString(value) { + return typeof value === 'string'; +} + +var isNaN = Number.isNaN || window.isNaN; + +function isNumber(value) { + return typeof value === 'number' && !isNaN(value); +} + +function isUndefined(value) { + return typeof value === 'undefined'; +} + +function isDate(value) { + return typeOf(value) === 'date'; +} + +function proxy(fn, context) { + for (var _len = arguments.length, args = Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) { + args[_key - 2] = arguments[_key]; + } + + return function () { + for (var _len2 = arguments.length, args2 = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { + args2[_key2] = arguments[_key2]; + } + + return fn.apply(context, args.concat(args2)); + }; +} + +function selectorOf(view) { + return '[data-view="' + view + '"]'; +} + +function isLeapYear(year) { + return year % 4 === 0 && year % 100 !== 0 || year % 400 === 0; +} + +function getDaysInMonth(year, month) { + return [31, isLeapYear(year) ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month]; +} + +function getMinDay(year, month, day) { + return Math.min(day, getDaysInMonth(year, month)); +} + +var formatParts = /(y|m|d)+/g; + +function parseFormat(format) { + var source = String(format).toLowerCase(); + var parts = source.match(formatParts); + + if (!parts || parts.length === 0) { + throw new Error('Invalid date format.'); + } + + format = { + source: source, + parts: parts + }; + + $.each(parts, function (i, part) { + switch (part) { + case 'dd': + case 'd': + format.hasDay = true; + break; + + case 'mm': + case 'm': + format.hasMonth = true; + break; + + case 'yyyy': + case 'yy': + format.hasYear = true; + break; + + default: + } + }); + + return format; +} + +var _window$1 = window; +var document$2 = _window$1.document; + +var $window = $(window); +var $document$1 = $(document$2); +var REGEXP_DIGITS = /\d+/g; + +var methods = { + // Show the datepicker + show: function show() { + if (!this.built) { + this.build(); + } + + if (this.shown) { + return; + } + + if (this.trigger(EVENT_SHOW).isDefaultPrevented()) { + return; + } + + this.shown = true; + this.$picker.removeClass(CLASS_HIDE).on(EVENT_CLICK, $.proxy(this.click, this)); + this.showView(this.options.startView); + + if (!this.inline) { + $window.on(EVENT_RESIZE, this.onResize = proxy(this.place, this)); + $document$1.on(EVENT_CLICK, this.onGlobalClick = proxy(this.globalClick, this)); + $document$1.on(EVENT_KEYUP, this.onGlobalKeyup = proxy(this.globalKeyup, this)); + this.place(); + } + }, + + + // Hide the datepicker + hide: function hide() { + if (!this.shown) { + return; + } + + if (this.trigger(EVENT_HIDE).isDefaultPrevented()) { + return; + } + + this.shown = false; + this.$picker.addClass(CLASS_HIDE).off(EVENT_CLICK, this.click); + + if (!this.inline) { + $window.off(EVENT_RESIZE, this.onResize); + $document$1.off(EVENT_CLICK, this.onGlobalClick); + $document$1.off(EVENT_KEYUP, this.onGlobalKeyup); + } + }, + toggle: function toggle() { + if (this.shown) { + this.hide(); + } else { + this.show(); + } + }, + + + // Update the datepicker with the current input value + update: function update() { + var value = this.getValue(); + + if (value === this.oldValue) { + return; + } + + this.setDate(value, true); + this.oldValue = value; + }, + + + /** + * Pick the current date to the element + * + * @param {String} _view (private) + */ + pick: function pick(_view) { + var $this = this.$element; + var date = this.date; + + + if (this.trigger(EVENT_PICK, { + view: _view || '', + date: date + }).isDefaultPrevented()) { + return; + } + + date = this.formatDate(this.date); + this.setValue(date); + + if (this.isInput) { + $this.trigger('input'); + $this.trigger('change'); + } + }, + + + // Reset the datepicker + reset: function reset() { + this.setDate(this.initialDate, true); + this.setValue(this.initialValue); + + if (this.shown) { + this.showView(this.options.startView); + } + }, + + + /** + * Get the month name with given argument or the current date + * + * @param {Number} month (optional) + * @param {Boolean} short (optional) + * @return {String} (month name) + */ + getMonthName: function getMonthName(month, short) { + var options = this.options; + var monthsShort = options.monthsShort; + var months = options.months; + + + if ($.isNumeric(month)) { + month = Number(month); + } else if (isUndefined(short)) { + short = month; + } + + if (short === true) { + months = monthsShort; + } + + return months[isNumber(month) ? month : this.date.getMonth()]; + }, + + + /** + * Get the day name with given argument or the current date + * + * @param {Number} day (optional) + * @param {Boolean} short (optional) + * @param {Boolean} min (optional) + * @return {String} (day name) + */ + getDayName: function getDayName(day, short, min) { + var options = this.options; + var days = options.days; + + + if ($.isNumeric(day)) { + day = Number(day); + } else { + if (isUndefined(min)) { + min = short; + } + + if (isUndefined(short)) { + short = day; + } + } + + if (min) { + days = options.daysMin; + } else if (short) { + days = options.daysShort; + } + + return days[isNumber(day) ? day : this.date.getDay()]; + }, + + + /** + * Get the current date + * + * @param {Boolean} formatted (optional) + * @return {Date|String} (date) + */ + getDate: function getDate(formatted) { + var date = this.date; + + + return formatted ? this.formatDate(date) : new Date(date); + }, + + + /** + * Set the current date with a new date + * + * @param {Date} date + * @param {Boolean} _updated (private) + */ + setDate: function setDate(date, _updated) { + var filter = this.options.filter; + + + if (isDate(date) || isString(date)) { + date = this.parseDate(date); + + if ($.isFunction(filter) && filter.call(this.$element, date) === false) { + return; + } + + this.date = date; + this.viewDate = new Date(date); + + if (!_updated) { + this.pick(); + } + + if (this.built) { + this.render(); + } + } + }, + + + /** + * Set the start view date with a new date + * + * @param {Date} date + */ + setStartDate: function setStartDate(date) { + if (isDate(date) || isString(date)) { + this.startDate = this.parseDate(date); + + if (this.built) { + this.render(); + } + } + }, + + + /** + * Set the end view date with a new date + * + * @param {Date} date + */ + setEndDate: function setEndDate(date) { + if (isDate(date) || isString(date)) { + this.endDate = this.parseDate(date); + + if (this.built) { + this.render(); + } + } + }, + + + /** + * Parse a date string with the set date format + * + * @param {String} date + * @return {Date} (parsed date) + */ + parseDate: function parseDate(date) { + var format = this.format; + + var parts = []; + + if (isDate(date)) { + return new Date(date.getFullYear(), date.getMonth(), date.getDate()); + } else if (isString(date)) { + parts = date.match(REGEXP_DIGITS) || []; + } + + date = new Date(); + + var length = format.parts.length; + + var year = date.getFullYear(); + var day = date.getDate(); + var month = date.getMonth(); + + if (parts.length === length) { + $.each(parts, function (i, part) { + var value = parseInt(part, 10) || 1; + + switch (format.parts[i]) { + case 'dd': + case 'd': + day = value; + break; + + case 'mm': + case 'm': + month = value - 1; + break; + + case 'yy': + year = 2000 + value; + break; + + case 'yyyy': + year = value; + break; + + default: + } + }); + } + + return new Date(year, month, day); + }, + + + /** + * Format a date object to a string with the set date format + * + * @param {Date} date + * @return {String} (formatted date) + */ + formatDate: function formatDate(date) { + var format = this.format; + + var formatted = ''; + + if (isDate(date)) { + var year = date.getFullYear(); + var values = { + d: date.getDate(), + m: date.getMonth() + 1, + yy: year.toString().substring(2), + yyyy: year + }; + + values.dd = (values.d < 10 ? '0' : '') + values.d; + values.mm = (values.m < 10 ? '0' : '') + values.m; + formatted = format.source; + $.each(format.parts, function (i, part) { + formatted = formatted.replace(part, values[part]); + }); + } + + return formatted; + }, + + + // Destroy the datepicker and remove the instance from the target element + destroy: function destroy() { + this.unbind(); + this.unbuild(); + this.$element.removeData(NAMESPACE); + } +}; + +var handlers = { + click: function click(e) { + var $target = $(e.target); + var options = this.options, + viewDate = this.viewDate, + format = this.format; + + + e.stopPropagation(); + e.preventDefault(); + + if ($target.hasClass('disabled')) { + return; + } + + var view = $target.data('view'); + var viewYear = viewDate.getFullYear(); + var viewMonth = viewDate.getMonth(); + var viewDay = viewDate.getDate(); + + switch (view) { + case 'years prev': + case 'years next': + { + viewYear = view === 'years prev' ? viewYear - 10 : viewYear + 10; + this.viewDate = new Date(viewYear, viewMonth, getMinDay(viewYear, viewMonth, viewDay)); + this.renderYears(); + break; + } + + case 'year prev': + case 'year next': + viewYear = view === 'year prev' ? viewYear - 1 : viewYear + 1; + this.viewDate = new Date(viewYear, viewMonth, getMinDay(viewYear, viewMonth, viewDay)); + this.renderMonths(); + break; + + case 'year current': + if (format.hasYear) { + this.showView(VIEWS.YEARS); + } + + break; + + case 'year picked': + if (format.hasMonth) { + this.showView(VIEWS.MONTHS); + } else { + $target.addClass(options.pickedClass).siblings().removeClass(options.pickedClass); + this.hideView(); + } + + this.pick('year'); + break; + + case 'year': + viewYear = parseInt($target.text(), 10); + this.date = new Date(viewYear, viewMonth, getMinDay(viewYear, viewMonth, viewDay)); + + if (format.hasMonth) { + this.viewDate = new Date(this.date); + this.showView(VIEWS.MONTHS); + } else { + $target.addClass(options.pickedClass).siblings().removeClass(options.pickedClass); + this.hideView(); + } + + this.pick('year'); + break; + + case 'month prev': + case 'month next': + viewMonth = view === 'month prev' ? viewMonth - 1 : viewMonth + 1; + this.viewDate = new Date(viewYear, viewMonth, getMinDay(viewYear, viewMonth, viewDay)); + this.renderDays(); + break; + + case 'month current': + if (format.hasMonth) { + this.showView(VIEWS.MONTHS); + } + + break; + + case 'month picked': + if (format.hasDay) { + this.showView(VIEWS.DAYS); + } else { + $target.addClass(options.pickedClass).siblings().removeClass(options.pickedClass); + this.hideView(); + } + + this.pick('month'); + break; + + case 'month': + viewMonth = $.inArray($target.text(), options.monthsShort); + this.date = new Date(viewYear, viewMonth, getMinDay(viewYear, viewMonth, viewDay)); + + if (format.hasDay) { + this.viewDate = new Date(viewYear, viewMonth, getMinDay(viewYear, viewMonth, viewDay)); + this.showView(VIEWS.DAYS); + } else { + $target.addClass(options.pickedClass).siblings().removeClass(options.pickedClass); + this.hideView(); + } + + this.pick('month'); + break; + + case 'day prev': + case 'day next': + case 'day': + if (view === 'day prev') { + viewMonth -= 1; + } else if (view === 'day next') { + viewMonth += 1; + } + + viewDay = parseInt($target.text(), 10); + this.date = new Date(viewYear, viewMonth, viewDay); + this.viewDate = new Date(viewYear, viewMonth, viewDay); + this.renderDays(); + + if (view === 'day') { + this.hideView(); + } + + this.pick('day'); + break; + + case 'day picked': + this.hideView(); + this.pick('day'); + break; + + default: + } + }, + globalClick: function globalClick(_ref) { + var target = _ref.target; + var element = this.element, + $trigger = this.$trigger; + + var trigger = $trigger[0]; + var hidden = true; + + while (target !== document) { + if (target === trigger || target === element) { + hidden = false; + break; + } + + target = target.parentNode; + } + + if (hidden) { + this.hide(); + } + }, + keyup: function keyup() { + this.update(); + }, + globalKeyup: function globalKeyup(_ref2) { + var target = _ref2.target, + key = _ref2.key, + keyCode = _ref2.keyCode; + + if (this.isInput && target !== this.element && this.shown && (key === 'Tab' || keyCode === 9)) { + this.hide(); + } + } +}; + +var render = { + render: function render() { + this.renderYears(); + this.renderMonths(); + this.renderDays(); + }, + renderWeek: function renderWeek() { + var _this = this; + + var items = []; + var _options = this.options, + weekStart = _options.weekStart, + daysMin = _options.daysMin; + + + weekStart = parseInt(weekStart, 10) % 7; + daysMin = daysMin.slice(weekStart).concat(daysMin.slice(0, weekStart)); + $.each(daysMin, function (i, day) { + items.push(_this.createItem({ + text: day + })); + }); + + this.$week.html(items.join('')); + }, + renderYears: function renderYears() { + var options = this.options, + startDate = this.startDate, + endDate = this.endDate; + var disabledClass = options.disabledClass, + filter = options.filter, + yearSuffix = options.yearSuffix; + + var viewYear = this.viewDate.getFullYear(); + var now = new Date(); + var thisYear = now.getFullYear(); + var year = this.date.getFullYear(); + var start = -5; + var end = 6; + var items = []; + var prevDisabled = false; + var nextDisabled = false; + var i = void 0; + + for (i = start; i <= end; i += 1) { + var date = new Date(viewYear + i, 1, 1); + var disabled = false; + + if (startDate) { + disabled = date.getFullYear() < startDate.getFullYear(); + + if (i === start) { + prevDisabled = disabled; + } + } + + if (!disabled && endDate) { + disabled = date.getFullYear() > endDate.getFullYear(); + + if (i === end) { + nextDisabled = disabled; + } + } + + if (!disabled && filter) { + disabled = filter.call(this.$element, date) === false; + } + + var picked = viewYear + i === year; + var view = picked ? 'year picked' : 'year'; + + items.push(this.createItem({ + picked: picked, + disabled: disabled, + muted: i === start || i === end, + text: viewYear + i, + view: disabled ? 'year disabled' : view, + highlighted: date.getFullYear() === thisYear + })); + } + + this.$yearsPrev.toggleClass(disabledClass, prevDisabled); + this.$yearsNext.toggleClass(disabledClass, nextDisabled); + this.$yearsCurrent.toggleClass(disabledClass, true).html(viewYear + start + yearSuffix + ' - ' + (viewYear + end) + yearSuffix); + this.$years.html(items.join('')); + }, + renderMonths: function renderMonths() { + var options = this.options, + startDate = this.startDate, + endDate = this.endDate, + viewDate = this.viewDate; + + var disabledClass = options.disabledClass || ''; + var months = options.monthsShort; + var filter = $.isFunction(options.filter) && options.filter; + var viewYear = viewDate.getFullYear(); + var now = new Date(); + var thisYear = now.getFullYear(); + var thisMonth = now.getMonth(); + var year = this.date.getFullYear(); + var month = this.date.getMonth(); + var items = []; + var prevDisabled = false; + var nextDisabled = false; + var i = void 0; + + for (i = 0; i <= 11; i += 1) { + var date = new Date(viewYear, i, 1); + var disabled = false; + + if (startDate) { + prevDisabled = date.getFullYear() === startDate.getFullYear(); + disabled = prevDisabled && date.getMonth() < startDate.getMonth(); + } + + if (!disabled && endDate) { + nextDisabled = date.getFullYear() === endDate.getFullYear(); + disabled = nextDisabled && date.getMonth() > endDate.getMonth(); + } + + if (!disabled && filter) { + disabled = filter.call(this.$element, date) === false; + } + + var picked = viewYear === year && i === month; + var view = picked ? 'month picked' : 'month'; + + items.push(this.createItem({ + disabled: disabled, + picked: picked, + highlighted: viewYear === thisYear && date.getMonth() === thisMonth, + index: i, + text: months[i], + view: disabled ? 'month disabled' : view + })); + } + + this.$yearPrev.toggleClass(disabledClass, prevDisabled); + this.$yearNext.toggleClass(disabledClass, nextDisabled); + this.$yearCurrent.toggleClass(disabledClass, prevDisabled && nextDisabled).html(viewYear + options.yearSuffix || ''); + this.$months.html(items.join('')); + }, + renderDays: function renderDays() { + var $element = this.$element, + options = this.options, + startDate = this.startDate, + endDate = this.endDate, + viewDate = this.viewDate, + currentDate = this.date; + var disabledClass = options.disabledClass, + filter = options.filter, + monthsShort = options.monthsShort, + weekStart = options.weekStart, + yearSuffix = options.yearSuffix; + + var viewYear = viewDate.getFullYear(); + var viewMonth = viewDate.getMonth(); + var now = new Date(); + var thisYear = now.getFullYear(); + var thisMonth = now.getMonth(); + var thisDay = now.getDate(); + var year = currentDate.getFullYear(); + var month = currentDate.getMonth(); + var day = currentDate.getDate(); + var length = void 0; + var i = void 0; + var n = void 0; + + // Days of prev month + // ----------------------------------------------------------------------- + + var prevItems = []; + var prevViewYear = viewYear; + var prevViewMonth = viewMonth; + var prevDisabled = false; + + if (viewMonth === 0) { + prevViewYear -= 1; + prevViewMonth = 11; + } else { + prevViewMonth -= 1; + } + + // The length of the days of prev month + length = getDaysInMonth(prevViewYear, prevViewMonth); + + // The first day of current month + var firstDay = new Date(viewYear, viewMonth, 1); + + // The visible length of the days of prev month + // [0,1,2,3,4,5,6] - [0,1,2,3,4,5,6] => [-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6] + n = firstDay.getDay() - parseInt(weekStart, 10) % 7; + + // [-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6] => [1,2,3,4,5,6,7] + if (n <= 0) { + n += 7; + } + + if (startDate) { + prevDisabled = firstDay.getTime() <= startDate.getTime(); + } + + for (i = length - (n - 1); i <= length; i += 1) { + var prevViewDate = new Date(prevViewYear, prevViewMonth, i); + var disabled = false; + + if (startDate) { + disabled = prevViewDate.getTime() < startDate.getTime(); + } + + if (!disabled && filter) { + disabled = filter.call($element, prevViewDate) === false; + } + + prevItems.push(this.createItem({ + disabled: disabled, + highlighted: prevViewYear === thisYear && prevViewMonth === thisMonth && prevViewDate.getDate() === thisDay, + muted: true, + picked: prevViewYear === year && prevViewMonth === month && i === day, + text: i, + view: 'day prev' + })); + } + + // Days of next month + // ----------------------------------------------------------------------- + + var nextItems = []; + var nextViewYear = viewYear; + var nextViewMonth = viewMonth; + var nextDisabled = false; + + if (viewMonth === 11) { + nextViewYear += 1; + nextViewMonth = 0; + } else { + nextViewMonth += 1; + } + + // The length of the days of current month + length = getDaysInMonth(viewYear, viewMonth); + + // The visible length of next month (42 means 6 rows and 7 columns) + n = 42 - (prevItems.length + length); + + // The last day of current month + var lastDate = new Date(viewYear, viewMonth, length); + + if (endDate) { + nextDisabled = lastDate.getTime() >= endDate.getTime(); + } + + for (i = 1; i <= n; i += 1) { + var date = new Date(nextViewYear, nextViewMonth, i); + var picked = nextViewYear === year && nextViewMonth === month && i === day; + var _disabled = false; + + if (endDate) { + _disabled = date.getTime() > endDate.getTime(); + } + + if (!_disabled && filter) { + _disabled = filter.call($element, date) === false; + } + + nextItems.push(this.createItem({ + disabled: _disabled, + picked: picked, + highlighted: nextViewYear === thisYear && nextViewMonth === thisMonth && date.getDate() === thisDay, + muted: true, + text: i, + view: 'day next' + })); + } + + // Days of current month + // ----------------------------------------------------------------------- + + var items = []; + + for (i = 1; i <= length; i += 1) { + var _date = new Date(viewYear, viewMonth, i); + var _disabled2 = false; + + if (startDate) { + _disabled2 = _date.getTime() < startDate.getTime(); + } + + if (!_disabled2 && endDate) { + _disabled2 = _date.getTime() > endDate.getTime(); + } + + if (!_disabled2 && filter) { + _disabled2 = filter.call($element, _date) === false; + } + + var _picked = viewYear === year && viewMonth === month && i === day; + var view = _picked ? 'day picked' : 'day'; + + items.push(this.createItem({ + disabled: _disabled2, + picked: _picked, + highlighted: viewYear === thisYear && viewMonth === thisMonth && _date.getDate() === thisDay, + text: i, + view: _disabled2 ? 'day disabled' : view + })); + } + + // Render days picker + // ----------------------------------------------------------------------- + + this.$monthPrev.toggleClass(disabledClass, prevDisabled); + this.$monthNext.toggleClass(disabledClass, nextDisabled); + this.$monthCurrent.toggleClass(disabledClass, prevDisabled && nextDisabled).html(options.yearFirst ? viewYear + yearSuffix + ' ' + monthsShort[viewMonth] : monthsShort[viewMonth] + ' ' + viewYear + yearSuffix); + this.$days.html(prevItems.join('') + items.join('') + nextItems.join('')); + } +}; + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +var _window = window; +var document$1 = _window.document; + +var $document = $(document$1); + +// Classes +var CLASS_TOP_LEFT = NAMESPACE + '-top-left'; +var CLASS_TOP_RIGHT = NAMESPACE + '-top-right'; +var CLASS_BOTTOM_LEFT = NAMESPACE + '-bottom-left'; +var CLASS_BOTTOM_RIGHT = NAMESPACE + '-bottom-right'; +var CLASS_PLACEMENTS = [CLASS_TOP_LEFT, CLASS_TOP_RIGHT, CLASS_BOTTOM_LEFT, CLASS_BOTTOM_RIGHT].join(' '); + +var Datepicker = function () { + function Datepicker(element) { + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + + _classCallCheck(this, Datepicker); + + this.$element = $(element); + this.element = element; + this.options = $.extend({}, DEFAULTS, LANGUAGES[options.language], options); + this.built = false; + this.shown = false; + this.isInput = false; + this.inline = false; + this.initialValue = ''; + this.initialDate = null; + this.startDate = null; + this.endDate = null; + this.init(); + } + + _createClass(Datepicker, [{ + key: 'init', + value: function init() { + var $this = this.$element, + options = this.options; + var startDate = options.startDate, + endDate = options.endDate, + date = options.date; + + + this.$trigger = $(options.trigger); + this.isInput = $this.is('input') || $this.is('textarea'); + this.inline = options.inline && (options.container || !this.isInput); + this.format = parseFormat(options.format); + + var initialValue = this.getValue(); + + this.initialValue = initialValue; + this.oldValue = initialValue; + date = this.parseDate(date || initialValue); + + if (startDate) { + startDate = this.parseDate(startDate); + + if (date.getTime() < startDate.getTime()) { + date = new Date(startDate); + } + + this.startDate = startDate; + } + + if (endDate) { + endDate = this.parseDate(endDate); + + if (startDate && endDate.getTime() < startDate.getTime()) { + endDate = new Date(startDate); + } + + if (date.getTime() > endDate.getTime()) { + date = new Date(endDate); + } + + this.endDate = endDate; + } + + this.date = date; + this.viewDate = new Date(date); + this.initialDate = new Date(this.date); + this.bind(); + + if (options.autoShow || this.inline) { + this.show(); + } + + if (options.autoPick) { + this.pick(); + } + } + }, { + key: 'build', + value: function build() { + if (this.built) { + return; + } + + this.built = true; + + var $this = this.$element, + options = this.options; + + var $picker = $(options.template); + + this.$picker = $picker; + this.$week = $picker.find(selectorOf('week')); + + // Years view + this.$yearsPicker = $picker.find(selectorOf('years picker')); + this.$yearsPrev = $picker.find(selectorOf('years prev')); + this.$yearsNext = $picker.find(selectorOf('years next')); + this.$yearsCurrent = $picker.find(selectorOf('years current')); + this.$years = $picker.find(selectorOf('years')); + + // Months view + this.$monthsPicker = $picker.find(selectorOf('months picker')); + this.$yearPrev = $picker.find(selectorOf('year prev')); + this.$yearNext = $picker.find(selectorOf('year next')); + this.$yearCurrent = $picker.find(selectorOf('year current')); + this.$months = $picker.find(selectorOf('months')); + + // Days view + this.$daysPicker = $picker.find(selectorOf('days picker')); + this.$monthPrev = $picker.find(selectorOf('month prev')); + this.$monthNext = $picker.find(selectorOf('month next')); + this.$monthCurrent = $picker.find(selectorOf('month current')); + this.$days = $picker.find(selectorOf('days')); + + if (this.inline) { + $(options.container || $this).append($picker.addClass(NAMESPACE + '-inline')); + } else { + $(document$1.body).append($picker.addClass(NAMESPACE + '-dropdown')); + $picker.addClass(CLASS_HIDE); + } + + this.renderWeek(); + } + }, { + key: 'unbuild', + value: function unbuild() { + if (!this.built) { + return; + } + + this.built = false; + this.$picker.remove(); + } + }, { + key: 'bind', + value: function bind() { + var options = this.options, + $this = this.$element; + + + if ($.isFunction(options.show)) { + $this.on(EVENT_SHOW, options.show); + } + + if ($.isFunction(options.hide)) { + $this.on(EVENT_HIDE, options.hide); + } + + if ($.isFunction(options.pick)) { + $this.on(EVENT_PICK, options.pick); + } + + if (this.isInput) { + $this.on(EVENT_KEYUP, $.proxy(this.keyup, this)); + } + + if (!this.inline) { + if (options.trigger) { + this.$trigger.on(EVENT_CLICK, $.proxy(this.toggle, this)); + } else if (this.isInput) { + $this.on(EVENT_FOCUS, $.proxy(this.show, this)); + } else { + $this.on(EVENT_CLICK, $.proxy(this.show, this)); + } + } + } + }, { + key: 'unbind', + value: function unbind() { + var $this = this.$element, + options = this.options; + + + if ($.isFunction(options.show)) { + $this.off(EVENT_SHOW, options.show); + } + + if ($.isFunction(options.hide)) { + $this.off(EVENT_HIDE, options.hide); + } + + if ($.isFunction(options.pick)) { + $this.off(EVENT_PICK, options.pick); + } + + if (this.isInput) { + $this.off(EVENT_KEYUP, this.keyup); + } + + if (!this.inline) { + if (options.trigger) { + this.$trigger.off(EVENT_CLICK, this.toggle); + } else if (this.isInput) { + $this.off(EVENT_FOCUS, this.show); + } else { + $this.off(EVENT_CLICK, this.show); + } + } + } + }, { + key: 'showView', + value: function showView(view) { + var $yearsPicker = this.$yearsPicker, + $monthsPicker = this.$monthsPicker, + $daysPicker = this.$daysPicker, + format = this.format; + + + if (format.hasYear || format.hasMonth || format.hasDay) { + switch (Number(view)) { + case VIEWS.YEARS: + $monthsPicker.addClass(CLASS_HIDE); + $daysPicker.addClass(CLASS_HIDE); + + if (format.hasYear) { + this.renderYears(); + $yearsPicker.removeClass(CLASS_HIDE); + this.place(); + } else { + this.showView(VIEWS.DAYS); + } + + break; + + case VIEWS.MONTHS: + $yearsPicker.addClass(CLASS_HIDE); + $daysPicker.addClass(CLASS_HIDE); + + if (format.hasMonth) { + this.renderMonths(); + $monthsPicker.removeClass(CLASS_HIDE); + this.place(); + } else { + this.showView(VIEWS.YEARS); + } + + break; + + // case VIEWS.DAYS: + default: + $yearsPicker.addClass(CLASS_HIDE); + $monthsPicker.addClass(CLASS_HIDE); + + if (format.hasDay) { + this.renderDays(); + $daysPicker.removeClass(CLASS_HIDE); + this.place(); + } else { + this.showView(VIEWS.MONTHS); + } + } + } + } + }, { + key: 'hideView', + value: function hideView() { + if (!this.inline && this.options.autoHide) { + this.hide(); + } + } + }, { + key: 'place', + value: function place() { + if (this.inline) { + return; + } + + var $this = this.$element, + options = this.options, + $picker = this.$picker; + + var containerWidth = $document.outerWidth(); + var containerHeight = $document.outerHeight(); + var elementWidth = $this.outerWidth(); + var elementHeight = $this.outerHeight(); + var width = $picker.width(); + var height = $picker.height(); + + var _$this$offset = $this.offset(), + left = _$this$offset.left, + top = _$this$offset.top; + + var offset = parseFloat(options.offset); + var placement = CLASS_TOP_LEFT; + + if (isNaN(offset)) { + offset = 10; + } + + if (top > height && top + elementHeight + height > containerHeight) { + top -= height + offset; + placement = CLASS_BOTTOM_LEFT; + } else { + top += elementHeight + offset; + } + + if (left + width > containerWidth) { + left += elementWidth - width; + placement = placement.replace('left', 'right'); + } + + $picker.removeClass(CLASS_PLACEMENTS).addClass(placement).css({ + top: top, + left: left, + zIndex: parseInt(options.zIndex, 10) + }); + } + + // A shortcut for triggering custom events + + }, { + key: 'trigger', + value: function trigger(type, data) { + var e = $.Event(type, data); + + this.$element.trigger(e); + + return e; + } + }, { + key: 'createItem', + value: function createItem(data) { + var options = this.options; + var itemTag = options.itemTag; + + var item = { + text: '', + view: '', + muted: false, + picked: false, + disabled: false, + highlighted: false + }; + var classes = []; + + $.extend(item, data); + + if (item.muted) { + classes.push(options.mutedClass); + } + + if (item.highlighted) { + classes.push(options.highlightedClass); + } + + if (item.picked) { + classes.push(options.pickedClass); + } + + if (item.disabled) { + classes.push(options.disabledClass); + } + + return '<' + itemTag + ' class="' + classes.join(' ') + '" data-view="' + item.view + '">' + item.text + ''; + } + }, { + key: 'getValue', + value: function getValue() { + var $this = this.$element; + + return this.isInput ? $this.val() : $this.text(); + } + }, { + key: 'setValue', + value: function setValue() { + var value = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ''; + + var $this = this.$element; + + if (this.isInput) { + $this.val(value); + } else { + $this.text(value); + } + } + }], [{ + key: 'setDefaults', + value: function setDefaults() { + var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + + $.extend(DEFAULTS, LANGUAGES[options.language], options); + } + }]); + + return Datepicker; +}(); + +$.extend(Datepicker.prototype, render, handlers, methods); + +var AnotherDatepicker = $.fn.datepicker; + +$.fn.datepicker = function jQueryDatepicker(option) { + for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { + args[_key - 1] = arguments[_key]; + } + + var result = void 0; + + this.each(function each() { + var $this = $(this); + var data = $this.data('datepicker'); + + if (!data) { + if (/destroy/.test(option)) { + return; + } + + var options = $.extend({}, $this.data(), $.isPlainObject(option) && option); + + data = new Datepicker(this, options); + $this.data('datepicker', data); + } + + if (typeof option === 'string') { + var fn = data[option]; + + if ($.isFunction(fn)) { + result = fn.apply(data, args); + } + } + }); + + return typeof result !== 'undefined' ? result : this; +}; + +$.fn.datepicker.Constructor = Datepicker; +$.fn.datepicker.languages = LANGUAGES; +$.fn.datepicker.setDefaults = Datepicker.setDefaults; +$.fn.datepicker.noConflict = function noConflict() { + $.fn.datepicker = AnotherDatepicker; + return this; +}; diff --git a/dist/datepicker.js b/dist/datepicker.js index 66a74d3..2b6560f 100644 --- a/dist/datepicker.js +++ b/dist/datepicker.js @@ -1,1567 +1,1517 @@ /*! - * Datepicker v0.5.5 + * Datepicker v0.6.0 * https://github.com/fengyuanchen/datepicker * * Copyright (c) 2014-2017 Fengyuan Chen * Released under the MIT license * - * Date: 2017-09-10T09:16:17.133Z + * Date: 2017-09-24T11:42:13.421Z */ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? factory(require('jquery')) : + typeof define === 'function' && define.amd ? define(['jquery'], factory) : + (factory(global.jQuery)); +}(this, (function ($) { 'use strict'; -(function (factory) { - if (typeof define === 'function' && define.amd) { - // AMD. Register as anonymous module. - define('datepicker', ['jquery'], factory); - } else if (typeof exports === 'object') { - // Node / CommonJS - factory(require('jquery')); - } else { - // Browser globals. - factory(jQuery); +$ = $ && $.hasOwnProperty('default') ? $['default'] : $; + +var DEFAULTS = { + // Show the datepicker automatically when initialized + autoShow: false, + + // Hide the datepicker automatically when picked + autoHide: false, + + // Pick the initial date automatically when initialized + autoPick: false, + + // Enable inline mode + inline: false, + + // A element (or selector) for putting the datepicker + container: null, + + // A element (or selector) for triggering the datepicker + trigger: null, + + // The ISO language code (built-in: en-US) + language: '', + + // The date string format + format: 'mm/dd/yyyy', + + // The initial date + date: null, + + // The start view date + startDate: null, + + // The end view date + endDate: null, + + // The start view when initialized + startView: 0, // 0 for days, 1 for months, 2 for years + + // The start day of the week + // 0 for Sunday, 1 for Monday, 2 for Tuesday, 3 for Wednesday, + // 4 for Thursday, 5 for Friday, 6 for Saturday + weekStart: 0, + + // Show year before month on the datepicker header + yearFirst: false, + + // A string suffix to the year number. + yearSuffix: '', + + // Days' name of the week. + days: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], + + // Shorter days' name + daysShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], + + // Shortest days' name + daysMin: ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'], + + // Months' name + months: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'], + + // Shorter months' name + monthsShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], + + // A element tag for each item of years, months and days + itemTag: 'li', + + // A class (CSS) for muted date item + mutedClass: 'muted', + + // A class (CSS) for picked date item + pickedClass: 'picked', + + // A class (CSS) for disabled date item + disabledClass: 'disabled', + + // A class (CSS) for highlight date item + highlightedClass: 'highlighted', + + // The template of the datepicker + template: '
' + '
' + '' + '' + '
' + '
' + '' + '' + '
' + '
' + '' + '' + '' + '
' + '
', + + // The offset top or bottom of the datepicker from the element + offset: 10, + + // The `z-index` of the datepicker + zIndex: 1000, + + // Filter each date item (return `false` to disable a date item) + filter: null, + + // Event shortcuts + show: null, + hide: null, + pick: null +}; + +var NAMESPACE = 'datepicker'; +var EVENT_CLICK = 'click.' + NAMESPACE; +var EVENT_FOCUS = 'focus.' + NAMESPACE; +var EVENT_HIDE = 'hide.' + NAMESPACE; +var EVENT_KEYUP = 'keyup.' + NAMESPACE; +var EVENT_PICK = 'pick.' + NAMESPACE; +var EVENT_RESIZE = 'resize.' + NAMESPACE; +var EVENT_SHOW = 'show.' + NAMESPACE; +var CLASS_HIDE = NAMESPACE + '-hide'; +var LANGUAGES = {}; +var VIEWS = { + DAYS: 0, + MONTHS: 1, + YEARS: 2 +}; + +var toString = Object.prototype.toString; + + +function typeOf(obj) { + return toString.call(obj).slice(8, -1).toLowerCase(); +} + +function isString(value) { + return typeof value === 'string'; +} + +var isNaN = Number.isNaN || window.isNaN; + +function isNumber(value) { + return typeof value === 'number' && !isNaN(value); +} + +function isUndefined(value) { + return typeof value === 'undefined'; +} + +function isDate(value) { + return typeOf(value) === 'date'; +} + +function proxy(fn, context) { + for (var _len = arguments.length, args = Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) { + args[_key - 2] = arguments[_key]; } -})(function ($) { - - 'use strict'; - - var $window = $(window); - var document = window.document; - var $document = $(document); - var Number = window.Number; - var NAMESPACE = 'datepicker'; - - // Events - var EVENT_CLICK = 'click.' + NAMESPACE; - var EVENT_KEYUP = 'keyup.' + NAMESPACE; - var EVENT_FOCUS = 'focus.' + NAMESPACE; - var EVENT_RESIZE = 'resize.' + NAMESPACE; - var EVENT_SHOW = 'show.' + NAMESPACE; - var EVENT_HIDE = 'hide.' + NAMESPACE; - var EVENT_PICK = 'pick.' + NAMESPACE; - - // RegExps - var REGEXP_FORMAT = /(y|m|d)+/g; - var REGEXP_DIGITS = /\d+/g; - var REGEXP_YEAR = /^\d{2,4}$/; - - // Classes - var CLASS_INLINE = NAMESPACE + '-inline'; - var CLASS_DROPDOWN = NAMESPACE + '-dropdown'; - var CLASS_TOP_LEFT = NAMESPACE + '-top-left'; - var CLASS_TOP_RIGHT = NAMESPACE + '-top-right'; - var CLASS_BOTTOM_LEFT = NAMESPACE + '-bottom-left'; - var CLASS_BOTTOM_RIGHT = NAMESPACE + '-bottom-right'; - var CLASS_PLACEMENTS = [ - CLASS_TOP_LEFT, - CLASS_TOP_RIGHT, - CLASS_BOTTOM_LEFT, - CLASS_BOTTOM_RIGHT - ].join(' '); - var CLASS_HIDE = NAMESPACE + '-hide'; - - // Views - var VIEWS = { - DAYS: 0, - MONTHS: 1, - YEARS: 2 + + return function () { + for (var _len2 = arguments.length, args2 = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { + args2[_key2] = arguments[_key2]; + } + + return fn.apply(context, args.concat(args2)); }; +} - // Maths - var min = Math.min; +function selectorOf(view) { + return '[data-view="' + view + '"]'; +} - // Utilities - var toString = Object.prototype.toString; +function isLeapYear(year) { + return year % 4 === 0 && year % 100 !== 0 || year % 400 === 0; +} - function typeOf(obj) { - return toString.call(obj).slice(8, -1).toLowerCase(); - } +function getDaysInMonth(year, month) { + return [31, isLeapYear(year) ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month]; +} - function isString(str) { - return typeof str === 'string'; - } +function getMinDay(year, month, day) { + return Math.min(day, getDaysInMonth(year, month)); +} - function isNumber(num) { - return typeof num === 'number' && !isNaN(num); - } +var formatParts = /(y|m|d)+/g; - function isUndefined(obj) { - return typeof obj === 'undefined'; - } +function parseFormat(format) { + var source = String(format).toLowerCase(); + var parts = source.match(formatParts); - function isDate(date) { - return typeOf(date) === 'date'; + if (!parts || parts.length === 0) { + throw new Error('Invalid date format.'); } - function toArray(obj, offset) { - var args = []; + format = { + source: source, + parts: parts + }; - if (Array.from) { - return Array.from(obj).slice(offset || 0); - } + $.each(parts, function (i, part) { + switch (part) { + case 'dd': + case 'd': + format.hasDay = true; + break; - // This is necessary for IE8 - if (isNumber(offset)) { - args.push(offset); - } + case 'mm': + case 'm': + format.hasMonth = true; + break; - return args.slice.apply(obj, args); - } + case 'yyyy': + case 'yy': + format.hasYear = true; + break; - // Custom proxy to avoid jQuery's guid - function proxy(fn, context) { - var args = toArray(arguments, 2); + default: + } + }); - return function () { - return fn.apply(context, args.concat(toArray(arguments))); - }; - } + return format; +} - function isLeapYear(year) { - return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0; - } +var _window$1 = window; +var document$2 = _window$1.document; - function getDaysInMonth(year, month) { - return [31, (isLeapYear(year) ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month]; - } +var $window = $(window); +var $document$1 = $(document$2); +var REGEXP_DIGITS = /\d+/g; - function parseFormat(format) { - var source = String(format).toLowerCase(); - var parts = source.match(REGEXP_FORMAT); - var length; - var i; +var methods = { + // Show the datepicker + show: function show() { + if (!this.built) { + this.build(); + } - if (!parts || parts.length === 0) { - throw new Error('Invalid date format.'); + if (this.shown) { + return; } - format = { - source: source, - parts: parts - }; + if (this.trigger(EVENT_SHOW).isDefaultPrevented()) { + return; + } - length = parts.length; + this.shown = true; + this.$picker.removeClass(CLASS_HIDE).on(EVENT_CLICK, $.proxy(this.click, this)); + this.showView(this.options.startView); - for (i = 0; i < length; i++) { - switch (parts[i]) { - case 'dd': - case 'd': - format.hasDay = true; - break; + if (!this.inline) { + $window.on(EVENT_RESIZE, this.onResize = proxy(this.place, this)); + $document$1.on(EVENT_CLICK, this.onGlobalClick = proxy(this.globalClick, this)); + $document$1.on(EVENT_KEYUP, this.onGlobalKeyup = proxy(this.globalKeyup, this)); + this.place(); + } + }, - case 'mm': - case 'm': - format.hasMonth = true; - break; - case 'yyyy': - case 'yy': - format.hasYear = true; - break; + // Hide the datepicker + hide: function hide() { + if (!this.shown) { + return; + } - // No default - } + if (this.trigger(EVENT_HIDE).isDefaultPrevented()) { + return; } - return format; - } + this.shown = false; + this.$picker.addClass(CLASS_HIDE).off(EVENT_CLICK, this.click); + + if (!this.inline) { + $window.off(EVENT_RESIZE, this.onResize); + $document$1.off(EVENT_CLICK, this.onGlobalClick); + $document$1.off(EVENT_KEYUP, this.onGlobalKeyup); + } + }, + toggle: function toggle() { + if (this.shown) { + this.hide(); + } else { + this.show(); + } + }, + - function Datepicker(element, options) { - options = $.isPlainObject(options) ? options : {}; + // Update the datepicker with the current input value + update: function update() { + var value = this.getValue(); - if (options.language) { - // Priority: Datepicker.DEFAULTS < Datepicker.LANGUAGES < options - options = $.extend({}, Datepicker.LANGUAGES[options.language], options); + if (value === this.oldValue) { + return; } - this.$element = $(element); - this.options = $.extend({}, Datepicker.DEFAULTS, options); - this.isBuilt = false; - this.isShown = false; - this.isInput = false; - this.isInline = false; - this.initialValue = ''; - this.initialDate = null; - this.startDate = null; - this.endDate = null; - this.init(); - } + this.setDate(value, true); + this.oldValue = value; + }, - Datepicker.prototype = { - constructor: Datepicker, - init: function () { - var options = this.options; - var $this = this.$element; - var startDate = options.startDate; - var endDate = options.endDate; - var date = options.date; + /** + * Pick the current date to the element + * + * @param {String} _view (private) + */ + pick: function pick(_view) { + var $this = this.$element; + var date = this.date; - this.$trigger = $(options.trigger); - this.isInput = $this.is('input') || $this.is('textarea'); - this.isInline = options.inline && (options.container || !this.isInput); - this.format = parseFormat(options.format); - this.oldValue = this.initialValue = this.getValue(); - date = this.parseDate(date || this.initialValue); - if (startDate) { - startDate = this.parseDate(startDate); + if (this.trigger(EVENT_PICK, { + view: _view || '', + date: date + }).isDefaultPrevented()) { + return; + } - if (date.getTime() < startDate.getTime()) { - date = new Date(startDate); - } + date = this.formatDate(this.date); + this.setValue(date); - this.startDate = startDate; - } + if (this.isInput) { + $this.trigger('input'); + $this.trigger('change'); + } + }, - if (endDate) { - endDate = this.parseDate(endDate); - if (startDate && endDate.getTime() < startDate.getTime()) { - endDate = new Date(startDate); - } + // Reset the datepicker + reset: function reset() { + this.setDate(this.initialDate, true); + this.setValue(this.initialValue); - if (date.getTime() > endDate.getTime()) { - date = new Date(endDate); - } + if (this.shown) { + this.showView(this.options.startView); + } + }, + + + /** + * Get the month name with given argument or the current date + * + * @param {Number} month (optional) + * @param {Boolean} short (optional) + * @return {String} (month name) + */ + getMonthName: function getMonthName(month, short) { + var options = this.options; + var monthsShort = options.monthsShort; + var months = options.months; + + + if ($.isNumeric(month)) { + month = Number(month); + } else if (isUndefined(short)) { + short = month; + } - this.endDate = endDate; - } + if (short === true) { + months = monthsShort; + } - this.date = date; - this.viewDate = new Date(date); - this.initialDate = new Date(this.date); + return months[isNumber(month) ? month : this.date.getMonth()]; + }, - this.bind(); - if (options.autoShow || this.isInline) { - this.show(); + /** + * Get the day name with given argument or the current date + * + * @param {Number} day (optional) + * @param {Boolean} short (optional) + * @param {Boolean} min (optional) + * @return {String} (day name) + */ + getDayName: function getDayName(day, short, min) { + var options = this.options; + var days = options.days; + + + if ($.isNumeric(day)) { + day = Number(day); + } else { + if (isUndefined(min)) { + min = short; } - if (options.autoPick) { - this.pick(); + if (isUndefined(short)) { + short = day; } - }, + } - build: function () { - var options = this.options; - var $this = this.$element; - var $picker; + if (min) { + days = options.daysMin; + } else if (short) { + days = options.daysShort; + } - if (this.isBuilt) { - return; - } + return days[isNumber(day) ? day : this.date.getDay()]; + }, - this.isBuilt = true; - this.$picker = $picker = $(options.template); - this.$week = $picker.find('[data-view="week"]'); + /** + * Get the current date + * + * @param {Boolean} formatted (optional) + * @return {Date|String} (date) + */ + getDate: function getDate(formatted) { + var date = this.date; - // Years view - this.$yearsPicker = $picker.find('[data-view="years picker"]'); - this.$yearsPrev = $picker.find('[data-view="years prev"]'); - this.$yearsNext = $picker.find('[data-view="years next"]'); - this.$yearsCurrent = $picker.find('[data-view="years current"]'); - this.$years = $picker.find('[data-view="years"]'); - // Months view - this.$monthsPicker = $picker.find('[data-view="months picker"]'); - this.$yearPrev = $picker.find('[data-view="year prev"]'); - this.$yearNext = $picker.find('[data-view="year next"]'); - this.$yearCurrent = $picker.find('[data-view="year current"]'); - this.$months = $picker.find('[data-view="months"]'); + return formatted ? this.formatDate(date) : new Date(date); + }, - // Days view - this.$daysPicker = $picker.find('[data-view="days picker"]'); - this.$monthPrev = $picker.find('[data-view="month prev"]'); - this.$monthNext = $picker.find('[data-view="month next"]'); - this.$monthCurrent = $picker.find('[data-view="month current"]'); - this.$days = $picker.find('[data-view="days"]'); - - if (this.isInline) { - $(options.container || $this).append($picker.addClass(CLASS_INLINE)); - } else { - $(document.body).append($picker.addClass(CLASS_DROPDOWN)); - $picker.addClass(CLASS_HIDE); - } - this.fillWeek(); - }, + /** + * Set the current date with a new date + * + * @param {Date} date + * @param {Boolean} _updated (private) + */ + setDate: function setDate(date, _updated) { + var filter = this.options.filter; + - unbuild: function () { - if (!this.isBuilt) { + if (isDate(date) || isString(date)) { + date = this.parseDate(date); + + if ($.isFunction(filter) && filter.call(this.$element, date) === false) { return; } - this.isBuilt = false; - this.$picker.remove(); - }, - - bind: function () { - var options = this.options; - var $this = this.$element; + this.date = date; + this.viewDate = new Date(date); - if ($.isFunction(options.show)) { - $this.on(EVENT_SHOW, options.show); + if (!_updated) { + this.pick(); } - if ($.isFunction(options.hide)) { - $this.on(EVENT_HIDE, options.hide); + if (this.built) { + this.render(); } + } + }, - if ($.isFunction(options.pick)) { - $this.on(EVENT_PICK, options.pick); - } - if (this.isInput) { - $this.on(EVENT_KEYUP, $.proxy(this.keyup, this)); - } + /** + * Set the start view date with a new date + * + * @param {Date} date + */ + setStartDate: function setStartDate(date) { + if (isDate(date) || isString(date)) { + this.startDate = this.parseDate(date); - if (!this.isInline) { - if (options.trigger) { - this.$trigger.on(EVENT_CLICK, $.proxy(this.toggle, this)); - } else if (this.isInput) { - $this.on(EVENT_FOCUS, $.proxy(this.show, this)); - } else { - $this.on(EVENT_CLICK, $.proxy(this.show, this)); - } + if (this.built) { + this.render(); } - }, + } + }, - unbind: function () { - var options = this.options; - var $this = this.$element; - if ($.isFunction(options.show)) { - $this.off(EVENT_SHOW, options.show); - } + /** + * Set the end view date with a new date + * + * @param {Date} date + */ + setEndDate: function setEndDate(date) { + if (isDate(date) || isString(date)) { + this.endDate = this.parseDate(date); - if ($.isFunction(options.hide)) { - $this.off(EVENT_HIDE, options.hide); + if (this.built) { + this.render(); } + } + }, - if ($.isFunction(options.pick)) { - $this.off(EVENT_PICK, options.pick); - } - if (this.isInput) { - $this.off(EVENT_KEYUP, this.keyup); - } + /** + * Parse a date string with the set date format + * + * @param {String} date + * @return {Date} (parsed date) + */ + parseDate: function parseDate(date) { + var format = this.format; - if (!this.isInline) { - if (options.trigger) { - this.$trigger.off(EVENT_CLICK, this.toggle); - } else if (this.isInput) { - $this.off(EVENT_FOCUS, this.show); - } else { - $this.off(EVENT_CLICK, this.show); - } - } - }, + var parts = []; - showView: function (view) { - var $yearsPicker = this.$yearsPicker; - var $monthsPicker = this.$monthsPicker; - var $daysPicker = this.$daysPicker; - var format = this.format; + if (isDate(date)) { + return new Date(date.getFullYear(), date.getMonth(), date.getDate()); + } else if (isString(date)) { + parts = date.match(REGEXP_DIGITS) || []; + } - if (format.hasYear || format.hasMonth || format.hasDay) { - switch (Number(view)) { - case VIEWS.YEARS: - case 'years': - $monthsPicker.addClass(CLASS_HIDE); - $daysPicker.addClass(CLASS_HIDE); + date = new Date(); - if (format.hasYear) { - this.fillYears(); - $yearsPicker.removeClass(CLASS_HIDE); - this.place(); - } else { - this.showView(VIEWS.DAYS); - } + var length = format.parts.length; + + var year = date.getFullYear(); + var day = date.getDate(); + var month = date.getMonth(); + if (parts.length === length) { + $.each(parts, function (i, part) { + var value = parseInt(part, 10) || 1; + + switch (format.parts[i]) { + case 'dd': + case 'd': + day = value; break; - case VIEWS.MONTHS: - case 'months': - $yearsPicker.addClass(CLASS_HIDE); - $daysPicker.addClass(CLASS_HIDE); + case 'mm': + case 'm': + month = value - 1; + break; - if (format.hasMonth) { - this.fillMonths(); - $monthsPicker.removeClass(CLASS_HIDE); - this.place(); - } else { - this.showView(VIEWS.YEARS); - } + case 'yy': + year = 2000 + value; + break; + case 'yyyy': + year = value; break; - // case VIEWS.DAYS: - // case 'days': default: - $yearsPicker.addClass(CLASS_HIDE); - $monthsPicker.addClass(CLASS_HIDE); - - if (format.hasDay) { - this.fillDays(); - $daysPicker.removeClass(CLASS_HIDE); - this.place(); - } else { - this.showView(VIEWS.MONTHS); - } } - } - }, + }); + } - hideView: function () { - if (!this.isInline && this.options.autoHide) { - this.hide(); - } - }, + return new Date(year, month, day); + }, - place: function () { - if (this.isInline) { - return; - } - var options = this.options; - var $this = this.$element; - var $picker = this.$picker; - var containerWidth = $document.outerWidth(); - var containerHeight = $document.outerHeight(); - var elementWidth = $this.outerWidth(); - var elementHeight = $this.outerHeight(); - var width = $picker.width(); - var height = $picker.height(); - var offsets = $this.offset(); - var left = offsets.left; - var top = offsets.top; - var offset = parseFloat(options.offset) || 10; - var placement = CLASS_TOP_LEFT; + /** + * Format a date object to a string with the set date format + * + * @param {Date} date + * @return {String} (formatted date) + */ + formatDate: function formatDate(date) { + var format = this.format; - if (top > height && top + elementHeight + height > containerHeight) { - top -= height + offset; - placement = CLASS_BOTTOM_LEFT; - } else { - top += elementHeight + offset; - } - - if (left + width > containerWidth) { - left = left + elementWidth - width; - placement = placement.replace('left', 'right'); - } + var formatted = ''; - $picker.removeClass(CLASS_PLACEMENTS).addClass(placement).css({ - top: top, - left: left, - zIndex: parseInt(options.zIndex, 10) + if (isDate(date)) { + var year = date.getFullYear(); + var values = { + d: date.getDate(), + m: date.getMonth() + 1, + yy: year.toString().substring(2), + yyyy: year + }; + + values.dd = (values.d < 10 ? '0' : '') + values.d; + values.mm = (values.m < 10 ? '0' : '') + values.m; + formatted = format.source; + $.each(format.parts, function (i, part) { + formatted = formatted.replace(part, values[part]); }); - }, + } - // A shortcut for triggering custom events - trigger: function (type, data) { - var e = $.Event(type, data); + return formatted; + }, - this.$element.trigger(e); - return e; - }, + // Destroy the datepicker and remove the instance from the target element + destroy: function destroy() { + this.unbind(); + this.unbuild(); + this.$element.removeData(NAMESPACE); + } +}; - createItem: function (data) { - var options = this.options; - var itemTag = options.itemTag; - var defaults = { - text: '', - view: '', - muted: false, - picked: false, - disabled: false, - highlighted: false - }; - var classes = []; +var handlers = { + click: function click(e) { + var $target = $(e.target); + var options = this.options, + viewDate = this.viewDate, + format = this.format; - $.extend(defaults, data); - if (defaults.muted) { - classes.push(options.mutedClass); - } + e.stopPropagation(); + e.preventDefault(); - if (defaults.highlighted) { - classes.push(options.highlightedClass); - } + if ($target.hasClass('disabled')) { + return; + } - if (defaults.picked) { - classes.push(options.pickedClass); - } + var view = $target.data('view'); + var viewYear = viewDate.getFullYear(); + var viewMonth = viewDate.getMonth(); + var viewDay = viewDate.getDate(); - if (defaults.disabled) { - classes.push(options.disabledClass); - } + switch (view) { + case 'years prev': + case 'years next': + { + viewYear = view === 'years prev' ? viewYear - 10 : viewYear + 10; + this.viewDate = new Date(viewYear, viewMonth, getMinDay(viewYear, viewMonth, viewDay)); + this.renderYears(); + break; + } - return ( - '<' + itemTag + ' class="' + classes.join(' ') + '"' + - (defaults.view ? ' data-view="' + defaults.view + '"' : '') + - '>' + - defaults.text + - '' - ); - }, - - fillAll: function () { - this.fillYears(); - this.fillMonths(); - this.fillDays(); - }, - - fillWeek: function () { - var options = this.options; - var weekStart = parseInt(options.weekStart, 10) % 7; - var days = options.daysMin; - var list = ''; - var i; + case 'year prev': + case 'year next': + viewYear = view === 'year prev' ? viewYear - 1 : viewYear + 1; + this.viewDate = new Date(viewYear, viewMonth, getMinDay(viewYear, viewMonth, viewDay)); + this.renderMonths(); + break; - days = $.merge(days.slice(weekStart), days.slice(0, weekStart)); + case 'year current': + if (format.hasYear) { + this.showView(VIEWS.YEARS); + } - for (i = 0; i <= 6; i++) { - list += this.createItem({ - text: days[i] - }); - } + break; + + case 'year picked': + if (format.hasMonth) { + this.showView(VIEWS.MONTHS); + } else { + $target.addClass(options.pickedClass).siblings().removeClass(options.pickedClass); + this.hideView(); + } - this.$week.html(list); - }, + this.pick('year'); + break; - fillYears: function () { - var options = this.options; - var disabledClass = options.disabledClass || ''; - var suffix = options.yearSuffix || ''; - var filter = $.isFunction(options.filter) && options.filter; - var startDate = this.startDate; - var endDate = this.endDate; - var viewDate = this.viewDate; - var viewYear = viewDate.getFullYear(); - var now = new Date(); - var thisYear = now.getFullYear(); - var date = this.date; - var year = date.getFullYear(); - var isPrevDisabled = false; - var isNextDisabled = false; - var isDisabled = false; - var isPicked = false; - var isMuted = false; - var list = ''; - var start = -5; - var end = 6; - var i; - - for (i = start; i <= end; i++) { - date = new Date(viewYear + i, 1, 1); - isMuted = i === start || i === end; - isPicked = (viewYear + i) === year; - isDisabled = false; - - if (startDate) { - isDisabled = date.getFullYear() < startDate.getFullYear(); - - if (i === start) { - isPrevDisabled = isDisabled; - } + case 'year': + viewYear = parseInt($target.text(), 10); + this.date = new Date(viewYear, viewMonth, getMinDay(viewYear, viewMonth, viewDay)); + + if (format.hasMonth) { + this.viewDate = new Date(this.date); + this.showView(VIEWS.MONTHS); + } else { + $target.addClass(options.pickedClass).siblings().removeClass(options.pickedClass); + this.hideView(); } - if (!isDisabled && endDate) { - isDisabled = date.getFullYear() > endDate.getFullYear(); + this.pick('year'); + break; - if (i === end) { - isNextDisabled = isDisabled; - } + case 'month prev': + case 'month next': + viewMonth = view === 'month prev' ? viewMonth - 1 : viewMonth + 1; + this.viewDate = new Date(viewYear, viewMonth, getMinDay(viewYear, viewMonth, viewDay)); + this.renderDays(); + break; + + case 'month current': + if (format.hasMonth) { + this.showView(VIEWS.MONTHS); } - if (!isDisabled && filter) { - isDisabled = filter.call(this.$element, date) === false; + break; + + case 'month picked': + if (format.hasDay) { + this.showView(VIEWS.DAYS); + } else { + $target.addClass(options.pickedClass).siblings().removeClass(options.pickedClass); + this.hideView(); } - list += this.createItem({ - text: viewYear + i, - view: isDisabled ? 'year disabled' : isPicked ? 'year picked' : 'year', - muted: isMuted, - picked: isPicked, - disabled: isDisabled, - highlighted: date.getFullYear() === thisYear - }); - } + this.pick('month'); + break; - this.$yearsPrev.toggleClass(disabledClass, isPrevDisabled); - this.$yearsNext.toggleClass(disabledClass, isNextDisabled); - this.$yearsCurrent. - toggleClass(disabledClass, true). - html((viewYear + start) + suffix + ' - ' + (viewYear + end) + suffix); - this.$years.html(list); - }, + case 'month': + viewMonth = $.inArray($target.text(), options.monthsShort); + this.date = new Date(viewYear, viewMonth, getMinDay(viewYear, viewMonth, viewDay)); - fillMonths: function () { - var options = this.options; - var disabledClass = options.disabledClass || ''; - var months = options.monthsShort; - var filter = $.isFunction(options.filter) && options.filter; - var startDate = this.startDate; - var endDate = this.endDate; - var viewDate = this.viewDate; - var viewYear = viewDate.getFullYear(); - var now = new Date(); - var thisYear = now.getFullYear(); - var thisMonth = now.getMonth(); - var date = this.date; - var year = date.getFullYear(); - var month = date.getMonth(); - var isPrevDisabled = false; - var isNextDisabled = false; - var isDisabled = false; - var isPicked = false; - var list = ''; - var i; - - for (i = 0; i <= 11; i++) { - date = new Date(viewYear, i, 1); - isPicked = viewYear === year && i === month; - isDisabled = false; - - if (startDate) { - isPrevDisabled = date.getFullYear() === startDate.getFullYear(); - isDisabled = isPrevDisabled && date.getMonth() < startDate.getMonth(); + if (format.hasDay) { + this.viewDate = new Date(viewYear, viewMonth, getMinDay(viewYear, viewMonth, viewDay)); + this.showView(VIEWS.DAYS); + } else { + $target.addClass(options.pickedClass).siblings().removeClass(options.pickedClass); + this.hideView(); } - if (!isDisabled && endDate) { - isNextDisabled = date.getFullYear() === endDate.getFullYear(); - isDisabled = isNextDisabled && date.getMonth() > endDate.getMonth(); - console.log(isNextDisabled, date, endDate) - } + this.pick('month'); + break; - if (!isDisabled && filter) { - isDisabled = filter.call(this.$element, date) === false; + case 'day prev': + case 'day next': + case 'day': + if (view === 'day prev') { + viewMonth -= 1; + } else if (view === 'day next') { + viewMonth += 1; } - list += this.createItem({ - index: i, - text: months[i], - view: isDisabled ? 'month disabled' : isPicked ? 'month picked' : 'month', - picked: isPicked, - disabled: isDisabled, - highlighted: viewYear === thisYear && date.getMonth() === thisMonth - }); - } + viewDay = parseInt($target.text(), 10); + this.date = new Date(viewYear, viewMonth, viewDay); + this.viewDate = new Date(viewYear, viewMonth, viewDay); + this.renderDays(); - this.$yearPrev.toggleClass(disabledClass, isPrevDisabled); - this.$yearNext.toggleClass(disabledClass, isNextDisabled); - this.$yearCurrent. - toggleClass(disabledClass, isPrevDisabled && isNextDisabled). - html(viewYear + options.yearSuffix || ''); - this.$months.html(list); - }, + if (view === 'day') { + this.hideView(); + } - fillDays: function () { - var options = this.options; - var disabledClass = options.disabledClass || ''; - var suffix = options.yearSuffix || ''; - var months = options.monthsShort; - var weekStart = parseInt(options.weekStart, 10) % 7; - var filter = $.isFunction(options.filter) && options.filter; - var startDate = this.startDate; - var endDate = this.endDate; - var viewDate = this.viewDate; - var viewYear = viewDate.getFullYear(); - var viewMonth = viewDate.getMonth(); - var prevViewYear = viewYear; - var prevViewMonth = viewMonth; - var nextViewYear = viewYear; - var now = new Date(); - var thisYear = now.getFullYear(); - var thisMonth = now.getMonth(); - var today = now.getDate(); - var nextViewMonth = viewMonth; - var date = this.date; - var year = date.getFullYear(); - var month = date.getMonth(); - var day = date.getDate(); - var isPrevDisabled = false; - var isNextDisabled = false; - var isDisabled = false; - var isPicked = false; - var prevItems = []; - var nextItems = []; - var items = []; - var total = 42; // 6 rows and 7 columns on the days picker - var length; - var i; - var n; - - // Days of previous month - // ----------------------------------------------------------------------- - - if (viewMonth === 0) { - prevViewYear -= 1; - prevViewMonth = 11; - } else { - prevViewMonth -= 1; - } + this.pick('day'); + break; - // The length of the days of previous month - length = getDaysInMonth(prevViewYear, prevViewMonth); + case 'day picked': + this.hideView(); + this.pick('day'); + break; - // The first day of current month - date = new Date(viewYear, viewMonth, 1); + default: + } + }, + globalClick: function globalClick(_ref) { + var target = _ref.target; + var element = this.element, + $trigger = this.$trigger; - // The visible length of the days of previous month - // [0,1,2,3,4,5,6] - [0,1,2,3,4,5,6] => [-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6] - n = date.getDay() - weekStart; + var trigger = $trigger[0]; + var hidden = true; - // [-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6] => [1,2,3,4,5,6,7] - if (n <= 0) { - n += 7; + while (target !== document) { + if (target === trigger || target === element) { + hidden = false; + break; } + target = target.parentNode; + } + + if (hidden) { + this.hide(); + } + }, + keyup: function keyup() { + this.update(); + }, + globalKeyup: function globalKeyup(_ref2) { + var target = _ref2.target, + key = _ref2.key, + keyCode = _ref2.keyCode; + + if (this.isInput && target !== this.element && this.shown && (key === 'Tab' || keyCode === 9)) { + this.hide(); + } + } +}; + +var render = { + render: function render() { + this.renderYears(); + this.renderMonths(); + this.renderDays(); + }, + renderWeek: function renderWeek() { + var _this = this; + + var items = []; + var _options = this.options, + weekStart = _options.weekStart, + daysMin = _options.daysMin; + + + weekStart = parseInt(weekStart, 10) % 7; + daysMin = daysMin.slice(weekStart).concat(daysMin.slice(0, weekStart)); + $.each(daysMin, function (i, day) { + items.push(_this.createItem({ + text: day + })); + }); + + this.$week.html(items.join('')); + }, + renderYears: function renderYears() { + var options = this.options, + startDate = this.startDate, + endDate = this.endDate; + var disabledClass = options.disabledClass, + filter = options.filter, + yearSuffix = options.yearSuffix; + + var viewYear = this.viewDate.getFullYear(); + var now = new Date(); + var thisYear = now.getFullYear(); + var year = this.date.getFullYear(); + var start = -5; + var end = 6; + var items = []; + var prevDisabled = false; + var nextDisabled = false; + var i = void 0; + + for (i = start; i <= end; i += 1) { + var date = new Date(viewYear + i, 1, 1); + var disabled = false; + if (startDate) { - isPrevDisabled = date.getTime() <= startDate.getTime(); + disabled = date.getFullYear() < startDate.getFullYear(); + + if (i === start) { + prevDisabled = disabled; + } } - for (i = length - (n - 1); i <= length; i++) { - date = new Date(prevViewYear, prevViewMonth, i); - isPicked = prevViewYear === year && prevViewMonth === month && i === day; - isDisabled = false; + if (!disabled && endDate) { + disabled = date.getFullYear() > endDate.getFullYear(); - if (startDate) { - isDisabled = date.getTime() < startDate.getTime(); + if (i === end) { + nextDisabled = disabled; } + } - if (!isDisabled && filter) { - isDisabled = filter.call(this.$element, date) === false; - } + if (!disabled && filter) { + disabled = filter.call(this.$element, date) === false; + } + + var picked = viewYear + i === year; + var view = picked ? 'year picked' : 'year'; + + items.push(this.createItem({ + picked: picked, + disabled: disabled, + muted: i === start || i === end, + text: viewYear + i, + view: disabled ? 'year disabled' : view, + highlighted: date.getFullYear() === thisYear + })); + } - prevItems.push(this.createItem({ - text: i, - view: 'day prev', - muted: true, - picked: isPicked, - disabled: isDisabled, - highlighted: prevViewYear === thisYear && prevViewMonth === thisMonth && date.getDate() === today - })); + this.$yearsPrev.toggleClass(disabledClass, prevDisabled); + this.$yearsNext.toggleClass(disabledClass, nextDisabled); + this.$yearsCurrent.toggleClass(disabledClass, true).html(viewYear + start + yearSuffix + ' - ' + (viewYear + end) + yearSuffix); + this.$years.html(items.join('')); + }, + renderMonths: function renderMonths() { + var options = this.options, + startDate = this.startDate, + endDate = this.endDate, + viewDate = this.viewDate; + + var disabledClass = options.disabledClass || ''; + var months = options.monthsShort; + var filter = $.isFunction(options.filter) && options.filter; + var viewYear = viewDate.getFullYear(); + var now = new Date(); + var thisYear = now.getFullYear(); + var thisMonth = now.getMonth(); + var year = this.date.getFullYear(); + var month = this.date.getMonth(); + var items = []; + var prevDisabled = false; + var nextDisabled = false; + var i = void 0; + + for (i = 0; i <= 11; i += 1) { + var date = new Date(viewYear, i, 1); + var disabled = false; + + if (startDate) { + prevDisabled = date.getFullYear() === startDate.getFullYear(); + disabled = prevDisabled && date.getMonth() < startDate.getMonth(); } - // Days of next month - // ----------------------------------------------------------------------- + if (!disabled && endDate) { + nextDisabled = date.getFullYear() === endDate.getFullYear(); + disabled = nextDisabled && date.getMonth() > endDate.getMonth(); + } - if (viewMonth === 11) { - nextViewYear += 1; - nextViewMonth = 0; - } else { - nextViewMonth += 1; + if (!disabled && filter) { + disabled = filter.call(this.$element, date) === false; } - // The length of the days of current month - length = getDaysInMonth(viewYear, viewMonth); + var picked = viewYear === year && i === month; + var view = picked ? 'month picked' : 'month'; - // The visible length of next month - n = total - (prevItems.length + length); + items.push(this.createItem({ + disabled: disabled, + picked: picked, + highlighted: viewYear === thisYear && date.getMonth() === thisMonth, + index: i, + text: months[i], + view: disabled ? 'month disabled' : view + })); + } - // The last day of current month - date = new Date(viewYear, viewMonth, length); + this.$yearPrev.toggleClass(disabledClass, prevDisabled); + this.$yearNext.toggleClass(disabledClass, nextDisabled); + this.$yearCurrent.toggleClass(disabledClass, prevDisabled && nextDisabled).html(viewYear + options.yearSuffix || ''); + this.$months.html(items.join('')); + }, + renderDays: function renderDays() { + var $element = this.$element, + options = this.options, + startDate = this.startDate, + endDate = this.endDate, + viewDate = this.viewDate, + currentDate = this.date; + var disabledClass = options.disabledClass, + filter = options.filter, + monthsShort = options.monthsShort, + weekStart = options.weekStart, + yearSuffix = options.yearSuffix; + + var viewYear = viewDate.getFullYear(); + var viewMonth = viewDate.getMonth(); + var now = new Date(); + var thisYear = now.getFullYear(); + var thisMonth = now.getMonth(); + var thisDay = now.getDate(); + var year = currentDate.getFullYear(); + var month = currentDate.getMonth(); + var day = currentDate.getDate(); + var length = void 0; + var i = void 0; + var n = void 0; + + // Days of prev month + // ----------------------------------------------------------------------- + + var prevItems = []; + var prevViewYear = viewYear; + var prevViewMonth = viewMonth; + var prevDisabled = false; + + if (viewMonth === 0) { + prevViewYear -= 1; + prevViewMonth = 11; + } else { + prevViewMonth -= 1; + } - if (endDate) { - isNextDisabled = date.getTime() >= endDate.getTime(); + // The length of the days of prev month + length = getDaysInMonth(prevViewYear, prevViewMonth); + + // The first day of current month + var firstDay = new Date(viewYear, viewMonth, 1); + + // The visible length of the days of prev month + // [0,1,2,3,4,5,6] - [0,1,2,3,4,5,6] => [-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6] + n = firstDay.getDay() - parseInt(weekStart, 10) % 7; + + // [-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6] => [1,2,3,4,5,6,7] + if (n <= 0) { + n += 7; + } + + if (startDate) { + prevDisabled = firstDay.getTime() <= startDate.getTime(); + } + + for (i = length - (n - 1); i <= length; i += 1) { + var prevViewDate = new Date(prevViewYear, prevViewMonth, i); + var disabled = false; + + if (startDate) { + disabled = prevViewDate.getTime() < startDate.getTime(); + } + + if (!disabled && filter) { + disabled = filter.call($element, prevViewDate) === false; } - for (i = 1; i <= n; i++) { - date = new Date(nextViewYear, nextViewMonth, i); - isPicked = nextViewYear === year && nextViewMonth === month && i === day; - isDisabled = false; + prevItems.push(this.createItem({ + disabled: disabled, + highlighted: prevViewYear === thisYear && prevViewMonth === thisMonth && prevViewDate.getDate() === thisDay, + muted: true, + picked: prevViewYear === year && prevViewMonth === month && i === day, + text: i, + view: 'day prev' + })); + } + + // Days of next month + // ----------------------------------------------------------------------- + + var nextItems = []; + var nextViewYear = viewYear; + var nextViewMonth = viewMonth; + var nextDisabled = false; + + if (viewMonth === 11) { + nextViewYear += 1; + nextViewMonth = 0; + } else { + nextViewMonth += 1; + } + + // The length of the days of current month + length = getDaysInMonth(viewYear, viewMonth); + + // The visible length of next month (42 means 6 rows and 7 columns) + n = 42 - (prevItems.length + length); - if (endDate) { - isDisabled = date.getTime() > endDate.getTime(); - } + // The last day of current month + var lastDate = new Date(viewYear, viewMonth, length); - if (!isDisabled && filter) { - isDisabled = filter.call(this.$element, date) === false; - } + if (endDate) { + nextDisabled = lastDate.getTime() >= endDate.getTime(); + } + + for (i = 1; i <= n; i += 1) { + var date = new Date(nextViewYear, nextViewMonth, i); + var picked = nextViewYear === year && nextViewMonth === month && i === day; + var _disabled = false; - nextItems.push(this.createItem({ - text: i, - view: 'day next', - muted: true, - picked: isPicked, - disabled: isDisabled, - highlighted: nextViewYear === thisYear && nextViewMonth === thisMonth && date.getDate() === today - })); + if (endDate) { + _disabled = date.getTime() > endDate.getTime(); } - // Days of current month - // ----------------------------------------------------------------------- + if (!_disabled && filter) { + _disabled = filter.call($element, date) === false; + } - for (i = 1; i <= length; i++) { - date = new Date(viewYear, viewMonth, i); - isPicked = viewYear === year && viewMonth === month && i === day; - isDisabled = false; + nextItems.push(this.createItem({ + disabled: _disabled, + picked: picked, + highlighted: nextViewYear === thisYear && nextViewMonth === thisMonth && date.getDate() === thisDay, + muted: true, + text: i, + view: 'day next' + })); + } - if (startDate) { - isDisabled = date.getTime() < startDate.getTime(); - } + // Days of current month + // ----------------------------------------------------------------------- - if (!isDisabled && endDate) { - isDisabled = date.getTime() > endDate.getTime(); - } + var items = []; - if (!isDisabled && filter) { - isDisabled = filter.call(this.$element, date) === false; - } + for (i = 1; i <= length; i += 1) { + var _date = new Date(viewYear, viewMonth, i); + var _disabled2 = false; - items.push(this.createItem({ - text: i, - view: isDisabled ? 'day disabled' : isPicked ? 'day picked' : 'day', - picked: isPicked, - disabled: isDisabled, - highlighted: viewYear === thisYear && viewMonth === thisMonth && date.getDate() === today - })); + if (startDate) { + _disabled2 = _date.getTime() < startDate.getTime(); } - // Render days picker - // ----------------------------------------------------------------------- - - this.$monthPrev.toggleClass(disabledClass, isPrevDisabled); - this.$monthNext.toggleClass(disabledClass, isNextDisabled); - this.$monthCurrent. - toggleClass(disabledClass, isPrevDisabled && isNextDisabled). - html( - options.yearFirst ? - viewYear + suffix + ' ' + months[viewMonth] : - months[viewMonth] + ' ' + viewYear + suffix - ); - this.$days.html(prevItems.join('') + items.join(' ') + nextItems.join('')); - }, - - click: function (e) { - var $target = $(e.target); - var options = this.options; - var viewDate = this.viewDate; - var viewYear; - var viewMonth; - var viewDay; - var isYear; - var year; - var view; - - e.stopPropagation(); - e.preventDefault(); - - if ($target.hasClass('disabled')) { - return; + if (!_disabled2 && endDate) { + _disabled2 = _date.getTime() > endDate.getTime(); } - viewYear = viewDate.getFullYear(); - viewMonth = viewDate.getMonth(); - viewDay = viewDate.getDate(); - view = $target.data('view'); + if (!_disabled2 && filter) { + _disabled2 = filter.call($element, _date) === false; + } - switch (view) { - case 'years prev': - case 'years next': - viewYear = view === 'years prev' ? viewYear - 10 : viewYear + 10; - year = $target.text(); - isYear = REGEXP_YEAR.test(year); + var _picked = viewYear === year && viewMonth === month && i === day; + var view = _picked ? 'day picked' : 'day'; - if (isYear) { - viewYear = parseInt(year, 10); - this.date = new Date(viewYear, viewMonth, min(viewDay, 28)); - } + items.push(this.createItem({ + disabled: _disabled2, + picked: _picked, + highlighted: viewYear === thisYear && viewMonth === thisMonth && _date.getDate() === thisDay, + text: i, + view: _disabled2 ? 'day disabled' : view + })); + } - this.viewDate = new Date(viewYear, viewMonth, min(viewDay, 28)); - this.fillYears(); + // Render days picker + // ----------------------------------------------------------------------- - if (isYear) { - this.showView(VIEWS.MONTHS); - this.pick('year'); - } + this.$monthPrev.toggleClass(disabledClass, prevDisabled); + this.$monthNext.toggleClass(disabledClass, nextDisabled); + this.$monthCurrent.toggleClass(disabledClass, prevDisabled && nextDisabled).html(options.yearFirst ? viewYear + yearSuffix + ' ' + monthsShort[viewMonth] : monthsShort[viewMonth] + ' ' + viewYear + yearSuffix); + this.$days.html(prevItems.join('') + items.join('') + nextItems.join('')); + } +}; - break; +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); - case 'year prev': - case 'year next': - viewYear = view === 'year prev' ? viewYear - 1 : viewYear + 1; - this.viewDate = new Date(viewYear, viewMonth, min(viewDay, 28)); - this.fillMonths(); - break; +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - case 'year current': - if (this.format.hasYear) { - this.showView(VIEWS.YEARS); - } +var _window = window; +var document$1 = _window.document; - break; +var $document = $(document$1); - case 'year picked': - if (this.format.hasMonth) { - this.showView(VIEWS.MONTHS); - } else { - $target.addClass(options.pickedClass) - .siblings() - .removeClass(options.pickedClass); - this.hideView(); - } - - this.pick('year'); - break; +// Classes +var CLASS_TOP_LEFT = NAMESPACE + '-top-left'; +var CLASS_TOP_RIGHT = NAMESPACE + '-top-right'; +var CLASS_BOTTOM_LEFT = NAMESPACE + '-bottom-left'; +var CLASS_BOTTOM_RIGHT = NAMESPACE + '-bottom-right'; +var CLASS_PLACEMENTS = [CLASS_TOP_LEFT, CLASS_TOP_RIGHT, CLASS_BOTTOM_LEFT, CLASS_BOTTOM_RIGHT].join(' '); - case 'year': - viewYear = parseInt($target.text(), 10); - this.date = new Date(viewYear, viewMonth, min(viewDay, 28)); - - if (this.format.hasMonth) { - this.viewDate = new Date(viewYear, viewMonth, min(viewDay, 28)); - this.showView(VIEWS.MONTHS); - } else { - $target.addClass(options.pickedClass) - .siblings() - .removeClass(options.pickedClass); - this.hideView(); - } - - this.pick('year'); - break; +var Datepicker = function () { + function Datepicker(element) { + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; - case 'month prev': - case 'month next': - viewMonth = view === 'month prev' ? viewMonth - 1 : view === 'month next' ? viewMonth + 1 : viewMonth; - this.viewDate = new Date(viewYear, viewMonth, min(viewDay, 28)); - this.fillDays(); - break; + _classCallCheck(this, Datepicker); - case 'month current': - if (this.format.hasMonth) { - this.showView(VIEWS.MONTHS); - } + this.$element = $(element); + this.element = element; + this.options = $.extend({}, DEFAULTS, LANGUAGES[options.language], options); + this.built = false; + this.shown = false; + this.isInput = false; + this.inline = false; + this.initialValue = ''; + this.initialDate = null; + this.startDate = null; + this.endDate = null; + this.init(); + } - break; + _createClass(Datepicker, [{ + key: 'init', + value: function init() { + var $this = this.$element, + options = this.options; + var startDate = options.startDate, + endDate = options.endDate, + date = options.date; - case 'month picked': - if (this.format.hasDay) { - this.showView(VIEWS.DAYS); - } else { - $target.addClass(options.pickedClass) - .siblings() - .removeClass(options.pickedClass); - this.hideView(); - } - - this.pick('month'); - break; - case 'month': - viewMonth = $.inArray($target.text(), options.monthsShort); - this.date = new Date(viewYear, viewMonth, min(viewDay, 28)); - - if (this.format.hasDay) { - this.viewDate = new Date(viewYear, viewMonth, min(viewDay, 28)); - this.showView(VIEWS.DAYS); - } else { - $target.addClass(options.pickedClass) - .siblings() - .removeClass(options.pickedClass); - this.hideView(); - } - - this.pick('month'); - break; + this.$trigger = $(options.trigger); + this.isInput = $this.is('input') || $this.is('textarea'); + this.inline = options.inline && (options.container || !this.isInput); + this.format = parseFormat(options.format); - case 'day prev': - case 'day next': - case 'day': - viewMonth = view === 'day prev' ? viewMonth - 1 : view === 'day next' ? viewMonth + 1 : viewMonth; - viewDay = parseInt($target.text(), 10); - this.date = new Date(viewYear, viewMonth, viewDay); - this.viewDate = new Date(viewYear, viewMonth, viewDay); - this.fillDays(); + var initialValue = this.getValue(); - if (view === 'day') { - this.hideView(); - } + this.initialValue = initialValue; + this.oldValue = initialValue; + date = this.parseDate(date || initialValue); - this.pick('day'); - break; + if (startDate) { + startDate = this.parseDate(startDate); - case 'day picked': - this.hideView(); - this.pick('day'); - break; + if (date.getTime() < startDate.getTime()) { + date = new Date(startDate); + } - // No default + this.startDate = startDate; } - }, - clickDoc: function (e) { - var target = e.target; - var element = this.$element[0]; - var trigger = this.$trigger[0]; - var ignored; + if (endDate) { + endDate = this.parseDate(endDate); - while (target !== document) { - if (target === trigger || target === element) { - ignored = true; - break; + if (startDate && endDate.getTime() < startDate.getTime()) { + endDate = new Date(startDate); } - target = target.parentNode; - } + if (date.getTime() > endDate.getTime()) { + date = new Date(endDate); + } - if (!ignored) { - this.hide(); + this.endDate = endDate; } - }, - keyup: function () { - this.update(); - }, + this.date = date; + this.viewDate = new Date(date); + this.initialDate = new Date(this.date); + this.bind(); - keyupDoc: function (e) { - if (this.isInput && e.target !== this.$element[0] && - this.isShown && (e.key === 'Tab' || e.keyCode === 9)) { - this.hide(); + if (options.autoShow || this.inline) { + this.show(); } - }, - - getValue: function () { - var $this = this.$element; - var val = ''; - if (this.isInput) { - val = $this.val(); - } else if (this.isInline) { - if (this.options.container) { - val = $this.text(); - } - } else { - val = $this.text(); + if (options.autoPick) { + this.pick(); + } + } + }, { + key: 'build', + value: function build() { + if (this.built) { + return; } - return val; - }, + this.built = true; - setValue: function (val) { - var $this = this.$element; + var $this = this.$element, + options = this.options; - val = isString(val) ? val : ''; + var $picker = $(options.template); - if (this.isInput) { - $this.val(val); - } else if (this.isInline) { - if (this.options.container) { - $this.text(val); - } - } else { - $this.text(val); - } - }, + this.$picker = $picker; + this.$week = $picker.find(selectorOf('week')); + // Years view + this.$yearsPicker = $picker.find(selectorOf('years picker')); + this.$yearsPrev = $picker.find(selectorOf('years prev')); + this.$yearsNext = $picker.find(selectorOf('years next')); + this.$yearsCurrent = $picker.find(selectorOf('years current')); + this.$years = $picker.find(selectorOf('years')); - // Methods - // ------------------------------------------------------------------------- + // Months view + this.$monthsPicker = $picker.find(selectorOf('months picker')); + this.$yearPrev = $picker.find(selectorOf('year prev')); + this.$yearNext = $picker.find(selectorOf('year next')); + this.$yearCurrent = $picker.find(selectorOf('year current')); + this.$months = $picker.find(selectorOf('months')); - // Show the datepicker - show: function () { - if (!this.isBuilt) { - this.build(); + // Days view + this.$daysPicker = $picker.find(selectorOf('days picker')); + this.$monthPrev = $picker.find(selectorOf('month prev')); + this.$monthNext = $picker.find(selectorOf('month next')); + this.$monthCurrent = $picker.find(selectorOf('month current')); + this.$days = $picker.find(selectorOf('days')); + + if (this.inline) { + $(options.container || $this).append($picker.addClass(NAMESPACE + '-inline')); + } else { + $(document$1.body).append($picker.addClass(NAMESPACE + '-dropdown')); + $picker.addClass(CLASS_HIDE); } - if (this.isShown) { + this.renderWeek(); + } + }, { + key: 'unbuild', + value: function unbuild() { + if (!this.built) { return; } - if (this.trigger(EVENT_SHOW).isDefaultPrevented()) { - return; - } + this.built = false; + this.$picker.remove(); + } + }, { + key: 'bind', + value: function bind() { + var options = this.options, + $this = this.$element; - this.isShown = true; - this.$picker.removeClass(CLASS_HIDE).on(EVENT_CLICK, $.proxy(this.click, this)); - this.showView(this.options.startView); - if (!this.isInline) { - $window.on(EVENT_RESIZE, (this._place = proxy(this.place, this))); - $document.on(EVENT_CLICK, (this._clickDoc = proxy(this.clickDoc, this))); - $document.on(EVENT_KEYUP, (this._keyupDoc = proxy(this.keyupDoc, this))); - this.place(); + if ($.isFunction(options.show)) { + $this.on(EVENT_SHOW, options.show); } - }, - // Hide the datepicker - hide: function () { - if (!this.isShown) { - return; + if ($.isFunction(options.hide)) { + $this.on(EVENT_HIDE, options.hide); } - if (this.trigger(EVENT_HIDE).isDefaultPrevented()) { - return; + if ($.isFunction(options.pick)) { + $this.on(EVENT_PICK, options.pick); } - this.isShown = false; - this.$picker.addClass(CLASS_HIDE).off(EVENT_CLICK, this.click); - - if (!this.isInline) { - $window.off(EVENT_RESIZE, this._place); - $document.off(EVENT_CLICK, this._clickDoc); - $document.off(EVENT_KEYUP, this._keyupDoc); + if (this.isInput) { + $this.on(EVENT_KEYUP, $.proxy(this.keyup, this)); } - }, - toggle: function () { - if (this.isShown) { - this.hide(); - } else { - this.show(); + if (!this.inline) { + if (options.trigger) { + this.$trigger.on(EVENT_CLICK, $.proxy(this.toggle, this)); + } else if (this.isInput) { + $this.on(EVENT_FOCUS, $.proxy(this.show, this)); + } else { + $this.on(EVENT_CLICK, $.proxy(this.show, this)); + } } - }, + } + }, { + key: 'unbind', + value: function unbind() { + var $this = this.$element, + options = this.options; - // Update the datepicker with the current input value - update: function () { - var value = this.getValue(); - if (value === this.oldValue) { - return; + if ($.isFunction(options.show)) { + $this.off(EVENT_SHOW, options.show); } - this.setDate(value, true); - this.oldValue = value; - }, - - /** - * Pick the current date to the element - * - * @param {String} _view (private) - */ - pick: function (_view) { - var $this = this.$element; - var date = this.date; - - if (this.trigger(EVENT_PICK, { - view: _view || '', - date: date - }).isDefaultPrevented()) { - return; + if ($.isFunction(options.hide)) { + $this.off(EVENT_HIDE, options.hide); } - this.setValue(date = this.formatDate(this.date)); + if ($.isFunction(options.pick)) { + $this.off(EVENT_PICK, options.pick); + } if (this.isInput) { - $this.trigger('change'); + $this.off(EVENT_KEYUP, this.keyup); } - }, - // Reset the datepicker - reset: function () { - this.setDate(this.initialDate, true); - this.setValue(this.initialValue); - - if (this.isShown) { - this.showView(this.options.startView); + if (!this.inline) { + if (options.trigger) { + this.$trigger.off(EVENT_CLICK, this.toggle); + } else if (this.isInput) { + $this.off(EVENT_FOCUS, this.show); + } else { + $this.off(EVENT_CLICK, this.show); + } } - }, - - /** - * Get the month name with given argument or the current date - * - * @param {Number} month (optional) - * @param {Boolean} short (optional) - * @return {String} (month name) - */ - getMonthName: function (month, short) { - var options = this.options; - var months = options.months; + } + }, { + key: 'showView', + value: function showView(view) { + var $yearsPicker = this.$yearsPicker, + $monthsPicker = this.$monthsPicker, + $daysPicker = this.$daysPicker, + format = this.format; - if ($.isNumeric(month)) { - month = Number(month); - } else if (isUndefined(short)) { - short = month; - } - if (short === true) { - months = options.monthsShort; - } + if (format.hasYear || format.hasMonth || format.hasDay) { + switch (Number(view)) { + case VIEWS.YEARS: + $monthsPicker.addClass(CLASS_HIDE); + $daysPicker.addClass(CLASS_HIDE); - return months[isNumber(month) ? month : this.date.getMonth()]; - }, - - /** - * Get the day name with given argument or the current date - * - * @param {Number} day (optional) - * @param {Boolean} short (optional) - * @param {Boolean} min (optional) - * @return {String} (day name) - */ - getDayName: function (day, short, min) { - var options = this.options; - var days = options.days; + if (format.hasYear) { + this.renderYears(); + $yearsPicker.removeClass(CLASS_HIDE); + this.place(); + } else { + this.showView(VIEWS.DAYS); + } - if ($.isNumeric(day)) { - day = Number(day); - } else { - if (isUndefined(min)) { - min = short; - } + break; - if (isUndefined(short)) { - short = day; - } - } + case VIEWS.MONTHS: + $yearsPicker.addClass(CLASS_HIDE); + $daysPicker.addClass(CLASS_HIDE); - days = min === true ? options.daysMin : short === true ? options.daysShort : days; - - return days[isNumber(day) ? day : this.date.getDay()]; - }, - - /** - * Get the current date - * - * @param {Boolean} formatted (optional) - * @return {Date|String} (date) - */ - getDate: function (formatted) { - var date = this.date; - - return formatted ? this.formatDate(date) : new Date(date); - }, - - /** - * Set the current date with a new date - * - * @param {Date} date - * @param {Boolean} _isUpdated (private) - */ - setDate: function (date, _isUpdated) { - var filter = this.options.filter; - - if (isDate(date) || isString(date)) { - date = this.parseDate(date); - - if ($.isFunction(filter) && filter.call(this.$element, date) === false) { - return; - } + if (format.hasMonth) { + this.renderMonths(); + $monthsPicker.removeClass(CLASS_HIDE); + this.place(); + } else { + this.showView(VIEWS.YEARS); + } - this.date = date; - this.viewDate = new Date(date); + break; - if (!_isUpdated) { - this.pick(); - } + // case VIEWS.DAYS: + default: + $yearsPicker.addClass(CLASS_HIDE); + $monthsPicker.addClass(CLASS_HIDE); - if (this.isBuilt) { - this.fillAll(); - } - } - }, - - /** - * Set the start view date with a new date - * - * @param {Date} date - */ - setStartDate: function (date) { - if (isDate(date) || isString(date)) { - this.startDate = this.parseDate(date); - - if (this.isBuilt) { - this.fillAll(); - } - } - }, - - /** - * Set the end view date with a new date - * - * @param {Date} date - */ - setEndDate: function (date) { - if (isDate(date) || isString(date)) { - this.endDate = this.parseDate(date); - - if (this.isBuilt) { - this.fillAll(); + if (format.hasDay) { + this.renderDays(); + $daysPicker.removeClass(CLASS_HIDE); + this.place(); + } else { + this.showView(VIEWS.MONTHS); + } } } - }, - - /** - * Parse a date string with the set date format - * - * @param {String} date - * @return {Date} (parsed date) - */ - parseDate: function (date) { - var format = this.format; - var parts = []; - var length; - var year; - var day; - var month; - var val; - var i; - - if (isDate(date)) { - return new Date(date.getFullYear(), date.getMonth(), date.getDate()); - } else if (isString(date)) { - parts = date.match(REGEXP_DIGITS) || []; - } - - date = new Date(); - year = date.getFullYear(); - day = date.getDate(); - month = date.getMonth(); - length = format.parts.length; - - if (parts.length === length) { - for (i = 0; i < length; i++) { - val = parseInt(parts[i], 10) || 1; - - switch (format.parts[i]) { - case 'dd': - case 'd': - day = val; - break; - - case 'mm': - case 'm': - month = val - 1; - break; - - case 'yy': - year = 2000 + val; - break; - - case 'yyyy': - year = val; - break; - - // No default - } - } + } + }, { + key: 'hideView', + value: function hideView() { + if (!this.inline && this.options.autoHide) { + this.hide(); } - - return new Date(year, month, day); - }, - - /** - * Format a date object to a string with the set date format - * - * @param {Date} date - * @return {String} (formatted date) - */ - formatDate: function (date) { - var format = this.format; - var formatted = ''; - var length; - var year; - var part; - var val; - var i; - - if (isDate(date)) { - formatted = format.source; - year = date.getFullYear(); - val = { - d: date.getDate(), - m: date.getMonth() + 1, - yy: year.toString().substring(2), - yyyy: year - }; - - val.dd = (val.d < 10 ? '0' : '') + val.d; - val.mm = (val.m < 10 ? '0' : '') + val.m; - length = format.parts.length; - - for (i = 0; i < length; i++) { - part = format.parts[i]; - formatted = formatted.replace(part, val[part]); - } + } + }, { + key: 'place', + value: function place() { + if (this.inline) { + return; } - return formatted; - }, + var $this = this.$element, + options = this.options, + $picker = this.$picker; - // Destroy the datepicker and remove the instance from the target element - destroy: function () { - this.unbind(); - this.unbuild(); - this.$element.removeData(NAMESPACE); - } - }; - - Datepicker.LANGUAGES = {}; + var containerWidth = $document.outerWidth(); + var containerHeight = $document.outerHeight(); + var elementWidth = $this.outerWidth(); + var elementHeight = $this.outerHeight(); + var width = $picker.width(); + var height = $picker.height(); - Datepicker.DEFAULTS = { - // Show the datepicker automatically when initialized - autoShow: false, + var _$this$offset = $this.offset(), + left = _$this$offset.left, + top = _$this$offset.top; - // Hide the datepicker automatically when picked - autoHide: false, + var offset = parseFloat(options.offset); + var placement = CLASS_TOP_LEFT; - // Pick the initial date automatically when initialized - autoPick: false, + if (isNaN(offset)) { + offset = 10; + } - // Enable inline mode - inline: false, + if (top > height && top + elementHeight + height > containerHeight) { + top -= height + offset; + placement = CLASS_BOTTOM_LEFT; + } else { + top += elementHeight + offset; + } - // A element (or selector) for putting the datepicker - container: null, + if (left + width > containerWidth) { + left += elementWidth - width; + placement = placement.replace('left', 'right'); + } - // A element (or selector) for triggering the datepicker - trigger: null, + $picker.removeClass(CLASS_PLACEMENTS).addClass(placement).css({ + top: top, + left: left, + zIndex: parseInt(options.zIndex, 10) + }); + } - // The ISO language code (built-in: en-US) - language: '', + // A shortcut for triggering custom events - // The date string format - format: 'mm/dd/yyyy', + }, { + key: 'trigger', + value: function trigger(type, data) { + var e = $.Event(type, data); - // The initial date - date: null, + this.$element.trigger(e); - // The start view date - startDate: null, + return e; + } + }, { + key: 'createItem', + value: function createItem(data) { + var options = this.options; + var itemTag = options.itemTag; - // The end view date - endDate: null, + var item = { + text: '', + view: '', + muted: false, + picked: false, + disabled: false, + highlighted: false + }; + var classes = []; - // The start view when initialized - startView: 0, // 0 for days, 1 for months, 2 for years + $.extend(item, data); - // The start day of the week - weekStart: 0, // 0 for Sunday, 1 for Monday, 2 for Tuesday, 3 for Wednesday, 4 for Thursday, 5 for Friday, 6 for Saturday + if (item.muted) { + classes.push(options.mutedClass); + } - // Show year before month on the datepicker header - yearFirst: false, + if (item.highlighted) { + classes.push(options.highlightedClass); + } - // A string suffix to the year number. - yearSuffix: '', + if (item.picked) { + classes.push(options.pickedClass); + } - // Days' name of the week. - days: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], + if (item.disabled) { + classes.push(options.disabledClass); + } - // Shorter days' name - daysShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], + return '<' + itemTag + ' class="' + classes.join(' ') + '" data-view="' + item.view + '">' + item.text + ''; + } + }, { + key: 'getValue', + value: function getValue() { + var $this = this.$element; - // Shortest days' name - daysMin: ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'], + return this.isInput ? $this.val() : $this.text(); + } + }, { + key: 'setValue', + value: function setValue() { + var value = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ''; - // Months' name - months: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'], + var $this = this.$element; - // Shorter months' name - monthsShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], + if (this.isInput) { + $this.val(value); + } else { + $this.text(value); + } + } + }], [{ + key: 'setDefaults', + value: function setDefaults() { + var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; - // A element tag for each item of years, months and days - itemTag: 'li', + $.extend(DEFAULTS, LANGUAGES[options.language], options); + } + }]); - // A class (CSS) for muted date item - mutedClass: 'muted', + return Datepicker; +}(); - // A class (CSS) for picked date item - pickedClass: 'picked', +$.extend(Datepicker.prototype, render, handlers, methods); - // A class (CSS) for disabled date item - disabledClass: 'disabled', +var AnotherDatepicker = $.fn.datepicker; - // A class (CSS) for highlight date item - highlightedClass: 'highlighted', +$.fn.datepicker = function jQueryDatepicker(option) { + for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { + args[_key - 1] = arguments[_key]; + } - // The template of the datepicker - template: ( - '
' + - '
' + - '' + - '' + - '
' + - '
' + - '' + - '' + - '
' + - '
' + - '' + - '' + - '' + - '
' + - '
' - ), + var result = void 0; - // The offset top or bottom of the datepicker from the element - offset: 10, + this.each(function each() { + var $this = $(this); + var data = $this.data('datepicker'); - // The `z-index` of the datepicker - zIndex: 1000, - - // Filter each date item (return `false` to disable a date item) - filter: null, - - // Event shortcuts - show: null, - hide: null, - pick: null - }; + if (!data) { + if (/destroy/.test(option)) { + return; + } - Datepicker.setDefaults = function (options) { - options = $.isPlainObject(options) ? options : {}; + var options = $.extend({}, $this.data(), $.isPlainObject(option) && option); - if (options.language) { - options = $.extend({}, Datepicker.LANGUAGES[options.language], options); + data = new Datepicker(this, options); + $this.data('datepicker', data); } - $.extend(Datepicker.DEFAULTS, options); - }; - - // Save the other datepicker - Datepicker.other = $.fn.datepicker; - - // Register as jQuery plugin - $.fn.datepicker = function (option) { - var args = toArray(arguments, 1); - var result; - - this.each(function () { - var $this = $(this); - var data = $this.data(NAMESPACE); - var options; - var fn; - - if (!data) { - if (/destroy/.test(option)) { - return; - } - - options = $.extend({}, $this.data(), $.isPlainObject(option) && option); - $this.data(NAMESPACE, (data = new Datepicker(this, options))); - } + if (typeof option === 'string') { + var fn = data[option]; - if (isString(option) && $.isFunction(fn = data[option])) { + if ($.isFunction(fn)) { result = fn.apply(data, args); } - }); - - return isUndefined(result) ? this : result; - }; + } + }); - $.fn.datepicker.Constructor = Datepicker; - $.fn.datepicker.languages = Datepicker.LANGUAGES; - $.fn.datepicker.setDefaults = Datepicker.setDefaults; + return typeof result !== 'undefined' ? result : this; +}; - // No conflict - $.fn.datepicker.noConflict = function () { - $.fn.datepicker = Datepicker.other; - return this; - }; +$.fn.datepicker.Constructor = Datepicker; +$.fn.datepicker.languages = LANGUAGES; +$.fn.datepicker.setDefaults = Datepicker.setDefaults; +$.fn.datepicker.noConflict = function noConflict() { + $.fn.datepicker = AnotherDatepicker; + return this; +}; -}); +}))); diff --git a/dist/datepicker.min.css b/dist/datepicker.min.css index 209b438..1d1e0b8 100644 --- a/dist/datepicker.min.css +++ b/dist/datepicker.min.css @@ -1,9 +1,10 @@ /*! - * Datepicker v0.5.3 + * Datepicker v0.6.0 * https://github.com/fengyuanchen/datepicker - * + * * Copyright (c) 2014-2017 Fengyuan Chen * Released under the MIT license - * - * Date: 2017-06-15T11:00:53.699Z - */.datepicker-container{font-size:12px;line-height:30px;position:fixed;z-index:-1;top:0;left:0;width:210px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-color:#fff;direction:ltr!important;-ms-touch-action:none;touch-action:none;-webkit-tap-highlight-color:transparent;-webkit-touch-callout:none}.datepicker-container:after,.datepicker-container:before{position:absolute;display:block;width:0;height:0;content:' ';border:5px solid transparent}.datepicker-dropdown{position:absolute;z-index:1;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;border:1px solid #ccc;-webkit-box-shadow:0 3px 6px #ccc;box-shadow:0 3px 6px #ccc}.datepicker-inline{position:static}.datepicker-top-left,.datepicker-top-right{border-top-color:#39f}.datepicker-top-left:after,.datepicker-top-left:before,.datepicker-top-right:after,.datepicker-top-right:before{top:-5px;left:10px;border-top:0}.datepicker-top-left:before,.datepicker-top-right:before{border-bottom-color:#39f}.datepicker-top-left:after,.datepicker-top-right:after{top:-4px;border-bottom-color:#fff}.datepicker-bottom-left,.datepicker-bottom-right{border-bottom-color:#39f}.datepicker-bottom-left:after,.datepicker-bottom-left:before,.datepicker-bottom-right:after,.datepicker-bottom-right:before{bottom:-5px;left:10px;border-bottom:0}.datepicker-bottom-left:before,.datepicker-bottom-right:before{border-top-color:#39f}.datepicker-bottom-left:after,.datepicker-bottom-right:after{bottom:-4px;border-top-color:#fff}.datepicker-bottom-right:after,.datepicker-bottom-right:before,.datepicker-top-right:after,.datepicker-top-right:before{right:10px;left:auto}.datepicker-panel>ul:after,.datepicker-panel>ul:before{display:table;content:' '}.datepicker-panel>ul:after{clear:both}.datepicker-panel>ul{width:102%;margin:0;padding:0}.datepicker-panel>ul>li{float:left;width:30px;height:30px;margin:0;padding:0;list-style:none;cursor:pointer;text-align:center;background-color:#fff}.datepicker-panel>ul>li.highlighted,.datepicker-panel>ul>li:hover{background-color:#e6f2ff}.datepicker-panel>ul>li.muted,.datepicker-panel>ul>li.muted:hover{color:#999}.datepicker-panel>ul>li.highlighted:hover{background-color:#cce6ff}.datepicker-panel>ul>li.picked,.datepicker-panel>ul>li.picked:hover{color:#39f}.datepicker-panel>ul>li.disabled,.datepicker-panel>ul>li.disabled:hover{cursor:default;color:#ccc;background-color:#fff}.datepicker-panel>ul>li.disabled.highlighted,.datepicker-panel>ul>li.disabled:hover.highlighted{background-color:#e6f2ff}.datepicker-panel>ul>li[data-view='years prev'],.datepicker-panel>ul>li[data-view='year prev'],.datepicker-panel>ul>li[data-view='month prev'],.datepicker-panel>ul>li[data-view='years next'],.datepicker-panel>ul>li[data-view='year next'],.datepicker-panel>ul>li[data-view='month next'],.datepicker-panel>ul>li[data-view=next]{font-size:18px}.datepicker-panel>ul>li[data-view='month current'],.datepicker-panel>ul>li[data-view='years current'],.datepicker-panel>ul>li[data-view='year current']{width:150px}.datepicker-panel>ul[data-view=years]>li,.datepicker-panel>ul[data-view=months]>li{line-height:52.5px;width:52.5px;height:52.5px}.datepicker-panel>ul[data-view=week]>li,.datepicker-panel>ul[data-view=week]>li:hover{cursor:default;background-color:#fff}.datepicker-hide{display:none} \ No newline at end of file + * + * Date: 2017-09-24T11:42:09.338Z + */.datepicker-container{background-color:#fff;direction:ltr;font-size:12px;left:0;line-height:30px;position:fixed;top:0;-ms-touch-action:none;touch-action:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;width:210px;z-index:-1;-webkit-tap-highlight-color:transparent;-webkit-touch-callout:none}.datepicker-container:after,.datepicker-container:before{border:5px solid transparent;content:" ";display:block;height:0;position:absolute;width:0}.datepicker-dropdown{border:1px solid #ccc;box-shadow:0 3px 6px #ccc;box-sizing:content-box;position:absolute;z-index:1}.datepicker-inline{position:static}.datepicker-top-left,.datepicker-top-right{border-top-color:#39f}.datepicker-top-left:after,.datepicker-top-left:before,.datepicker-top-right:after,.datepicker-top-right:before{border-top:0;left:10px;top:-5px}.datepicker-top-left:before,.datepicker-top-right:before{border-bottom-color:#39f}.datepicker-top-left:after,.datepicker-top-right:after{border-bottom-color:#fff;top:-4px}.datepicker-bottom-left,.datepicker-bottom-right{border-bottom-color:#39f}.datepicker-bottom-left:after,.datepicker-bottom-left:before,.datepicker-bottom-right:after,.datepicker-bottom-right:before{border-bottom:0;bottom:-5px;left:10px}.datepicker-bottom-left:before,.datepicker-bottom-right:before{border-top-color:#39f}.datepicker-bottom-left:after,.datepicker-bottom-right:after{border-top-color:#fff;bottom:-4px}.datepicker-bottom-right:after,.datepicker-bottom-right:before,.datepicker-top-right:after,.datepicker-top-right:before{left:auto;right:10px}.datepicker-panel>ul{margin:0;padding:0;width:102%}.datepicker-panel>ul:after,.datepicker-panel>ul:before{content:" ";display:table}.datepicker-panel>ul:after{clear:both}.datepicker-panel>ul>li{background-color:#fff;cursor:pointer;float:left;height:30px;list-style:none;margin:0;padding:0;text-align:center;width:30px}.datepicker-panel>ul>li:hover{background-color:lighten(#39f 35%)}.datepicker-panel>ul>li.muted,.datepicker-panel>ul>li.muted:hover{color:#999}.datepicker-panel>ul>li.highlighted{background-color:lighten(#39f 35%)}.datepicker-panel>ul>li.highlighted:hover{background-color:lighten(#39f 30%)}.datepicker-panel>ul>li.picked,.datepicker-panel>ul>li.picked:hover{color:#39f}.datepicker-panel>ul>li.disabled,.datepicker-panel>ul>li.disabled:hover{background-color:#fff;color:#ccc;cursor:default}.datepicker-panel>ul>li.disabled.highlighted,.datepicker-panel>ul>li.disabled:hover.highlighted{background-color:lighten(#39f 35%)}.datepicker-panel>ul>li[data-view="month next"],.datepicker-panel>ul>li[data-view="month prev"],.datepicker-panel>ul>li[data-view="year next"],.datepicker-panel>ul>li[data-view="year prev"],.datepicker-panel>ul>li[data-view="years next"],.datepicker-panel>ul>li[data-view="years prev"],.datepicker-panel>ul>li[data-view=next]{font-size:18px}.datepicker-panel>ul>li[data-view="month current"],.datepicker-panel>ul>li[data-view="year current"],.datepicker-panel>ul>li[data-view="years current"]{width:150px}.datepicker-panel>ul[data-view=months]>li,.datepicker-panel>ul[data-view=years]>li{height:52.5px;line-height:52.5px;width:52.5px}.datepicker-panel>ul[data-view=week]>li,.datepicker-panel>ul[data-view=week]>li:hover{background-color:#fff;cursor:default}.datepicker-hide{display:none} +/*# sourceMappingURL=datepicker.min.css.map */ \ No newline at end of file diff --git a/dist/datepicker.min.js b/dist/datepicker.min.js index 96485ed..3d750f4 100644 --- a/dist/datepicker.min.js +++ b/dist/datepicker.min.js @@ -1 +1,10 @@ -!function(t){"function"==typeof define&&define.amd?define("datepicker",["jquery"],t):t("object"==typeof exports?require("jquery"):jQuery)}(function(t){"use strict";function e(t){return S.call(t).slice(8,-1).toLowerCase()}function i(t){return"string"==typeof t}function s(t){return"number"==typeof t&&!isNaN(t)}function a(t){return void 0===t}function n(t){return"date"===e(t)}function h(t,e){var i=[];return Array.from?Array.from(t).slice(e||0):(s(e)&&i.push(e),i.slice.apply(t,i))}function r(t,e){var i=h(arguments,2);return function(){return t.apply(e,i.concat(h(arguments)))}}function l(t){return t%4==0&&t%100!=0||t%400==0}function o(t,e){return[31,l(t)?29:28,31,30,31,30,31,31,30,31,30,31][e]}function d(t){var e,i,s=String(t).toLowerCase(),a=s.match(m);if(!a||0===a.length)throw new Error("Invalid date format.");for(t={source:s,parts:a},e=a.length,i=0;ia.getTime()&&(n=new Date(a)),this.endDate=a),this.date=n,this.viewDate=new Date(n),this.initialDate=new Date(this.date),this.bind(),(e.autoShow||this.isInline)&&this.show(),e.autoPick&&this.pick()},build:function(){var e,i=this.options,s=this.$element;this.isBuilt||(this.isBuilt=!0,this.$picker=e=t(i.template),this.$week=e.find('[data-view="week"]'),this.$yearsPicker=e.find('[data-view="years picker"]'),this.$yearsPrev=e.find('[data-view="years prev"]'),this.$yearsNext=e.find('[data-view="years next"]'),this.$yearsCurrent=e.find('[data-view="years current"]'),this.$years=e.find('[data-view="years"]'),this.$monthsPicker=e.find('[data-view="months picker"]'),this.$yearPrev=e.find('[data-view="year prev"]'),this.$yearNext=e.find('[data-view="year next"]'),this.$yearCurrent=e.find('[data-view="year current"]'),this.$months=e.find('[data-view="months"]'),this.$daysPicker=e.find('[data-view="days picker"]'),this.$monthPrev=e.find('[data-view="month prev"]'),this.$monthNext=e.find('[data-view="month next"]'),this.$monthCurrent=e.find('[data-view="month current"]'),this.$days=e.find('[data-view="days"]'),this.isInline?t(i.container||s).append(e.addClass("datepicker-inline")):(t(p.body).append(e.addClass("datepicker-dropdown")),e.addClass(b)),this.fillWeek())},unbuild:function(){this.isBuilt&&(this.isBuilt=!1,this.$picker.remove())},bind:function(){var e=this.options,i=this.$element;t.isFunction(e.show)&&i.on("show.datepicker",e.show),t.isFunction(e.hide)&&i.on("hide.datepicker",e.hide),t.isFunction(e.pick)&&i.on("pick.datepicker",e.pick),this.isInput&&i.on("keyup.datepicker",t.proxy(this.keyup,this)),this.isInline||(e.trigger?this.$trigger.on(y,t.proxy(this.toggle,this)):this.isInput?i.on("focus.datepicker",t.proxy(this.show,this)):i.on(y,t.proxy(this.show,this)))},unbind:function(){var e=this.options,i=this.$element;t.isFunction(e.show)&&i.off("show.datepicker",e.show),t.isFunction(e.hide)&&i.off("hide.datepicker",e.hide),t.isFunction(e.pick)&&i.off("pick.datepicker",e.pick),this.isInput&&i.off("keyup.datepicker",this.keyup),this.isInline||(e.trigger?this.$trigger.off(y,this.toggle):this.isInput?i.off("focus.datepicker",this.show):i.off(y,this.show))},showView:function(t){var e=this.$yearsPicker,i=this.$monthsPicker,s=this.$daysPicker,a=this.format;if(a.hasYear||a.hasMonth||a.hasDay)switch(g(t)){case C.YEARS:case"years":i.addClass(b),s.addClass(b),a.hasYear?(this.fillYears(),e.removeClass(b),this.place()):this.showView(C.DAYS);break;case C.MONTHS:case"months":e.addClass(b),s.addClass(b),a.hasMonth?(this.fillMonths(),i.removeClass(b),this.place()):this.showView(C.YEARS);break;default:e.addClass(b),i.addClass(b),a.hasDay?(this.fillDays(),s.removeClass(b),this.place()):this.showView(C.MONTHS)}},hideView:function(){!this.isInline&&this.options.autoHide&&this.hide()},place:function(){if(!this.isInline){var t=this.options,e=this.$element,i=this.$picker,s=f.outerWidth(),a=f.outerHeight(),n=e.outerWidth(),h=e.outerHeight(),r=i.width(),l=i.height(),o=e.offset(),d=o.left,c=o.top,u=parseFloat(t.offset)||10,p="datepicker-top-left";c>l&&c+h+l>a?(c-=l+u,p="datepicker-bottom-left"):c+=h+u,d+r>s&&(d=d+n-r,p=p.replace("left","right")),i.removeClass(D).addClass(p).css({top:c,left:d,zIndex:parseInt(t.zIndex,10)})}},trigger:function(e,i){var s=t.Event(e,i);return this.$element.trigger(s),s},createItem:function(e){var i=this.options,s=i.itemTag,a={text:"",view:"",muted:!1,picked:!1,disabled:!1,highlighted:!1},n=[];return t.extend(a,e),a.muted&&n.push(i.mutedClass),a.highlighted&&n.push(i.highlightedClass),a.picked&&n.push(i.pickedClass),a.disabled&&n.push(i.disabledClass),"<"+s+' class="'+n.join(" ")+'"'+(a.view?' data-view="'+a.view+'"':"")+">"+a.text+""},fillAll:function(){this.fillYears(),this.fillMonths(),this.fillDays()},fillWeek:function(){var e,i=this.options,s=parseInt(i.weekStart,10)%7,a=i.daysMin,n="";for(a=t.merge(a.slice(s),a.slice(0,s)),e=0;e<=6;e++)n+=this.createItem({text:a[e]});this.$week.html(n)},fillYears:function(){var e,i=this.options,s=i.disabledClass||"",a=i.yearSuffix||"",n=t.isFunction(i.filter)&&i.filter,h=this.startDate,r=this.endDate,l=this.viewDate.getFullYear(),o=(new Date).getFullYear(),d=this.date,c=d.getFullYear(),u=!1,p=!1,f=!1,g=!1,w=!1,y="";for(e=-5;e<=6;e++)d=new Date(l+e,1,1),w=-5===e||6===e,g=l+e===c,f=!1,h&&(f=d.getFullYear()r.getFullYear(),6===e&&(p=f)),!f&&n&&(f=!1===n.call(this.$element,d)),y+=this.createItem({text:l+e,view:f?"year disabled":g?"year picked":"year",muted:w,picked:g,disabled:f,highlighted:d.getFullYear()===o});this.$yearsPrev.toggleClass(s,u),this.$yearsNext.toggleClass(s,p),this.$yearsCurrent.toggleClass(s,!0).html(l+-5+a+" - "+(l+6)+a),this.$years.html(y)},fillMonths:function(){var e,i=this.options,s=i.disabledClass||"",a=i.monthsShort,n=t.isFunction(i.filter)&&i.filter,h=this.startDate,r=this.endDate,l=this.viewDate.getFullYear(),o=new Date,d=o.getFullYear(),c=o.getMonth(),u=this.date,p=u.getFullYear(),f=u.getMonth(),g=!1,w=!1,y=!1,m=!1,k="";for(e=0;e<=11;e++)u=new Date(l,e,1),m=l===p&&e===f,y=!1,h&&(y=(g=u.getFullYear()===h.getFullYear())&&u.getMonth()r.getMonth(),console.log(w,u,r)),!y&&n&&(y=!1===n.call(this.$element,u)),k+=this.createItem({index:e,text:a[e],view:y?"month disabled":m?"month picked":"month",picked:m,disabled:y,highlighted:l===d&&u.getMonth()===c});this.$yearPrev.toggleClass(s,g),this.$yearNext.toggleClass(s,w),this.$yearCurrent.toggleClass(s,g&&w).html(l+i.yearSuffix||""),this.$months.html(k)},fillDays:function(){var e,i,s,a=this.options,n=a.disabledClass||"",h=a.yearSuffix||"",r=a.monthsShort,l=parseInt(a.weekStart,10)%7,d=t.isFunction(a.filter)&&a.filter,c=this.startDate,u=this.endDate,p=this.viewDate,f=p.getFullYear(),g=p.getMonth(),w=f,y=g,m=f,k=new Date,v=k.getFullYear(),D=k.getMonth(),b=k.getDate(),C=g,$=this.date,S=$.getFullYear(),x=$.getMonth(),F=$.getDate(),M=!1,I=!1,Y=!1,T=!1,V=[],A=[],N=[];for(0===g?(w-=1,y=11):y-=1,e=o(w,y),(s=($=new Date(f,g,1)).getDay()-l)<=0&&(s+=7),c&&(M=$.getTime()<=c.getTime()),i=e-(s-1);i<=e;i++)$=new Date(w,y,i),T=w===S&&y===x&&i===F,Y=!1,c&&(Y=$.getTime()=u.getTime()),i=1;i<=s;i++)$=new Date(m,C,i),T=m===S&&C===x&&i===F,Y=!1,u&&(Y=$.getTime()>u.getTime()),!Y&&d&&(Y=!1===d.call(this.$element,$)),A.push(this.createItem({text:i,view:"day next",muted:!0,picked:T,disabled:Y,highlighted:m===v&&C===D&&$.getDate()===b}));for(i=1;i<=e;i++)$=new Date(f,g,i),T=f===S&&g===x&&i===F,Y=!1,c&&(Y=$.getTime()u.getTime()),!Y&&d&&(Y=!1===d.call(this.$element,$)),N.push(this.createItem({text:i,view:Y?"day disabled":T?"day picked":"day",picked:T,disabled:Y,highlighted:f===v&&g===D&&$.getDate()===b}));this.$monthPrev.toggleClass(n,M),this.$monthNext.toggleClass(n,I),this.$monthCurrent.toggleClass(n,M&&I).html(a.yearFirst?f+h+" "+r[g]:r[g]+" "+f+h),this.$days.html(V.join("")+N.join(" ")+A.join(""))},click:function(e){var i,s,a,n,h,r,l=t(e.target),o=this.options,d=this.viewDate;if(e.stopPropagation(),e.preventDefault(),!l.hasClass("disabled"))switch(i=d.getFullYear(),s=d.getMonth(),a=d.getDate(),r=l.data("view")){case"years prev":case"years next":i="years prev"===r?i-10:i+10,h=l.text(),(n=v.test(h))&&(i=parseInt(h,10),this.date=new Date(i,s,$(a,28))),this.viewDate=new Date(i,s,$(a,28)),this.fillYears(),n&&(this.showView(C.MONTHS),this.pick("year"));break;case"year prev":case"year next":i="year prev"===r?i-1:i+1,this.viewDate=new Date(i,s,$(a,28)),this.fillMonths();break;case"year current":this.format.hasYear&&this.showView(C.YEARS);break;case"year picked":this.format.hasMonth?this.showView(C.MONTHS):(l.addClass(o.pickedClass).siblings().removeClass(o.pickedClass),this.hideView()),this.pick("year");break;case"year":i=parseInt(l.text(),10),this.date=new Date(i,s,$(a,28)),this.format.hasMonth?(this.viewDate=new Date(i,s,$(a,28)),this.showView(C.MONTHS)):(l.addClass(o.pickedClass).siblings().removeClass(o.pickedClass),this.hideView()),this.pick("year");break;case"month prev":case"month next":s="month prev"===r?s-1:"month next"===r?s+1:s,this.viewDate=new Date(i,s,$(a,28)),this.fillDays();break;case"month current":this.format.hasMonth&&this.showView(C.MONTHS);break;case"month picked":this.format.hasDay?this.showView(C.DAYS):(l.addClass(o.pickedClass).siblings().removeClass(o.pickedClass),this.hideView()),this.pick("month");break;case"month":s=t.inArray(l.text(),o.monthsShort),this.date=new Date(i,s,$(a,28)),this.format.hasDay?(this.viewDate=new Date(i,s,$(a,28)),this.showView(C.DAYS)):(l.addClass(o.pickedClass).siblings().removeClass(o.pickedClass),this.hideView()),this.pick("month");break;case"day prev":case"day next":case"day":s="day prev"===r?s-1:"day next"===r?s+1:s,a=parseInt(l.text(),10),this.date=new Date(i,s,a),this.viewDate=new Date(i,s,a),this.fillDays(),"day"===r&&this.hideView(),this.pick("day");break;case"day picked":this.hideView(),this.pick("day")}},clickDoc:function(t){for(var e,i=t.target,s=this.$element[0],a=this.$trigger[0];i!==p;){if(i===a||i===s){e=!0;break}i=i.parentNode}e||this.hide()},keyup:function(){this.update()},keyupDoc:function(t){this.isInput&&t.target!==this.$element[0]&&this.isShown&&("Tab"===t.key||9===t.keyCode)&&this.hide()},getValue:function(){var t=this.$element,e="";return this.isInput?e=t.val():this.isInline?this.options.container&&(e=t.text()):e=t.text(),e},setValue:function(t){var e=this.$element;t=i(t)?t:"",this.isInput?e.val(t):this.isInline?this.options.container&&e.text(t):e.text(t)},show:function(){this.isBuilt||this.build(),this.isShown||this.trigger("show.datepicker").isDefaultPrevented()||(this.isShown=!0,this.$picker.removeClass(b).on(y,t.proxy(this.click,this)),this.showView(this.options.startView),this.isInline||(u.on("resize.datepicker",this._place=r(this.place,this)),f.on(y,this._clickDoc=r(this.clickDoc,this)),f.on("keyup.datepicker",this._keyupDoc=r(this.keyupDoc,this)),this.place()))},hide:function(){this.isShown&&(this.trigger("hide.datepicker").isDefaultPrevented()||(this.isShown=!1,this.$picker.addClass(b).off(y,this.click),this.isInline||(u.off("resize.datepicker",this._place),f.off(y,this._clickDoc),f.off("keyup.datepicker",this._keyupDoc))))},toggle:function(){this.isShown?this.hide():this.show()},update:function(){var t=this.getValue();t!==this.oldValue&&(this.setDate(t,!0),this.oldValue=t)},pick:function(t){var e=this.$element,i=this.date;this.trigger("pick.datepicker",{view:t||"",date:i}).isDefaultPrevented()||(this.setValue(i=this.formatDate(this.date)),this.isInput&&e.trigger("change"))},reset:function(){this.setDate(this.initialDate,!0),this.setValue(this.initialValue),this.isShown&&this.showView(this.options.startView)},getMonthName:function(e,i){var n=this.options,h=n.months;return t.isNumeric(e)?e=g(e):a(i)&&(i=e),!0===i&&(h=n.monthsShort),h[s(e)?e:this.date.getMonth()]},getDayName:function(e,i,n){var h=this.options,r=h.days;return t.isNumeric(e)?e=g(e):(a(n)&&(n=i),a(i)&&(i=e)),(r=!0===n?h.daysMin:!0===i?h.daysShort:r)[s(e)?e:this.date.getDay()]},getDate:function(t){var e=this.date;return t?this.formatDate(e):new Date(e)},setDate:function(e,s){var a=this.options.filter;if(n(e)||i(e)){if(e=this.parseDate(e),t.isFunction(a)&&!1===a.call(this.$element,e))return;this.date=e,this.viewDate=new Date(e),s||this.pick(),this.isBuilt&&this.fillAll()}},setStartDate:function(t){(n(t)||i(t))&&(this.startDate=this.parseDate(t),this.isBuilt&&this.fillAll())},setEndDate:function(t){(n(t)||i(t))&&(this.endDate=this.parseDate(t),this.isBuilt&&this.fillAll())},parseDate:function(t){var e,s,a,h,r,l,o=this.format,d=[];if(n(t))return new Date(t.getFullYear(),t.getMonth(),t.getDate());if(i(t)&&(d=t.match(k)||[]),t=new Date,s=t.getFullYear(),a=t.getDate(),h=t.getMonth(),e=o.parts.length,d.length===e)for(l=0;l
          ',offset:10,zIndex:1e3,filter:null,show:null,hide:null,pick:null},c.setDefaults=function(e){(e=t.isPlainObject(e)?e:{}).language&&(e=t.extend({},c.LANGUAGES[e.language],e)),t.extend(c.DEFAULTS,e)},c.other=t.fn.datepicker,t.fn.datepicker=function(e){var s,n=h(arguments,1);return this.each(function(){var a,h,r=t(this),l=r.data(w);if(!l){if(/destroy/.test(e))return;a=t.extend({},r.data(),t.isPlainObject(e)&&e),r.data(w,l=new c(this,a))}i(e)&&t.isFunction(h=l[e])&&(s=h.apply(l,n))}),a(s)?this:s},t.fn.datepicker.Constructor=c,t.fn.datepicker.languages=c.LANGUAGES,t.fn.datepicker.setDefaults=c.setDefaults,t.fn.datepicker.noConflict=function(){return t.fn.datepicker=c.other,this}}); \ No newline at end of file +/*! + * Datepicker v0.6.0 + * https://github.com/fengyuanchen/datepicker + * + * Copyright (c) 2014-2017 Fengyuan Chen + * Released under the MIT license + * + * Date: 2017-09-24T11:42:13.421Z + */ +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(require("jquery")):"function"==typeof define&&define.amd?define(["jquery"],t):t(e.jQuery)}(this,function(e){"use strict";function t(e){return k.call(e).slice(8,-1).toLowerCase()}function i(e){return"string"==typeof e}function a(e){return"number"==typeof e&&!w(e)}function s(e){return void 0===e}function n(e){return"date"===t(e)}function r(e,t){for(var i=arguments.length,a=Array(i>2?i-2:0),s=2;s
                  ',offset:10,zIndex:1e3,filter:null,show:null,hide:null,pick:null},f="datepicker",g="click.datepicker",y="datepicker-hide",v={},m={DAYS:0,MONTHS:1,YEARS:2},k=Object.prototype.toString,w=Number.isNaN||window.isNaN,D=/(y|m|d)+/g,b=window.document,C=e(window),$=e(b),x=/\d+/g,M={show:function(){this.built||this.build(),this.shown||this.trigger("show.datepicker").isDefaultPrevented()||(this.shown=!0,this.$picker.removeClass(y).on(g,e.proxy(this.click,this)),this.showView(this.options.startView),this.inline||(C.on("resize.datepicker",this.onResize=r(this.place,this)),$.on(g,this.onGlobalClick=r(this.globalClick,this)),$.on("keyup.datepicker",this.onGlobalKeyup=r(this.globalKeyup,this)),this.place()))},hide:function(){this.shown&&(this.trigger("hide.datepicker").isDefaultPrevented()||(this.shown=!1,this.$picker.addClass(y).off(g,this.click),this.inline||(C.off("resize.datepicker",this.onResize),$.off(g,this.onGlobalClick),$.off("keyup.datepicker",this.onGlobalKeyup))))},toggle:function(){this.shown?this.hide():this.show()},update:function(){var e=this.getValue();e!==this.oldValue&&(this.setDate(e,!0),this.oldValue=e)},pick:function(e){var t=this.$element,i=this.date;this.trigger("pick.datepicker",{view:e||"",date:i}).isDefaultPrevented()||(i=this.formatDate(this.date),this.setValue(i),this.isInput&&(t.trigger("input"),t.trigger("change")))},reset:function(){this.setDate(this.initialDate,!0),this.setValue(this.initialValue),this.shown&&this.showView(this.options.startView)},getMonthName:function(t,i){var n=this.options,r=n.monthsShort,h=n.months;return e.isNumeric(t)?t=Number(t):s(i)&&(i=t),!0===i&&(h=r),h[a(t)?t:this.date.getMonth()]},getDayName:function(t,i,n){var r=this.options,h=r.days;return e.isNumeric(t)?t=Number(t):(s(n)&&(n=i),s(i)&&(i=t)),n?h=r.daysMin:i&&(h=r.daysShort),h[a(t)?t:this.date.getDay()]},getDate:function(e){var t=this.date;return e?this.formatDate(t):new Date(t)},setDate:function(t,a){var s=this.options.filter;if(n(t)||i(t)){if(t=this.parseDate(t),e.isFunction(s)&&!1===s.call(this.$element,t))return;this.date=t,this.viewDate=new Date(t),a||this.pick(),this.built&&this.render()}},setStartDate:function(e){(n(e)||i(e))&&(this.startDate=this.parseDate(e),this.built&&this.render())},setEndDate:function(e){(n(e)||i(e))&&(this.endDate=this.parseDate(e),this.built&&this.render())},parseDate:function(t){var a=this.format,s=[];if(n(t))return new Date(t.getFullYear(),t.getMonth(),t.getDate());i(t)&&(s=t.match(x)||[]),t=new Date;var r=a.parts.length,h=t.getFullYear(),o=t.getDate(),l=t.getMonth();return s.length===r&&e.each(s,function(e,t){var i=parseInt(t,10)||1;switch(a.parts[e]){case"dd":case"d":o=i;break;case"mm":case"m":l=i-1;break;case"yy":h=2e3+i;break;case"yyyy":h=i}}),new Date(h,l,o)},formatDate:function(t){var i=this.format,a="";if(n(t)){var s=t.getFullYear(),r={d:t.getDate(),m:t.getMonth()+1,yy:s.toString().substring(2),yyyy:s};r.dd=(r.d<10?"0":"")+r.d,r.mm=(r.m<10?"0":"")+r.m,a=i.source,e.each(i.parts,function(e,t){a=a.replace(t,r[t])})}return a},destroy:function(){this.unbind(),this.unbuild(),this.$element.removeData(f)}},S={click:function(t){var i=e(t.target),a=this.options,s=this.viewDate,n=this.format;if(t.stopPropagation(),t.preventDefault(),!i.hasClass("disabled")){var r=i.data("view"),h=s.getFullYear(),o=s.getMonth(),l=s.getDate();switch(r){case"years prev":case"years next":h="years prev"===r?h-10:h+10,this.viewDate=new Date(h,o,d(h,o,l)),this.renderYears();break;case"year prev":case"year next":h="year prev"===r?h-1:h+1,this.viewDate=new Date(h,o,d(h,o,l)),this.renderMonths();break;case"year current":n.hasYear&&this.showView(m.YEARS);break;case"year picked":n.hasMonth?this.showView(m.MONTHS):(i.addClass(a.pickedClass).siblings().removeClass(a.pickedClass),this.hideView()),this.pick("year");break;case"year":h=parseInt(i.text(),10),this.date=new Date(h,o,d(h,o,l)),n.hasMonth?(this.viewDate=new Date(this.date),this.showView(m.MONTHS)):(i.addClass(a.pickedClass).siblings().removeClass(a.pickedClass),this.hideView()),this.pick("year");break;case"month prev":case"month next":o="month prev"===r?o-1:o+1,this.viewDate=new Date(h,o,d(h,o,l)),this.renderDays();break;case"month current":n.hasMonth&&this.showView(m.MONTHS);break;case"month picked":n.hasDay?this.showView(m.DAYS):(i.addClass(a.pickedClass).siblings().removeClass(a.pickedClass),this.hideView()),this.pick("month");break;case"month":o=e.inArray(i.text(),a.monthsShort),this.date=new Date(h,o,d(h,o,l)),n.hasDay?(this.viewDate=new Date(h,o,d(h,o,l)),this.showView(m.DAYS)):(i.addClass(a.pickedClass).siblings().removeClass(a.pickedClass),this.hideView()),this.pick("month");break;case"day prev":case"day next":case"day":"day prev"===r?o-=1:"day next"===r&&(o+=1),l=parseInt(i.text(),10),this.date=new Date(h,o,l),this.viewDate=new Date(h,o,l),this.renderDays(),"day"===r&&this.hideView(),this.pick("day");break;case"day picked":this.hideView(),this.pick("day")}}},globalClick:function(e){for(var t=e.target,i=this.element,a=this.$trigger[0],s=!0;t!==document;){if(t===a||t===i){s=!1;break}t=t.parentNode}s&&this.hide()},keyup:function(){this.update()},globalKeyup:function(e){var t=e.target,i=e.key,a=e.keyCode;this.isInput&&t!==this.element&&this.shown&&("Tab"===i||9===a)&&this.hide()}},F={render:function(){this.renderYears(),this.renderMonths(),this.renderDays()},renderWeek:function(){var t=this,i=[],a=this.options,s=a.weekStart,n=a.daysMin;s=parseInt(s,10)%7,n=n.slice(s).concat(n.slice(0,s)),e.each(n,function(e,a){i.push(t.createItem({text:a}))}),this.$week.html(i.join(""))},renderYears:function(){var e=this.options,t=this.startDate,i=this.endDate,a=e.disabledClass,s=e.filter,n=e.yearSuffix,r=this.viewDate.getFullYear(),h=(new Date).getFullYear(),o=this.date.getFullYear(),l=[],d=!1,u=!1,c=void 0;for(c=-5;c<=6;c+=1){var p=new Date(r+c,1,1),f=!1;t&&(f=p.getFullYear()i.getFullYear(),6===c&&(u=f)),!f&&s&&(f=!1===s.call(this.$element,p));var g=r+c===o,y=g?"year picked":"year";l.push(this.createItem({picked:g,disabled:f,muted:-5===c||6===c,text:r+c,view:f?"year disabled":y,highlighted:p.getFullYear()===h}))}this.$yearsPrev.toggleClass(a,d),this.$yearsNext.toggleClass(a,u),this.$yearsCurrent.toggleClass(a,!0).html(r+-5+n+" - "+(r+6)+n),this.$years.html(l.join(""))},renderMonths:function(){var t=this.options,i=this.startDate,a=this.endDate,s=this.viewDate,n=t.disabledClass||"",r=t.monthsShort,h=e.isFunction(t.filter)&&t.filter,o=s.getFullYear(),l=new Date,d=l.getFullYear(),u=l.getMonth(),c=this.date.getFullYear(),p=this.date.getMonth(),f=[],g=!1,y=!1,v=void 0;for(v=0;v<=11;v+=1){var m=new Date(o,v,1),k=!1;i&&(k=(g=m.getFullYear()===i.getFullYear())&&m.getMonth()a.getMonth()),!k&&h&&(k=!1===h.call(this.$element,m));var w=o===c&&v===p,D=w?"month picked":"month";f.push(this.createItem({disabled:k,picked:w,highlighted:o===d&&m.getMonth()===u,index:v,text:r[v],view:k?"month disabled":D}))}this.$yearPrev.toggleClass(n,g),this.$yearNext.toggleClass(n,y),this.$yearCurrent.toggleClass(n,g&&y).html(o+t.yearSuffix||""),this.$months.html(f.join(""))},renderDays:function(){var e=this.$element,t=this.options,i=this.startDate,a=this.endDate,s=this.viewDate,n=this.date,r=t.disabledClass,h=t.filter,o=t.monthsShort,d=t.weekStart,u=t.yearSuffix,c=s.getFullYear(),p=s.getMonth(),f=new Date,g=f.getFullYear(),y=f.getMonth(),v=f.getDate(),m=n.getFullYear(),k=n.getMonth(),w=n.getDate(),D=void 0,b=void 0,C=void 0,$=[],x=c,M=p,S=!1;0===p?(x-=1,M=11):M-=1,D=l(x,M);var F=new Date(c,p,1);for((C=F.getDay()-parseInt(d,10)%7)<=0&&(C+=7),i&&(S=F.getTime()<=i.getTime()),b=D-(C-1);b<=D;b+=1){var Y=new Date(x,M,b),T=!1;i&&(T=Y.getTime()=a.getTime()),b=1;b<=C;b+=1){var j=new Date(I,N,b),O=I===m&&N===k&&b===w,H=!1;a&&(H=j.getTime()>a.getTime()),!H&&h&&(H=!1===h.call(e,j)),V.push(this.createItem({disabled:H,picked:O,highlighted:I===g&&N===y&&j.getDate()===v,muted:!0,text:b,view:"day next"}))}var q=[];for(b=1;b<=D;b+=1){var E=new Date(c,p,b),z=!1;i&&(z=E.getTime()a.getTime()),!z&&h&&(z=!1===h.call(e,E));var W=c===m&&p===k&&b===w,J=W?"day picked":"day";q.push(this.createItem({disabled:z,picked:W,highlighted:c===g&&p===y&&E.getDate()===v,text:b,view:z?"day disabled":J}))}this.$monthPrev.toggleClass(r,S),this.$monthNext.toggleClass(r,P),this.$monthCurrent.toggleClass(r,S&&P).html(t.yearFirst?c+u+" "+o[p]:o[p]+" "+c+u),this.$days.html($.join("")+q.join("")+V.join(""))}},Y=function(){function e(e,t){for(var i=0;i1&&void 0!==arguments[1]?arguments[1]:{};c(this,t),this.$element=e(i),this.element=i,this.options=e.extend({},p,v[a.language],a),this.built=!1,this.shown=!1,this.isInput=!1,this.inline=!1,this.initialValue="",this.initialDate=null,this.startDate=null,this.endDate=null,this.init()}return Y(t,[{key:"init",value:function(){var t=this.$element,i=this.options,a=i.startDate,s=i.endDate,n=i.date;this.$trigger=e(i.trigger),this.isInput=t.is("input")||t.is("textarea"),this.inline=i.inline&&(i.container||!this.isInput),this.format=u(i.format);var r=this.getValue();this.initialValue=r,this.oldValue=r,n=this.parseDate(n||r),a&&(a=this.parseDate(a),n.getTime()s.getTime()&&(n=new Date(s)),this.endDate=s),this.date=n,this.viewDate=new Date(n),this.initialDate=new Date(this.date),this.bind(),(i.autoShow||this.inline)&&this.show(),i.autoPick&&this.pick()}},{key:"build",value:function(){if(!this.built){this.built=!0;var t=this.$element,i=this.options,a=e(i.template);this.$picker=a,this.$week=a.find(h("week")),this.$yearsPicker=a.find(h("years picker")),this.$yearsPrev=a.find(h("years prev")),this.$yearsNext=a.find(h("years next")),this.$yearsCurrent=a.find(h("years current")),this.$years=a.find(h("years")),this.$monthsPicker=a.find(h("months picker")),this.$yearPrev=a.find(h("year prev")),this.$yearNext=a.find(h("year next")),this.$yearCurrent=a.find(h("year current")),this.$months=a.find(h("months")),this.$daysPicker=a.find(h("days picker")),this.$monthPrev=a.find(h("month prev")),this.$monthNext=a.find(h("month next")),this.$monthCurrent=a.find(h("month current")),this.$days=a.find(h("days")),this.inline?e(i.container||t).append(a.addClass("datepicker-inline")):(e(T.body).append(a.addClass("datepicker-dropdown")),a.addClass(y)),this.renderWeek()}}},{key:"unbuild",value:function(){this.built&&(this.built=!1,this.$picker.remove())}},{key:"bind",value:function(){var t=this.options,i=this.$element;e.isFunction(t.show)&&i.on("show.datepicker",t.show),e.isFunction(t.hide)&&i.on("hide.datepicker",t.hide),e.isFunction(t.pick)&&i.on("pick.datepicker",t.pick),this.isInput&&i.on("keyup.datepicker",e.proxy(this.keyup,this)),this.inline||(t.trigger?this.$trigger.on(g,e.proxy(this.toggle,this)):this.isInput?i.on("focus.datepicker",e.proxy(this.show,this)):i.on(g,e.proxy(this.show,this)))}},{key:"unbind",value:function(){var t=this.$element,i=this.options;e.isFunction(i.show)&&t.off("show.datepicker",i.show),e.isFunction(i.hide)&&t.off("hide.datepicker",i.hide),e.isFunction(i.pick)&&t.off("pick.datepicker",i.pick),this.isInput&&t.off("keyup.datepicker",this.keyup),this.inline||(i.trigger?this.$trigger.off(g,this.toggle):this.isInput?t.off("focus.datepicker",this.show):t.off(g,this.show))}},{key:"showView",value:function(e){var t=this.$yearsPicker,i=this.$monthsPicker,a=this.$daysPicker,s=this.format;if(s.hasYear||s.hasMonth||s.hasDay)switch(Number(e)){case m.YEARS:i.addClass(y),a.addClass(y),s.hasYear?(this.renderYears(),t.removeClass(y),this.place()):this.showView(m.DAYS);break;case m.MONTHS:t.addClass(y),a.addClass(y),s.hasMonth?(this.renderMonths(),i.removeClass(y),this.place()):this.showView(m.YEARS);break;default:t.addClass(y),i.addClass(y),s.hasDay?(this.renderDays(),a.removeClass(y),this.place()):this.showView(m.MONTHS)}}},{key:"hideView",value:function(){!this.inline&&this.options.autoHide&&this.hide()}},{key:"place",value:function(){if(!this.inline){var e=this.$element,t=this.options,i=this.$picker,a=V.outerWidth(),s=V.outerHeight(),n=e.outerWidth(),r=e.outerHeight(),h=i.width(),o=i.height(),l=e.offset(),d=l.left,u=l.top,c=parseFloat(t.offset),p="datepicker-top-left";w(c)&&(c=10),u>o&&u+r+o>s?(u-=o+c,p="datepicker-bottom-left"):u+=r+c,d+h>a&&(d+=n-h,p=p.replace("left","right")),i.removeClass(I).addClass(p).css({top:u,left:d,zIndex:parseInt(t.zIndex,10)})}}},{key:"trigger",value:function(t,i){var a=e.Event(t,i);return this.$element.trigger(a),a}},{key:"createItem",value:function(t){var i=this.options,a=i.itemTag,s={text:"",view:"",muted:!1,picked:!1,disabled:!1,highlighted:!1},n=[];return e.extend(s,t),s.muted&&n.push(i.mutedClass),s.highlighted&&n.push(i.highlightedClass),s.picked&&n.push(i.pickedClass),s.disabled&&n.push(i.disabledClass),"<"+a+' class="'+n.join(" ")+'" data-view="'+s.view+'">'+s.text+""}},{key:"getValue",value:function(){var e=this.$element;return this.isInput?e.val():e.text()}},{key:"setValue",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"",t=this.$element;this.isInput?t.val(e):t.text(e)}}],[{key:"setDefaults",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};e.extend(p,v[t.language],t)}}]),t}();e.extend(N.prototype,F,S,M);var P=e.fn.datepicker;e.fn.datepicker=function(t){for(var i=arguments.length,a=Array(i>1?i-1:0),s=1;s ul:before, -.datepicker-panel > ul:after { - display: table; - - content: ' '; +.datepicker-panel > ul { + margin: 0; + padding: 0; + width: 102%; } -.datepicker-panel > ul:after { - clear: both; +.datepicker-panel > ul::before, +.datepicker-panel > ul::after { + content: " "; + display: table; } -.datepicker-panel > ul { - width: 102%; - margin: 0; - padding: 0; +.datepicker-panel > ul::after { + clear: both; } .datepicker-panel > ul > li { + background-color: #fff; + cursor: pointer; float: left; - - width: 30px; height: 30px; + list-style: none; margin: 0; padding: 0; - - list-style: none; - - cursor: pointer; text-align: center; - - background-color: #fff; + width: 30px; } .datepicker-panel > ul > li:hover { - background-color: #e6f2ff; + background-color: lighten(#39f 35%); } .datepicker-panel > ul > li.muted, @@ -168,11 +147,11 @@ } .datepicker-panel > ul > li.highlighted { - background-color: #e6f2ff; + background-color: lighten(#39f 35%); } .datepicker-panel > ul > li.highlighted:hover { - background-color: #cce6ff; + background-color: lighten(#39f 30%); } .datepicker-panel > ul > li.picked, @@ -182,46 +161,43 @@ .datepicker-panel > ul > li.disabled, .datepicker-panel > ul > li.disabled:hover { - cursor: default; - - color: #ccc; background-color: #fff; + color: #ccc; + cursor: default; } .datepicker-panel > ul > li.disabled.highlighted, .datepicker-panel > ul > li.disabled:hover.highlighted { - background-color: #e6f2ff; + background-color: lighten(#39f 35%); } -.datepicker-panel > ul > li[data-view='years prev'], -.datepicker-panel > ul > li[data-view='year prev'], -.datepicker-panel > ul > li[data-view='month prev'], -.datepicker-panel > ul > li[data-view='years next'], -.datepicker-panel > ul > li[data-view='year next'], -.datepicker-panel > ul > li[data-view='month next'], -.datepicker-panel > ul > li[data-view='next'] { +.datepicker-panel > ul > li[data-view="years prev"], +.datepicker-panel > ul > li[data-view="year prev"], +.datepicker-panel > ul > li[data-view="month prev"], +.datepicker-panel > ul > li[data-view="years next"], +.datepicker-panel > ul > li[data-view="year next"], +.datepicker-panel > ul > li[data-view="month next"], +.datepicker-panel > ul > li[data-view="next"] { font-size: 18px; } -.datepicker-panel > ul > li[data-view='years current'], -.datepicker-panel > ul > li[data-view='year current'], -.datepicker-panel > ul > li[data-view='month current'] { +.datepicker-panel > ul > li[data-view="years current"], +.datepicker-panel > ul > li[data-view="year current"], +.datepicker-panel > ul > li[data-view="month current"] { width: 150px; } -.datepicker-panel > ul[data-view='years'] > li, -.datepicker-panel > ul[data-view='months'] > li { +.datepicker-panel > ul[data-view="years"] > li, +.datepicker-panel > ul[data-view="months"] > li { + height: 52.5px; line-height: 52.5px; - width: 52.5px; - height: 52.5px; } -.datepicker-panel > ul[data-view='week'] > li, -.datepicker-panel > ul[data-view='week'] > li:hover { - cursor: default; - +.datepicker-panel > ul[data-view="week"] > li, +.datepicker-panel > ul[data-view="week"] > li:hover { background-color: #fff; + cursor: default; } .datepicker-hide { diff --git a/docs/js/datepicker.js b/docs/js/datepicker.js index 66a74d3..2b6560f 100644 --- a/docs/js/datepicker.js +++ b/docs/js/datepicker.js @@ -1,1567 +1,1517 @@ /*! - * Datepicker v0.5.5 + * Datepicker v0.6.0 * https://github.com/fengyuanchen/datepicker * * Copyright (c) 2014-2017 Fengyuan Chen * Released under the MIT license * - * Date: 2017-09-10T09:16:17.133Z + * Date: 2017-09-24T11:42:13.421Z */ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? factory(require('jquery')) : + typeof define === 'function' && define.amd ? define(['jquery'], factory) : + (factory(global.jQuery)); +}(this, (function ($) { 'use strict'; -(function (factory) { - if (typeof define === 'function' && define.amd) { - // AMD. Register as anonymous module. - define('datepicker', ['jquery'], factory); - } else if (typeof exports === 'object') { - // Node / CommonJS - factory(require('jquery')); - } else { - // Browser globals. - factory(jQuery); +$ = $ && $.hasOwnProperty('default') ? $['default'] : $; + +var DEFAULTS = { + // Show the datepicker automatically when initialized + autoShow: false, + + // Hide the datepicker automatically when picked + autoHide: false, + + // Pick the initial date automatically when initialized + autoPick: false, + + // Enable inline mode + inline: false, + + // A element (or selector) for putting the datepicker + container: null, + + // A element (or selector) for triggering the datepicker + trigger: null, + + // The ISO language code (built-in: en-US) + language: '', + + // The date string format + format: 'mm/dd/yyyy', + + // The initial date + date: null, + + // The start view date + startDate: null, + + // The end view date + endDate: null, + + // The start view when initialized + startView: 0, // 0 for days, 1 for months, 2 for years + + // The start day of the week + // 0 for Sunday, 1 for Monday, 2 for Tuesday, 3 for Wednesday, + // 4 for Thursday, 5 for Friday, 6 for Saturday + weekStart: 0, + + // Show year before month on the datepicker header + yearFirst: false, + + // A string suffix to the year number. + yearSuffix: '', + + // Days' name of the week. + days: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], + + // Shorter days' name + daysShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], + + // Shortest days' name + daysMin: ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'], + + // Months' name + months: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'], + + // Shorter months' name + monthsShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], + + // A element tag for each item of years, months and days + itemTag: 'li', + + // A class (CSS) for muted date item + mutedClass: 'muted', + + // A class (CSS) for picked date item + pickedClass: 'picked', + + // A class (CSS) for disabled date item + disabledClass: 'disabled', + + // A class (CSS) for highlight date item + highlightedClass: 'highlighted', + + // The template of the datepicker + template: '
                  ' + '
                  ' + '
                    ' + '
                  • ' + '
                  • ' + '
                  • ' + '
                  ' + '
                    ' + '
                    ' + '
                    ' + '
                      ' + '
                    • ' + '
                    • ' + '
                    • ' + '
                    ' + '
                      ' + '
                      ' + '
                      ' + '
                        ' + '
                      • ' + '
                      • ' + '
                      • ' + '
                      ' + '
                        ' + '
                          ' + '
                          ' + '
                          ', + + // The offset top or bottom of the datepicker from the element + offset: 10, + + // The `z-index` of the datepicker + zIndex: 1000, + + // Filter each date item (return `false` to disable a date item) + filter: null, + + // Event shortcuts + show: null, + hide: null, + pick: null +}; + +var NAMESPACE = 'datepicker'; +var EVENT_CLICK = 'click.' + NAMESPACE; +var EVENT_FOCUS = 'focus.' + NAMESPACE; +var EVENT_HIDE = 'hide.' + NAMESPACE; +var EVENT_KEYUP = 'keyup.' + NAMESPACE; +var EVENT_PICK = 'pick.' + NAMESPACE; +var EVENT_RESIZE = 'resize.' + NAMESPACE; +var EVENT_SHOW = 'show.' + NAMESPACE; +var CLASS_HIDE = NAMESPACE + '-hide'; +var LANGUAGES = {}; +var VIEWS = { + DAYS: 0, + MONTHS: 1, + YEARS: 2 +}; + +var toString = Object.prototype.toString; + + +function typeOf(obj) { + return toString.call(obj).slice(8, -1).toLowerCase(); +} + +function isString(value) { + return typeof value === 'string'; +} + +var isNaN = Number.isNaN || window.isNaN; + +function isNumber(value) { + return typeof value === 'number' && !isNaN(value); +} + +function isUndefined(value) { + return typeof value === 'undefined'; +} + +function isDate(value) { + return typeOf(value) === 'date'; +} + +function proxy(fn, context) { + for (var _len = arguments.length, args = Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) { + args[_key - 2] = arguments[_key]; } -})(function ($) { - - 'use strict'; - - var $window = $(window); - var document = window.document; - var $document = $(document); - var Number = window.Number; - var NAMESPACE = 'datepicker'; - - // Events - var EVENT_CLICK = 'click.' + NAMESPACE; - var EVENT_KEYUP = 'keyup.' + NAMESPACE; - var EVENT_FOCUS = 'focus.' + NAMESPACE; - var EVENT_RESIZE = 'resize.' + NAMESPACE; - var EVENT_SHOW = 'show.' + NAMESPACE; - var EVENT_HIDE = 'hide.' + NAMESPACE; - var EVENT_PICK = 'pick.' + NAMESPACE; - - // RegExps - var REGEXP_FORMAT = /(y|m|d)+/g; - var REGEXP_DIGITS = /\d+/g; - var REGEXP_YEAR = /^\d{2,4}$/; - - // Classes - var CLASS_INLINE = NAMESPACE + '-inline'; - var CLASS_DROPDOWN = NAMESPACE + '-dropdown'; - var CLASS_TOP_LEFT = NAMESPACE + '-top-left'; - var CLASS_TOP_RIGHT = NAMESPACE + '-top-right'; - var CLASS_BOTTOM_LEFT = NAMESPACE + '-bottom-left'; - var CLASS_BOTTOM_RIGHT = NAMESPACE + '-bottom-right'; - var CLASS_PLACEMENTS = [ - CLASS_TOP_LEFT, - CLASS_TOP_RIGHT, - CLASS_BOTTOM_LEFT, - CLASS_BOTTOM_RIGHT - ].join(' '); - var CLASS_HIDE = NAMESPACE + '-hide'; - - // Views - var VIEWS = { - DAYS: 0, - MONTHS: 1, - YEARS: 2 + + return function () { + for (var _len2 = arguments.length, args2 = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { + args2[_key2] = arguments[_key2]; + } + + return fn.apply(context, args.concat(args2)); }; +} - // Maths - var min = Math.min; +function selectorOf(view) { + return '[data-view="' + view + '"]'; +} - // Utilities - var toString = Object.prototype.toString; +function isLeapYear(year) { + return year % 4 === 0 && year % 100 !== 0 || year % 400 === 0; +} - function typeOf(obj) { - return toString.call(obj).slice(8, -1).toLowerCase(); - } +function getDaysInMonth(year, month) { + return [31, isLeapYear(year) ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month]; +} - function isString(str) { - return typeof str === 'string'; - } +function getMinDay(year, month, day) { + return Math.min(day, getDaysInMonth(year, month)); +} - function isNumber(num) { - return typeof num === 'number' && !isNaN(num); - } +var formatParts = /(y|m|d)+/g; - function isUndefined(obj) { - return typeof obj === 'undefined'; - } +function parseFormat(format) { + var source = String(format).toLowerCase(); + var parts = source.match(formatParts); - function isDate(date) { - return typeOf(date) === 'date'; + if (!parts || parts.length === 0) { + throw new Error('Invalid date format.'); } - function toArray(obj, offset) { - var args = []; + format = { + source: source, + parts: parts + }; - if (Array.from) { - return Array.from(obj).slice(offset || 0); - } + $.each(parts, function (i, part) { + switch (part) { + case 'dd': + case 'd': + format.hasDay = true; + break; - // This is necessary for IE8 - if (isNumber(offset)) { - args.push(offset); - } + case 'mm': + case 'm': + format.hasMonth = true; + break; - return args.slice.apply(obj, args); - } + case 'yyyy': + case 'yy': + format.hasYear = true; + break; - // Custom proxy to avoid jQuery's guid - function proxy(fn, context) { - var args = toArray(arguments, 2); + default: + } + }); - return function () { - return fn.apply(context, args.concat(toArray(arguments))); - }; - } + return format; +} - function isLeapYear(year) { - return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0; - } +var _window$1 = window; +var document$2 = _window$1.document; - function getDaysInMonth(year, month) { - return [31, (isLeapYear(year) ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month]; - } +var $window = $(window); +var $document$1 = $(document$2); +var REGEXP_DIGITS = /\d+/g; - function parseFormat(format) { - var source = String(format).toLowerCase(); - var parts = source.match(REGEXP_FORMAT); - var length; - var i; +var methods = { + // Show the datepicker + show: function show() { + if (!this.built) { + this.build(); + } - if (!parts || parts.length === 0) { - throw new Error('Invalid date format.'); + if (this.shown) { + return; } - format = { - source: source, - parts: parts - }; + if (this.trigger(EVENT_SHOW).isDefaultPrevented()) { + return; + } - length = parts.length; + this.shown = true; + this.$picker.removeClass(CLASS_HIDE).on(EVENT_CLICK, $.proxy(this.click, this)); + this.showView(this.options.startView); - for (i = 0; i < length; i++) { - switch (parts[i]) { - case 'dd': - case 'd': - format.hasDay = true; - break; + if (!this.inline) { + $window.on(EVENT_RESIZE, this.onResize = proxy(this.place, this)); + $document$1.on(EVENT_CLICK, this.onGlobalClick = proxy(this.globalClick, this)); + $document$1.on(EVENT_KEYUP, this.onGlobalKeyup = proxy(this.globalKeyup, this)); + this.place(); + } + }, - case 'mm': - case 'm': - format.hasMonth = true; - break; - case 'yyyy': - case 'yy': - format.hasYear = true; - break; + // Hide the datepicker + hide: function hide() { + if (!this.shown) { + return; + } - // No default - } + if (this.trigger(EVENT_HIDE).isDefaultPrevented()) { + return; } - return format; - } + this.shown = false; + this.$picker.addClass(CLASS_HIDE).off(EVENT_CLICK, this.click); + + if (!this.inline) { + $window.off(EVENT_RESIZE, this.onResize); + $document$1.off(EVENT_CLICK, this.onGlobalClick); + $document$1.off(EVENT_KEYUP, this.onGlobalKeyup); + } + }, + toggle: function toggle() { + if (this.shown) { + this.hide(); + } else { + this.show(); + } + }, + - function Datepicker(element, options) { - options = $.isPlainObject(options) ? options : {}; + // Update the datepicker with the current input value + update: function update() { + var value = this.getValue(); - if (options.language) { - // Priority: Datepicker.DEFAULTS < Datepicker.LANGUAGES < options - options = $.extend({}, Datepicker.LANGUAGES[options.language], options); + if (value === this.oldValue) { + return; } - this.$element = $(element); - this.options = $.extend({}, Datepicker.DEFAULTS, options); - this.isBuilt = false; - this.isShown = false; - this.isInput = false; - this.isInline = false; - this.initialValue = ''; - this.initialDate = null; - this.startDate = null; - this.endDate = null; - this.init(); - } + this.setDate(value, true); + this.oldValue = value; + }, - Datepicker.prototype = { - constructor: Datepicker, - init: function () { - var options = this.options; - var $this = this.$element; - var startDate = options.startDate; - var endDate = options.endDate; - var date = options.date; + /** + * Pick the current date to the element + * + * @param {String} _view (private) + */ + pick: function pick(_view) { + var $this = this.$element; + var date = this.date; - this.$trigger = $(options.trigger); - this.isInput = $this.is('input') || $this.is('textarea'); - this.isInline = options.inline && (options.container || !this.isInput); - this.format = parseFormat(options.format); - this.oldValue = this.initialValue = this.getValue(); - date = this.parseDate(date || this.initialValue); - if (startDate) { - startDate = this.parseDate(startDate); + if (this.trigger(EVENT_PICK, { + view: _view || '', + date: date + }).isDefaultPrevented()) { + return; + } - if (date.getTime() < startDate.getTime()) { - date = new Date(startDate); - } + date = this.formatDate(this.date); + this.setValue(date); - this.startDate = startDate; - } + if (this.isInput) { + $this.trigger('input'); + $this.trigger('change'); + } + }, - if (endDate) { - endDate = this.parseDate(endDate); - if (startDate && endDate.getTime() < startDate.getTime()) { - endDate = new Date(startDate); - } + // Reset the datepicker + reset: function reset() { + this.setDate(this.initialDate, true); + this.setValue(this.initialValue); - if (date.getTime() > endDate.getTime()) { - date = new Date(endDate); - } + if (this.shown) { + this.showView(this.options.startView); + } + }, + + + /** + * Get the month name with given argument or the current date + * + * @param {Number} month (optional) + * @param {Boolean} short (optional) + * @return {String} (month name) + */ + getMonthName: function getMonthName(month, short) { + var options = this.options; + var monthsShort = options.monthsShort; + var months = options.months; + + + if ($.isNumeric(month)) { + month = Number(month); + } else if (isUndefined(short)) { + short = month; + } - this.endDate = endDate; - } + if (short === true) { + months = monthsShort; + } - this.date = date; - this.viewDate = new Date(date); - this.initialDate = new Date(this.date); + return months[isNumber(month) ? month : this.date.getMonth()]; + }, - this.bind(); - if (options.autoShow || this.isInline) { - this.show(); + /** + * Get the day name with given argument or the current date + * + * @param {Number} day (optional) + * @param {Boolean} short (optional) + * @param {Boolean} min (optional) + * @return {String} (day name) + */ + getDayName: function getDayName(day, short, min) { + var options = this.options; + var days = options.days; + + + if ($.isNumeric(day)) { + day = Number(day); + } else { + if (isUndefined(min)) { + min = short; } - if (options.autoPick) { - this.pick(); + if (isUndefined(short)) { + short = day; } - }, + } - build: function () { - var options = this.options; - var $this = this.$element; - var $picker; + if (min) { + days = options.daysMin; + } else if (short) { + days = options.daysShort; + } - if (this.isBuilt) { - return; - } + return days[isNumber(day) ? day : this.date.getDay()]; + }, - this.isBuilt = true; - this.$picker = $picker = $(options.template); - this.$week = $picker.find('[data-view="week"]'); + /** + * Get the current date + * + * @param {Boolean} formatted (optional) + * @return {Date|String} (date) + */ + getDate: function getDate(formatted) { + var date = this.date; - // Years view - this.$yearsPicker = $picker.find('[data-view="years picker"]'); - this.$yearsPrev = $picker.find('[data-view="years prev"]'); - this.$yearsNext = $picker.find('[data-view="years next"]'); - this.$yearsCurrent = $picker.find('[data-view="years current"]'); - this.$years = $picker.find('[data-view="years"]'); - // Months view - this.$monthsPicker = $picker.find('[data-view="months picker"]'); - this.$yearPrev = $picker.find('[data-view="year prev"]'); - this.$yearNext = $picker.find('[data-view="year next"]'); - this.$yearCurrent = $picker.find('[data-view="year current"]'); - this.$months = $picker.find('[data-view="months"]'); + return formatted ? this.formatDate(date) : new Date(date); + }, - // Days view - this.$daysPicker = $picker.find('[data-view="days picker"]'); - this.$monthPrev = $picker.find('[data-view="month prev"]'); - this.$monthNext = $picker.find('[data-view="month next"]'); - this.$monthCurrent = $picker.find('[data-view="month current"]'); - this.$days = $picker.find('[data-view="days"]'); - - if (this.isInline) { - $(options.container || $this).append($picker.addClass(CLASS_INLINE)); - } else { - $(document.body).append($picker.addClass(CLASS_DROPDOWN)); - $picker.addClass(CLASS_HIDE); - } - this.fillWeek(); - }, + /** + * Set the current date with a new date + * + * @param {Date} date + * @param {Boolean} _updated (private) + */ + setDate: function setDate(date, _updated) { + var filter = this.options.filter; + - unbuild: function () { - if (!this.isBuilt) { + if (isDate(date) || isString(date)) { + date = this.parseDate(date); + + if ($.isFunction(filter) && filter.call(this.$element, date) === false) { return; } - this.isBuilt = false; - this.$picker.remove(); - }, - - bind: function () { - var options = this.options; - var $this = this.$element; + this.date = date; + this.viewDate = new Date(date); - if ($.isFunction(options.show)) { - $this.on(EVENT_SHOW, options.show); + if (!_updated) { + this.pick(); } - if ($.isFunction(options.hide)) { - $this.on(EVENT_HIDE, options.hide); + if (this.built) { + this.render(); } + } + }, - if ($.isFunction(options.pick)) { - $this.on(EVENT_PICK, options.pick); - } - if (this.isInput) { - $this.on(EVENT_KEYUP, $.proxy(this.keyup, this)); - } + /** + * Set the start view date with a new date + * + * @param {Date} date + */ + setStartDate: function setStartDate(date) { + if (isDate(date) || isString(date)) { + this.startDate = this.parseDate(date); - if (!this.isInline) { - if (options.trigger) { - this.$trigger.on(EVENT_CLICK, $.proxy(this.toggle, this)); - } else if (this.isInput) { - $this.on(EVENT_FOCUS, $.proxy(this.show, this)); - } else { - $this.on(EVENT_CLICK, $.proxy(this.show, this)); - } + if (this.built) { + this.render(); } - }, + } + }, - unbind: function () { - var options = this.options; - var $this = this.$element; - if ($.isFunction(options.show)) { - $this.off(EVENT_SHOW, options.show); - } + /** + * Set the end view date with a new date + * + * @param {Date} date + */ + setEndDate: function setEndDate(date) { + if (isDate(date) || isString(date)) { + this.endDate = this.parseDate(date); - if ($.isFunction(options.hide)) { - $this.off(EVENT_HIDE, options.hide); + if (this.built) { + this.render(); } + } + }, - if ($.isFunction(options.pick)) { - $this.off(EVENT_PICK, options.pick); - } - if (this.isInput) { - $this.off(EVENT_KEYUP, this.keyup); - } + /** + * Parse a date string with the set date format + * + * @param {String} date + * @return {Date} (parsed date) + */ + parseDate: function parseDate(date) { + var format = this.format; - if (!this.isInline) { - if (options.trigger) { - this.$trigger.off(EVENT_CLICK, this.toggle); - } else if (this.isInput) { - $this.off(EVENT_FOCUS, this.show); - } else { - $this.off(EVENT_CLICK, this.show); - } - } - }, + var parts = []; - showView: function (view) { - var $yearsPicker = this.$yearsPicker; - var $monthsPicker = this.$monthsPicker; - var $daysPicker = this.$daysPicker; - var format = this.format; + if (isDate(date)) { + return new Date(date.getFullYear(), date.getMonth(), date.getDate()); + } else if (isString(date)) { + parts = date.match(REGEXP_DIGITS) || []; + } - if (format.hasYear || format.hasMonth || format.hasDay) { - switch (Number(view)) { - case VIEWS.YEARS: - case 'years': - $monthsPicker.addClass(CLASS_HIDE); - $daysPicker.addClass(CLASS_HIDE); + date = new Date(); - if (format.hasYear) { - this.fillYears(); - $yearsPicker.removeClass(CLASS_HIDE); - this.place(); - } else { - this.showView(VIEWS.DAYS); - } + var length = format.parts.length; + + var year = date.getFullYear(); + var day = date.getDate(); + var month = date.getMonth(); + if (parts.length === length) { + $.each(parts, function (i, part) { + var value = parseInt(part, 10) || 1; + + switch (format.parts[i]) { + case 'dd': + case 'd': + day = value; break; - case VIEWS.MONTHS: - case 'months': - $yearsPicker.addClass(CLASS_HIDE); - $daysPicker.addClass(CLASS_HIDE); + case 'mm': + case 'm': + month = value - 1; + break; - if (format.hasMonth) { - this.fillMonths(); - $monthsPicker.removeClass(CLASS_HIDE); - this.place(); - } else { - this.showView(VIEWS.YEARS); - } + case 'yy': + year = 2000 + value; + break; + case 'yyyy': + year = value; break; - // case VIEWS.DAYS: - // case 'days': default: - $yearsPicker.addClass(CLASS_HIDE); - $monthsPicker.addClass(CLASS_HIDE); - - if (format.hasDay) { - this.fillDays(); - $daysPicker.removeClass(CLASS_HIDE); - this.place(); - } else { - this.showView(VIEWS.MONTHS); - } } - } - }, + }); + } - hideView: function () { - if (!this.isInline && this.options.autoHide) { - this.hide(); - } - }, + return new Date(year, month, day); + }, - place: function () { - if (this.isInline) { - return; - } - var options = this.options; - var $this = this.$element; - var $picker = this.$picker; - var containerWidth = $document.outerWidth(); - var containerHeight = $document.outerHeight(); - var elementWidth = $this.outerWidth(); - var elementHeight = $this.outerHeight(); - var width = $picker.width(); - var height = $picker.height(); - var offsets = $this.offset(); - var left = offsets.left; - var top = offsets.top; - var offset = parseFloat(options.offset) || 10; - var placement = CLASS_TOP_LEFT; + /** + * Format a date object to a string with the set date format + * + * @param {Date} date + * @return {String} (formatted date) + */ + formatDate: function formatDate(date) { + var format = this.format; - if (top > height && top + elementHeight + height > containerHeight) { - top -= height + offset; - placement = CLASS_BOTTOM_LEFT; - } else { - top += elementHeight + offset; - } - - if (left + width > containerWidth) { - left = left + elementWidth - width; - placement = placement.replace('left', 'right'); - } + var formatted = ''; - $picker.removeClass(CLASS_PLACEMENTS).addClass(placement).css({ - top: top, - left: left, - zIndex: parseInt(options.zIndex, 10) + if (isDate(date)) { + var year = date.getFullYear(); + var values = { + d: date.getDate(), + m: date.getMonth() + 1, + yy: year.toString().substring(2), + yyyy: year + }; + + values.dd = (values.d < 10 ? '0' : '') + values.d; + values.mm = (values.m < 10 ? '0' : '') + values.m; + formatted = format.source; + $.each(format.parts, function (i, part) { + formatted = formatted.replace(part, values[part]); }); - }, + } - // A shortcut for triggering custom events - trigger: function (type, data) { - var e = $.Event(type, data); + return formatted; + }, - this.$element.trigger(e); - return e; - }, + // Destroy the datepicker and remove the instance from the target element + destroy: function destroy() { + this.unbind(); + this.unbuild(); + this.$element.removeData(NAMESPACE); + } +}; - createItem: function (data) { - var options = this.options; - var itemTag = options.itemTag; - var defaults = { - text: '', - view: '', - muted: false, - picked: false, - disabled: false, - highlighted: false - }; - var classes = []; +var handlers = { + click: function click(e) { + var $target = $(e.target); + var options = this.options, + viewDate = this.viewDate, + format = this.format; - $.extend(defaults, data); - if (defaults.muted) { - classes.push(options.mutedClass); - } + e.stopPropagation(); + e.preventDefault(); - if (defaults.highlighted) { - classes.push(options.highlightedClass); - } + if ($target.hasClass('disabled')) { + return; + } - if (defaults.picked) { - classes.push(options.pickedClass); - } + var view = $target.data('view'); + var viewYear = viewDate.getFullYear(); + var viewMonth = viewDate.getMonth(); + var viewDay = viewDate.getDate(); - if (defaults.disabled) { - classes.push(options.disabledClass); - } + switch (view) { + case 'years prev': + case 'years next': + { + viewYear = view === 'years prev' ? viewYear - 10 : viewYear + 10; + this.viewDate = new Date(viewYear, viewMonth, getMinDay(viewYear, viewMonth, viewDay)); + this.renderYears(); + break; + } - return ( - '<' + itemTag + ' class="' + classes.join(' ') + '"' + - (defaults.view ? ' data-view="' + defaults.view + '"' : '') + - '>' + - defaults.text + - '' - ); - }, - - fillAll: function () { - this.fillYears(); - this.fillMonths(); - this.fillDays(); - }, - - fillWeek: function () { - var options = this.options; - var weekStart = parseInt(options.weekStart, 10) % 7; - var days = options.daysMin; - var list = ''; - var i; + case 'year prev': + case 'year next': + viewYear = view === 'year prev' ? viewYear - 1 : viewYear + 1; + this.viewDate = new Date(viewYear, viewMonth, getMinDay(viewYear, viewMonth, viewDay)); + this.renderMonths(); + break; - days = $.merge(days.slice(weekStart), days.slice(0, weekStart)); + case 'year current': + if (format.hasYear) { + this.showView(VIEWS.YEARS); + } - for (i = 0; i <= 6; i++) { - list += this.createItem({ - text: days[i] - }); - } + break; + + case 'year picked': + if (format.hasMonth) { + this.showView(VIEWS.MONTHS); + } else { + $target.addClass(options.pickedClass).siblings().removeClass(options.pickedClass); + this.hideView(); + } - this.$week.html(list); - }, + this.pick('year'); + break; - fillYears: function () { - var options = this.options; - var disabledClass = options.disabledClass || ''; - var suffix = options.yearSuffix || ''; - var filter = $.isFunction(options.filter) && options.filter; - var startDate = this.startDate; - var endDate = this.endDate; - var viewDate = this.viewDate; - var viewYear = viewDate.getFullYear(); - var now = new Date(); - var thisYear = now.getFullYear(); - var date = this.date; - var year = date.getFullYear(); - var isPrevDisabled = false; - var isNextDisabled = false; - var isDisabled = false; - var isPicked = false; - var isMuted = false; - var list = ''; - var start = -5; - var end = 6; - var i; - - for (i = start; i <= end; i++) { - date = new Date(viewYear + i, 1, 1); - isMuted = i === start || i === end; - isPicked = (viewYear + i) === year; - isDisabled = false; - - if (startDate) { - isDisabled = date.getFullYear() < startDate.getFullYear(); - - if (i === start) { - isPrevDisabled = isDisabled; - } + case 'year': + viewYear = parseInt($target.text(), 10); + this.date = new Date(viewYear, viewMonth, getMinDay(viewYear, viewMonth, viewDay)); + + if (format.hasMonth) { + this.viewDate = new Date(this.date); + this.showView(VIEWS.MONTHS); + } else { + $target.addClass(options.pickedClass).siblings().removeClass(options.pickedClass); + this.hideView(); } - if (!isDisabled && endDate) { - isDisabled = date.getFullYear() > endDate.getFullYear(); + this.pick('year'); + break; - if (i === end) { - isNextDisabled = isDisabled; - } + case 'month prev': + case 'month next': + viewMonth = view === 'month prev' ? viewMonth - 1 : viewMonth + 1; + this.viewDate = new Date(viewYear, viewMonth, getMinDay(viewYear, viewMonth, viewDay)); + this.renderDays(); + break; + + case 'month current': + if (format.hasMonth) { + this.showView(VIEWS.MONTHS); } - if (!isDisabled && filter) { - isDisabled = filter.call(this.$element, date) === false; + break; + + case 'month picked': + if (format.hasDay) { + this.showView(VIEWS.DAYS); + } else { + $target.addClass(options.pickedClass).siblings().removeClass(options.pickedClass); + this.hideView(); } - list += this.createItem({ - text: viewYear + i, - view: isDisabled ? 'year disabled' : isPicked ? 'year picked' : 'year', - muted: isMuted, - picked: isPicked, - disabled: isDisabled, - highlighted: date.getFullYear() === thisYear - }); - } + this.pick('month'); + break; - this.$yearsPrev.toggleClass(disabledClass, isPrevDisabled); - this.$yearsNext.toggleClass(disabledClass, isNextDisabled); - this.$yearsCurrent. - toggleClass(disabledClass, true). - html((viewYear + start) + suffix + ' - ' + (viewYear + end) + suffix); - this.$years.html(list); - }, + case 'month': + viewMonth = $.inArray($target.text(), options.monthsShort); + this.date = new Date(viewYear, viewMonth, getMinDay(viewYear, viewMonth, viewDay)); - fillMonths: function () { - var options = this.options; - var disabledClass = options.disabledClass || ''; - var months = options.monthsShort; - var filter = $.isFunction(options.filter) && options.filter; - var startDate = this.startDate; - var endDate = this.endDate; - var viewDate = this.viewDate; - var viewYear = viewDate.getFullYear(); - var now = new Date(); - var thisYear = now.getFullYear(); - var thisMonth = now.getMonth(); - var date = this.date; - var year = date.getFullYear(); - var month = date.getMonth(); - var isPrevDisabled = false; - var isNextDisabled = false; - var isDisabled = false; - var isPicked = false; - var list = ''; - var i; - - for (i = 0; i <= 11; i++) { - date = new Date(viewYear, i, 1); - isPicked = viewYear === year && i === month; - isDisabled = false; - - if (startDate) { - isPrevDisabled = date.getFullYear() === startDate.getFullYear(); - isDisabled = isPrevDisabled && date.getMonth() < startDate.getMonth(); + if (format.hasDay) { + this.viewDate = new Date(viewYear, viewMonth, getMinDay(viewYear, viewMonth, viewDay)); + this.showView(VIEWS.DAYS); + } else { + $target.addClass(options.pickedClass).siblings().removeClass(options.pickedClass); + this.hideView(); } - if (!isDisabled && endDate) { - isNextDisabled = date.getFullYear() === endDate.getFullYear(); - isDisabled = isNextDisabled && date.getMonth() > endDate.getMonth(); - console.log(isNextDisabled, date, endDate) - } + this.pick('month'); + break; - if (!isDisabled && filter) { - isDisabled = filter.call(this.$element, date) === false; + case 'day prev': + case 'day next': + case 'day': + if (view === 'day prev') { + viewMonth -= 1; + } else if (view === 'day next') { + viewMonth += 1; } - list += this.createItem({ - index: i, - text: months[i], - view: isDisabled ? 'month disabled' : isPicked ? 'month picked' : 'month', - picked: isPicked, - disabled: isDisabled, - highlighted: viewYear === thisYear && date.getMonth() === thisMonth - }); - } + viewDay = parseInt($target.text(), 10); + this.date = new Date(viewYear, viewMonth, viewDay); + this.viewDate = new Date(viewYear, viewMonth, viewDay); + this.renderDays(); - this.$yearPrev.toggleClass(disabledClass, isPrevDisabled); - this.$yearNext.toggleClass(disabledClass, isNextDisabled); - this.$yearCurrent. - toggleClass(disabledClass, isPrevDisabled && isNextDisabled). - html(viewYear + options.yearSuffix || ''); - this.$months.html(list); - }, + if (view === 'day') { + this.hideView(); + } - fillDays: function () { - var options = this.options; - var disabledClass = options.disabledClass || ''; - var suffix = options.yearSuffix || ''; - var months = options.monthsShort; - var weekStart = parseInt(options.weekStart, 10) % 7; - var filter = $.isFunction(options.filter) && options.filter; - var startDate = this.startDate; - var endDate = this.endDate; - var viewDate = this.viewDate; - var viewYear = viewDate.getFullYear(); - var viewMonth = viewDate.getMonth(); - var prevViewYear = viewYear; - var prevViewMonth = viewMonth; - var nextViewYear = viewYear; - var now = new Date(); - var thisYear = now.getFullYear(); - var thisMonth = now.getMonth(); - var today = now.getDate(); - var nextViewMonth = viewMonth; - var date = this.date; - var year = date.getFullYear(); - var month = date.getMonth(); - var day = date.getDate(); - var isPrevDisabled = false; - var isNextDisabled = false; - var isDisabled = false; - var isPicked = false; - var prevItems = []; - var nextItems = []; - var items = []; - var total = 42; // 6 rows and 7 columns on the days picker - var length; - var i; - var n; - - // Days of previous month - // ----------------------------------------------------------------------- - - if (viewMonth === 0) { - prevViewYear -= 1; - prevViewMonth = 11; - } else { - prevViewMonth -= 1; - } + this.pick('day'); + break; - // The length of the days of previous month - length = getDaysInMonth(prevViewYear, prevViewMonth); + case 'day picked': + this.hideView(); + this.pick('day'); + break; - // The first day of current month - date = new Date(viewYear, viewMonth, 1); + default: + } + }, + globalClick: function globalClick(_ref) { + var target = _ref.target; + var element = this.element, + $trigger = this.$trigger; - // The visible length of the days of previous month - // [0,1,2,3,4,5,6] - [0,1,2,3,4,5,6] => [-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6] - n = date.getDay() - weekStart; + var trigger = $trigger[0]; + var hidden = true; - // [-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6] => [1,2,3,4,5,6,7] - if (n <= 0) { - n += 7; + while (target !== document) { + if (target === trigger || target === element) { + hidden = false; + break; } + target = target.parentNode; + } + + if (hidden) { + this.hide(); + } + }, + keyup: function keyup() { + this.update(); + }, + globalKeyup: function globalKeyup(_ref2) { + var target = _ref2.target, + key = _ref2.key, + keyCode = _ref2.keyCode; + + if (this.isInput && target !== this.element && this.shown && (key === 'Tab' || keyCode === 9)) { + this.hide(); + } + } +}; + +var render = { + render: function render() { + this.renderYears(); + this.renderMonths(); + this.renderDays(); + }, + renderWeek: function renderWeek() { + var _this = this; + + var items = []; + var _options = this.options, + weekStart = _options.weekStart, + daysMin = _options.daysMin; + + + weekStart = parseInt(weekStart, 10) % 7; + daysMin = daysMin.slice(weekStart).concat(daysMin.slice(0, weekStart)); + $.each(daysMin, function (i, day) { + items.push(_this.createItem({ + text: day + })); + }); + + this.$week.html(items.join('')); + }, + renderYears: function renderYears() { + var options = this.options, + startDate = this.startDate, + endDate = this.endDate; + var disabledClass = options.disabledClass, + filter = options.filter, + yearSuffix = options.yearSuffix; + + var viewYear = this.viewDate.getFullYear(); + var now = new Date(); + var thisYear = now.getFullYear(); + var year = this.date.getFullYear(); + var start = -5; + var end = 6; + var items = []; + var prevDisabled = false; + var nextDisabled = false; + var i = void 0; + + for (i = start; i <= end; i += 1) { + var date = new Date(viewYear + i, 1, 1); + var disabled = false; + if (startDate) { - isPrevDisabled = date.getTime() <= startDate.getTime(); + disabled = date.getFullYear() < startDate.getFullYear(); + + if (i === start) { + prevDisabled = disabled; + } } - for (i = length - (n - 1); i <= length; i++) { - date = new Date(prevViewYear, prevViewMonth, i); - isPicked = prevViewYear === year && prevViewMonth === month && i === day; - isDisabled = false; + if (!disabled && endDate) { + disabled = date.getFullYear() > endDate.getFullYear(); - if (startDate) { - isDisabled = date.getTime() < startDate.getTime(); + if (i === end) { + nextDisabled = disabled; } + } - if (!isDisabled && filter) { - isDisabled = filter.call(this.$element, date) === false; - } + if (!disabled && filter) { + disabled = filter.call(this.$element, date) === false; + } + + var picked = viewYear + i === year; + var view = picked ? 'year picked' : 'year'; + + items.push(this.createItem({ + picked: picked, + disabled: disabled, + muted: i === start || i === end, + text: viewYear + i, + view: disabled ? 'year disabled' : view, + highlighted: date.getFullYear() === thisYear + })); + } - prevItems.push(this.createItem({ - text: i, - view: 'day prev', - muted: true, - picked: isPicked, - disabled: isDisabled, - highlighted: prevViewYear === thisYear && prevViewMonth === thisMonth && date.getDate() === today - })); + this.$yearsPrev.toggleClass(disabledClass, prevDisabled); + this.$yearsNext.toggleClass(disabledClass, nextDisabled); + this.$yearsCurrent.toggleClass(disabledClass, true).html(viewYear + start + yearSuffix + ' - ' + (viewYear + end) + yearSuffix); + this.$years.html(items.join('')); + }, + renderMonths: function renderMonths() { + var options = this.options, + startDate = this.startDate, + endDate = this.endDate, + viewDate = this.viewDate; + + var disabledClass = options.disabledClass || ''; + var months = options.monthsShort; + var filter = $.isFunction(options.filter) && options.filter; + var viewYear = viewDate.getFullYear(); + var now = new Date(); + var thisYear = now.getFullYear(); + var thisMonth = now.getMonth(); + var year = this.date.getFullYear(); + var month = this.date.getMonth(); + var items = []; + var prevDisabled = false; + var nextDisabled = false; + var i = void 0; + + for (i = 0; i <= 11; i += 1) { + var date = new Date(viewYear, i, 1); + var disabled = false; + + if (startDate) { + prevDisabled = date.getFullYear() === startDate.getFullYear(); + disabled = prevDisabled && date.getMonth() < startDate.getMonth(); } - // Days of next month - // ----------------------------------------------------------------------- + if (!disabled && endDate) { + nextDisabled = date.getFullYear() === endDate.getFullYear(); + disabled = nextDisabled && date.getMonth() > endDate.getMonth(); + } - if (viewMonth === 11) { - nextViewYear += 1; - nextViewMonth = 0; - } else { - nextViewMonth += 1; + if (!disabled && filter) { + disabled = filter.call(this.$element, date) === false; } - // The length of the days of current month - length = getDaysInMonth(viewYear, viewMonth); + var picked = viewYear === year && i === month; + var view = picked ? 'month picked' : 'month'; - // The visible length of next month - n = total - (prevItems.length + length); + items.push(this.createItem({ + disabled: disabled, + picked: picked, + highlighted: viewYear === thisYear && date.getMonth() === thisMonth, + index: i, + text: months[i], + view: disabled ? 'month disabled' : view + })); + } - // The last day of current month - date = new Date(viewYear, viewMonth, length); + this.$yearPrev.toggleClass(disabledClass, prevDisabled); + this.$yearNext.toggleClass(disabledClass, nextDisabled); + this.$yearCurrent.toggleClass(disabledClass, prevDisabled && nextDisabled).html(viewYear + options.yearSuffix || ''); + this.$months.html(items.join('')); + }, + renderDays: function renderDays() { + var $element = this.$element, + options = this.options, + startDate = this.startDate, + endDate = this.endDate, + viewDate = this.viewDate, + currentDate = this.date; + var disabledClass = options.disabledClass, + filter = options.filter, + monthsShort = options.monthsShort, + weekStart = options.weekStart, + yearSuffix = options.yearSuffix; + + var viewYear = viewDate.getFullYear(); + var viewMonth = viewDate.getMonth(); + var now = new Date(); + var thisYear = now.getFullYear(); + var thisMonth = now.getMonth(); + var thisDay = now.getDate(); + var year = currentDate.getFullYear(); + var month = currentDate.getMonth(); + var day = currentDate.getDate(); + var length = void 0; + var i = void 0; + var n = void 0; + + // Days of prev month + // ----------------------------------------------------------------------- + + var prevItems = []; + var prevViewYear = viewYear; + var prevViewMonth = viewMonth; + var prevDisabled = false; + + if (viewMonth === 0) { + prevViewYear -= 1; + prevViewMonth = 11; + } else { + prevViewMonth -= 1; + } - if (endDate) { - isNextDisabled = date.getTime() >= endDate.getTime(); + // The length of the days of prev month + length = getDaysInMonth(prevViewYear, prevViewMonth); + + // The first day of current month + var firstDay = new Date(viewYear, viewMonth, 1); + + // The visible length of the days of prev month + // [0,1,2,3,4,5,6] - [0,1,2,3,4,5,6] => [-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6] + n = firstDay.getDay() - parseInt(weekStart, 10) % 7; + + // [-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6] => [1,2,3,4,5,6,7] + if (n <= 0) { + n += 7; + } + + if (startDate) { + prevDisabled = firstDay.getTime() <= startDate.getTime(); + } + + for (i = length - (n - 1); i <= length; i += 1) { + var prevViewDate = new Date(prevViewYear, prevViewMonth, i); + var disabled = false; + + if (startDate) { + disabled = prevViewDate.getTime() < startDate.getTime(); + } + + if (!disabled && filter) { + disabled = filter.call($element, prevViewDate) === false; } - for (i = 1; i <= n; i++) { - date = new Date(nextViewYear, nextViewMonth, i); - isPicked = nextViewYear === year && nextViewMonth === month && i === day; - isDisabled = false; + prevItems.push(this.createItem({ + disabled: disabled, + highlighted: prevViewYear === thisYear && prevViewMonth === thisMonth && prevViewDate.getDate() === thisDay, + muted: true, + picked: prevViewYear === year && prevViewMonth === month && i === day, + text: i, + view: 'day prev' + })); + } + + // Days of next month + // ----------------------------------------------------------------------- + + var nextItems = []; + var nextViewYear = viewYear; + var nextViewMonth = viewMonth; + var nextDisabled = false; + + if (viewMonth === 11) { + nextViewYear += 1; + nextViewMonth = 0; + } else { + nextViewMonth += 1; + } + + // The length of the days of current month + length = getDaysInMonth(viewYear, viewMonth); + + // The visible length of next month (42 means 6 rows and 7 columns) + n = 42 - (prevItems.length + length); - if (endDate) { - isDisabled = date.getTime() > endDate.getTime(); - } + // The last day of current month + var lastDate = new Date(viewYear, viewMonth, length); - if (!isDisabled && filter) { - isDisabled = filter.call(this.$element, date) === false; - } + if (endDate) { + nextDisabled = lastDate.getTime() >= endDate.getTime(); + } + + for (i = 1; i <= n; i += 1) { + var date = new Date(nextViewYear, nextViewMonth, i); + var picked = nextViewYear === year && nextViewMonth === month && i === day; + var _disabled = false; - nextItems.push(this.createItem({ - text: i, - view: 'day next', - muted: true, - picked: isPicked, - disabled: isDisabled, - highlighted: nextViewYear === thisYear && nextViewMonth === thisMonth && date.getDate() === today - })); + if (endDate) { + _disabled = date.getTime() > endDate.getTime(); } - // Days of current month - // ----------------------------------------------------------------------- + if (!_disabled && filter) { + _disabled = filter.call($element, date) === false; + } - for (i = 1; i <= length; i++) { - date = new Date(viewYear, viewMonth, i); - isPicked = viewYear === year && viewMonth === month && i === day; - isDisabled = false; + nextItems.push(this.createItem({ + disabled: _disabled, + picked: picked, + highlighted: nextViewYear === thisYear && nextViewMonth === thisMonth && date.getDate() === thisDay, + muted: true, + text: i, + view: 'day next' + })); + } - if (startDate) { - isDisabled = date.getTime() < startDate.getTime(); - } + // Days of current month + // ----------------------------------------------------------------------- - if (!isDisabled && endDate) { - isDisabled = date.getTime() > endDate.getTime(); - } + var items = []; - if (!isDisabled && filter) { - isDisabled = filter.call(this.$element, date) === false; - } + for (i = 1; i <= length; i += 1) { + var _date = new Date(viewYear, viewMonth, i); + var _disabled2 = false; - items.push(this.createItem({ - text: i, - view: isDisabled ? 'day disabled' : isPicked ? 'day picked' : 'day', - picked: isPicked, - disabled: isDisabled, - highlighted: viewYear === thisYear && viewMonth === thisMonth && date.getDate() === today - })); + if (startDate) { + _disabled2 = _date.getTime() < startDate.getTime(); } - // Render days picker - // ----------------------------------------------------------------------- - - this.$monthPrev.toggleClass(disabledClass, isPrevDisabled); - this.$monthNext.toggleClass(disabledClass, isNextDisabled); - this.$monthCurrent. - toggleClass(disabledClass, isPrevDisabled && isNextDisabled). - html( - options.yearFirst ? - viewYear + suffix + ' ' + months[viewMonth] : - months[viewMonth] + ' ' + viewYear + suffix - ); - this.$days.html(prevItems.join('') + items.join(' ') + nextItems.join('')); - }, - - click: function (e) { - var $target = $(e.target); - var options = this.options; - var viewDate = this.viewDate; - var viewYear; - var viewMonth; - var viewDay; - var isYear; - var year; - var view; - - e.stopPropagation(); - e.preventDefault(); - - if ($target.hasClass('disabled')) { - return; + if (!_disabled2 && endDate) { + _disabled2 = _date.getTime() > endDate.getTime(); } - viewYear = viewDate.getFullYear(); - viewMonth = viewDate.getMonth(); - viewDay = viewDate.getDate(); - view = $target.data('view'); + if (!_disabled2 && filter) { + _disabled2 = filter.call($element, _date) === false; + } - switch (view) { - case 'years prev': - case 'years next': - viewYear = view === 'years prev' ? viewYear - 10 : viewYear + 10; - year = $target.text(); - isYear = REGEXP_YEAR.test(year); + var _picked = viewYear === year && viewMonth === month && i === day; + var view = _picked ? 'day picked' : 'day'; - if (isYear) { - viewYear = parseInt(year, 10); - this.date = new Date(viewYear, viewMonth, min(viewDay, 28)); - } + items.push(this.createItem({ + disabled: _disabled2, + picked: _picked, + highlighted: viewYear === thisYear && viewMonth === thisMonth && _date.getDate() === thisDay, + text: i, + view: _disabled2 ? 'day disabled' : view + })); + } - this.viewDate = new Date(viewYear, viewMonth, min(viewDay, 28)); - this.fillYears(); + // Render days picker + // ----------------------------------------------------------------------- - if (isYear) { - this.showView(VIEWS.MONTHS); - this.pick('year'); - } + this.$monthPrev.toggleClass(disabledClass, prevDisabled); + this.$monthNext.toggleClass(disabledClass, nextDisabled); + this.$monthCurrent.toggleClass(disabledClass, prevDisabled && nextDisabled).html(options.yearFirst ? viewYear + yearSuffix + ' ' + monthsShort[viewMonth] : monthsShort[viewMonth] + ' ' + viewYear + yearSuffix); + this.$days.html(prevItems.join('') + items.join('') + nextItems.join('')); + } +}; - break; +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); - case 'year prev': - case 'year next': - viewYear = view === 'year prev' ? viewYear - 1 : viewYear + 1; - this.viewDate = new Date(viewYear, viewMonth, min(viewDay, 28)); - this.fillMonths(); - break; +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - case 'year current': - if (this.format.hasYear) { - this.showView(VIEWS.YEARS); - } +var _window = window; +var document$1 = _window.document; - break; +var $document = $(document$1); - case 'year picked': - if (this.format.hasMonth) { - this.showView(VIEWS.MONTHS); - } else { - $target.addClass(options.pickedClass) - .siblings() - .removeClass(options.pickedClass); - this.hideView(); - } - - this.pick('year'); - break; +// Classes +var CLASS_TOP_LEFT = NAMESPACE + '-top-left'; +var CLASS_TOP_RIGHT = NAMESPACE + '-top-right'; +var CLASS_BOTTOM_LEFT = NAMESPACE + '-bottom-left'; +var CLASS_BOTTOM_RIGHT = NAMESPACE + '-bottom-right'; +var CLASS_PLACEMENTS = [CLASS_TOP_LEFT, CLASS_TOP_RIGHT, CLASS_BOTTOM_LEFT, CLASS_BOTTOM_RIGHT].join(' '); - case 'year': - viewYear = parseInt($target.text(), 10); - this.date = new Date(viewYear, viewMonth, min(viewDay, 28)); - - if (this.format.hasMonth) { - this.viewDate = new Date(viewYear, viewMonth, min(viewDay, 28)); - this.showView(VIEWS.MONTHS); - } else { - $target.addClass(options.pickedClass) - .siblings() - .removeClass(options.pickedClass); - this.hideView(); - } - - this.pick('year'); - break; +var Datepicker = function () { + function Datepicker(element) { + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; - case 'month prev': - case 'month next': - viewMonth = view === 'month prev' ? viewMonth - 1 : view === 'month next' ? viewMonth + 1 : viewMonth; - this.viewDate = new Date(viewYear, viewMonth, min(viewDay, 28)); - this.fillDays(); - break; + _classCallCheck(this, Datepicker); - case 'month current': - if (this.format.hasMonth) { - this.showView(VIEWS.MONTHS); - } + this.$element = $(element); + this.element = element; + this.options = $.extend({}, DEFAULTS, LANGUAGES[options.language], options); + this.built = false; + this.shown = false; + this.isInput = false; + this.inline = false; + this.initialValue = ''; + this.initialDate = null; + this.startDate = null; + this.endDate = null; + this.init(); + } - break; + _createClass(Datepicker, [{ + key: 'init', + value: function init() { + var $this = this.$element, + options = this.options; + var startDate = options.startDate, + endDate = options.endDate, + date = options.date; - case 'month picked': - if (this.format.hasDay) { - this.showView(VIEWS.DAYS); - } else { - $target.addClass(options.pickedClass) - .siblings() - .removeClass(options.pickedClass); - this.hideView(); - } - - this.pick('month'); - break; - case 'month': - viewMonth = $.inArray($target.text(), options.monthsShort); - this.date = new Date(viewYear, viewMonth, min(viewDay, 28)); - - if (this.format.hasDay) { - this.viewDate = new Date(viewYear, viewMonth, min(viewDay, 28)); - this.showView(VIEWS.DAYS); - } else { - $target.addClass(options.pickedClass) - .siblings() - .removeClass(options.pickedClass); - this.hideView(); - } - - this.pick('month'); - break; + this.$trigger = $(options.trigger); + this.isInput = $this.is('input') || $this.is('textarea'); + this.inline = options.inline && (options.container || !this.isInput); + this.format = parseFormat(options.format); - case 'day prev': - case 'day next': - case 'day': - viewMonth = view === 'day prev' ? viewMonth - 1 : view === 'day next' ? viewMonth + 1 : viewMonth; - viewDay = parseInt($target.text(), 10); - this.date = new Date(viewYear, viewMonth, viewDay); - this.viewDate = new Date(viewYear, viewMonth, viewDay); - this.fillDays(); + var initialValue = this.getValue(); - if (view === 'day') { - this.hideView(); - } + this.initialValue = initialValue; + this.oldValue = initialValue; + date = this.parseDate(date || initialValue); - this.pick('day'); - break; + if (startDate) { + startDate = this.parseDate(startDate); - case 'day picked': - this.hideView(); - this.pick('day'); - break; + if (date.getTime() < startDate.getTime()) { + date = new Date(startDate); + } - // No default + this.startDate = startDate; } - }, - clickDoc: function (e) { - var target = e.target; - var element = this.$element[0]; - var trigger = this.$trigger[0]; - var ignored; + if (endDate) { + endDate = this.parseDate(endDate); - while (target !== document) { - if (target === trigger || target === element) { - ignored = true; - break; + if (startDate && endDate.getTime() < startDate.getTime()) { + endDate = new Date(startDate); } - target = target.parentNode; - } + if (date.getTime() > endDate.getTime()) { + date = new Date(endDate); + } - if (!ignored) { - this.hide(); + this.endDate = endDate; } - }, - keyup: function () { - this.update(); - }, + this.date = date; + this.viewDate = new Date(date); + this.initialDate = new Date(this.date); + this.bind(); - keyupDoc: function (e) { - if (this.isInput && e.target !== this.$element[0] && - this.isShown && (e.key === 'Tab' || e.keyCode === 9)) { - this.hide(); + if (options.autoShow || this.inline) { + this.show(); } - }, - - getValue: function () { - var $this = this.$element; - var val = ''; - if (this.isInput) { - val = $this.val(); - } else if (this.isInline) { - if (this.options.container) { - val = $this.text(); - } - } else { - val = $this.text(); + if (options.autoPick) { + this.pick(); + } + } + }, { + key: 'build', + value: function build() { + if (this.built) { + return; } - return val; - }, + this.built = true; - setValue: function (val) { - var $this = this.$element; + var $this = this.$element, + options = this.options; - val = isString(val) ? val : ''; + var $picker = $(options.template); - if (this.isInput) { - $this.val(val); - } else if (this.isInline) { - if (this.options.container) { - $this.text(val); - } - } else { - $this.text(val); - } - }, + this.$picker = $picker; + this.$week = $picker.find(selectorOf('week')); + // Years view + this.$yearsPicker = $picker.find(selectorOf('years picker')); + this.$yearsPrev = $picker.find(selectorOf('years prev')); + this.$yearsNext = $picker.find(selectorOf('years next')); + this.$yearsCurrent = $picker.find(selectorOf('years current')); + this.$years = $picker.find(selectorOf('years')); - // Methods - // ------------------------------------------------------------------------- + // Months view + this.$monthsPicker = $picker.find(selectorOf('months picker')); + this.$yearPrev = $picker.find(selectorOf('year prev')); + this.$yearNext = $picker.find(selectorOf('year next')); + this.$yearCurrent = $picker.find(selectorOf('year current')); + this.$months = $picker.find(selectorOf('months')); - // Show the datepicker - show: function () { - if (!this.isBuilt) { - this.build(); + // Days view + this.$daysPicker = $picker.find(selectorOf('days picker')); + this.$monthPrev = $picker.find(selectorOf('month prev')); + this.$monthNext = $picker.find(selectorOf('month next')); + this.$monthCurrent = $picker.find(selectorOf('month current')); + this.$days = $picker.find(selectorOf('days')); + + if (this.inline) { + $(options.container || $this).append($picker.addClass(NAMESPACE + '-inline')); + } else { + $(document$1.body).append($picker.addClass(NAMESPACE + '-dropdown')); + $picker.addClass(CLASS_HIDE); } - if (this.isShown) { + this.renderWeek(); + } + }, { + key: 'unbuild', + value: function unbuild() { + if (!this.built) { return; } - if (this.trigger(EVENT_SHOW).isDefaultPrevented()) { - return; - } + this.built = false; + this.$picker.remove(); + } + }, { + key: 'bind', + value: function bind() { + var options = this.options, + $this = this.$element; - this.isShown = true; - this.$picker.removeClass(CLASS_HIDE).on(EVENT_CLICK, $.proxy(this.click, this)); - this.showView(this.options.startView); - if (!this.isInline) { - $window.on(EVENT_RESIZE, (this._place = proxy(this.place, this))); - $document.on(EVENT_CLICK, (this._clickDoc = proxy(this.clickDoc, this))); - $document.on(EVENT_KEYUP, (this._keyupDoc = proxy(this.keyupDoc, this))); - this.place(); + if ($.isFunction(options.show)) { + $this.on(EVENT_SHOW, options.show); } - }, - // Hide the datepicker - hide: function () { - if (!this.isShown) { - return; + if ($.isFunction(options.hide)) { + $this.on(EVENT_HIDE, options.hide); } - if (this.trigger(EVENT_HIDE).isDefaultPrevented()) { - return; + if ($.isFunction(options.pick)) { + $this.on(EVENT_PICK, options.pick); } - this.isShown = false; - this.$picker.addClass(CLASS_HIDE).off(EVENT_CLICK, this.click); - - if (!this.isInline) { - $window.off(EVENT_RESIZE, this._place); - $document.off(EVENT_CLICK, this._clickDoc); - $document.off(EVENT_KEYUP, this._keyupDoc); + if (this.isInput) { + $this.on(EVENT_KEYUP, $.proxy(this.keyup, this)); } - }, - toggle: function () { - if (this.isShown) { - this.hide(); - } else { - this.show(); + if (!this.inline) { + if (options.trigger) { + this.$trigger.on(EVENT_CLICK, $.proxy(this.toggle, this)); + } else if (this.isInput) { + $this.on(EVENT_FOCUS, $.proxy(this.show, this)); + } else { + $this.on(EVENT_CLICK, $.proxy(this.show, this)); + } } - }, + } + }, { + key: 'unbind', + value: function unbind() { + var $this = this.$element, + options = this.options; - // Update the datepicker with the current input value - update: function () { - var value = this.getValue(); - if (value === this.oldValue) { - return; + if ($.isFunction(options.show)) { + $this.off(EVENT_SHOW, options.show); } - this.setDate(value, true); - this.oldValue = value; - }, - - /** - * Pick the current date to the element - * - * @param {String} _view (private) - */ - pick: function (_view) { - var $this = this.$element; - var date = this.date; - - if (this.trigger(EVENT_PICK, { - view: _view || '', - date: date - }).isDefaultPrevented()) { - return; + if ($.isFunction(options.hide)) { + $this.off(EVENT_HIDE, options.hide); } - this.setValue(date = this.formatDate(this.date)); + if ($.isFunction(options.pick)) { + $this.off(EVENT_PICK, options.pick); + } if (this.isInput) { - $this.trigger('change'); + $this.off(EVENT_KEYUP, this.keyup); } - }, - // Reset the datepicker - reset: function () { - this.setDate(this.initialDate, true); - this.setValue(this.initialValue); - - if (this.isShown) { - this.showView(this.options.startView); + if (!this.inline) { + if (options.trigger) { + this.$trigger.off(EVENT_CLICK, this.toggle); + } else if (this.isInput) { + $this.off(EVENT_FOCUS, this.show); + } else { + $this.off(EVENT_CLICK, this.show); + } } - }, - - /** - * Get the month name with given argument or the current date - * - * @param {Number} month (optional) - * @param {Boolean} short (optional) - * @return {String} (month name) - */ - getMonthName: function (month, short) { - var options = this.options; - var months = options.months; + } + }, { + key: 'showView', + value: function showView(view) { + var $yearsPicker = this.$yearsPicker, + $monthsPicker = this.$monthsPicker, + $daysPicker = this.$daysPicker, + format = this.format; - if ($.isNumeric(month)) { - month = Number(month); - } else if (isUndefined(short)) { - short = month; - } - if (short === true) { - months = options.monthsShort; - } + if (format.hasYear || format.hasMonth || format.hasDay) { + switch (Number(view)) { + case VIEWS.YEARS: + $monthsPicker.addClass(CLASS_HIDE); + $daysPicker.addClass(CLASS_HIDE); - return months[isNumber(month) ? month : this.date.getMonth()]; - }, - - /** - * Get the day name with given argument or the current date - * - * @param {Number} day (optional) - * @param {Boolean} short (optional) - * @param {Boolean} min (optional) - * @return {String} (day name) - */ - getDayName: function (day, short, min) { - var options = this.options; - var days = options.days; + if (format.hasYear) { + this.renderYears(); + $yearsPicker.removeClass(CLASS_HIDE); + this.place(); + } else { + this.showView(VIEWS.DAYS); + } - if ($.isNumeric(day)) { - day = Number(day); - } else { - if (isUndefined(min)) { - min = short; - } + break; - if (isUndefined(short)) { - short = day; - } - } + case VIEWS.MONTHS: + $yearsPicker.addClass(CLASS_HIDE); + $daysPicker.addClass(CLASS_HIDE); - days = min === true ? options.daysMin : short === true ? options.daysShort : days; - - return days[isNumber(day) ? day : this.date.getDay()]; - }, - - /** - * Get the current date - * - * @param {Boolean} formatted (optional) - * @return {Date|String} (date) - */ - getDate: function (formatted) { - var date = this.date; - - return formatted ? this.formatDate(date) : new Date(date); - }, - - /** - * Set the current date with a new date - * - * @param {Date} date - * @param {Boolean} _isUpdated (private) - */ - setDate: function (date, _isUpdated) { - var filter = this.options.filter; - - if (isDate(date) || isString(date)) { - date = this.parseDate(date); - - if ($.isFunction(filter) && filter.call(this.$element, date) === false) { - return; - } + if (format.hasMonth) { + this.renderMonths(); + $monthsPicker.removeClass(CLASS_HIDE); + this.place(); + } else { + this.showView(VIEWS.YEARS); + } - this.date = date; - this.viewDate = new Date(date); + break; - if (!_isUpdated) { - this.pick(); - } + // case VIEWS.DAYS: + default: + $yearsPicker.addClass(CLASS_HIDE); + $monthsPicker.addClass(CLASS_HIDE); - if (this.isBuilt) { - this.fillAll(); - } - } - }, - - /** - * Set the start view date with a new date - * - * @param {Date} date - */ - setStartDate: function (date) { - if (isDate(date) || isString(date)) { - this.startDate = this.parseDate(date); - - if (this.isBuilt) { - this.fillAll(); - } - } - }, - - /** - * Set the end view date with a new date - * - * @param {Date} date - */ - setEndDate: function (date) { - if (isDate(date) || isString(date)) { - this.endDate = this.parseDate(date); - - if (this.isBuilt) { - this.fillAll(); + if (format.hasDay) { + this.renderDays(); + $daysPicker.removeClass(CLASS_HIDE); + this.place(); + } else { + this.showView(VIEWS.MONTHS); + } } } - }, - - /** - * Parse a date string with the set date format - * - * @param {String} date - * @return {Date} (parsed date) - */ - parseDate: function (date) { - var format = this.format; - var parts = []; - var length; - var year; - var day; - var month; - var val; - var i; - - if (isDate(date)) { - return new Date(date.getFullYear(), date.getMonth(), date.getDate()); - } else if (isString(date)) { - parts = date.match(REGEXP_DIGITS) || []; - } - - date = new Date(); - year = date.getFullYear(); - day = date.getDate(); - month = date.getMonth(); - length = format.parts.length; - - if (parts.length === length) { - for (i = 0; i < length; i++) { - val = parseInt(parts[i], 10) || 1; - - switch (format.parts[i]) { - case 'dd': - case 'd': - day = val; - break; - - case 'mm': - case 'm': - month = val - 1; - break; - - case 'yy': - year = 2000 + val; - break; - - case 'yyyy': - year = val; - break; - - // No default - } - } + } + }, { + key: 'hideView', + value: function hideView() { + if (!this.inline && this.options.autoHide) { + this.hide(); } - - return new Date(year, month, day); - }, - - /** - * Format a date object to a string with the set date format - * - * @param {Date} date - * @return {String} (formatted date) - */ - formatDate: function (date) { - var format = this.format; - var formatted = ''; - var length; - var year; - var part; - var val; - var i; - - if (isDate(date)) { - formatted = format.source; - year = date.getFullYear(); - val = { - d: date.getDate(), - m: date.getMonth() + 1, - yy: year.toString().substring(2), - yyyy: year - }; - - val.dd = (val.d < 10 ? '0' : '') + val.d; - val.mm = (val.m < 10 ? '0' : '') + val.m; - length = format.parts.length; - - for (i = 0; i < length; i++) { - part = format.parts[i]; - formatted = formatted.replace(part, val[part]); - } + } + }, { + key: 'place', + value: function place() { + if (this.inline) { + return; } - return formatted; - }, + var $this = this.$element, + options = this.options, + $picker = this.$picker; - // Destroy the datepicker and remove the instance from the target element - destroy: function () { - this.unbind(); - this.unbuild(); - this.$element.removeData(NAMESPACE); - } - }; - - Datepicker.LANGUAGES = {}; + var containerWidth = $document.outerWidth(); + var containerHeight = $document.outerHeight(); + var elementWidth = $this.outerWidth(); + var elementHeight = $this.outerHeight(); + var width = $picker.width(); + var height = $picker.height(); - Datepicker.DEFAULTS = { - // Show the datepicker automatically when initialized - autoShow: false, + var _$this$offset = $this.offset(), + left = _$this$offset.left, + top = _$this$offset.top; - // Hide the datepicker automatically when picked - autoHide: false, + var offset = parseFloat(options.offset); + var placement = CLASS_TOP_LEFT; - // Pick the initial date automatically when initialized - autoPick: false, + if (isNaN(offset)) { + offset = 10; + } - // Enable inline mode - inline: false, + if (top > height && top + elementHeight + height > containerHeight) { + top -= height + offset; + placement = CLASS_BOTTOM_LEFT; + } else { + top += elementHeight + offset; + } - // A element (or selector) for putting the datepicker - container: null, + if (left + width > containerWidth) { + left += elementWidth - width; + placement = placement.replace('left', 'right'); + } - // A element (or selector) for triggering the datepicker - trigger: null, + $picker.removeClass(CLASS_PLACEMENTS).addClass(placement).css({ + top: top, + left: left, + zIndex: parseInt(options.zIndex, 10) + }); + } - // The ISO language code (built-in: en-US) - language: '', + // A shortcut for triggering custom events - // The date string format - format: 'mm/dd/yyyy', + }, { + key: 'trigger', + value: function trigger(type, data) { + var e = $.Event(type, data); - // The initial date - date: null, + this.$element.trigger(e); - // The start view date - startDate: null, + return e; + } + }, { + key: 'createItem', + value: function createItem(data) { + var options = this.options; + var itemTag = options.itemTag; - // The end view date - endDate: null, + var item = { + text: '', + view: '', + muted: false, + picked: false, + disabled: false, + highlighted: false + }; + var classes = []; - // The start view when initialized - startView: 0, // 0 for days, 1 for months, 2 for years + $.extend(item, data); - // The start day of the week - weekStart: 0, // 0 for Sunday, 1 for Monday, 2 for Tuesday, 3 for Wednesday, 4 for Thursday, 5 for Friday, 6 for Saturday + if (item.muted) { + classes.push(options.mutedClass); + } - // Show year before month on the datepicker header - yearFirst: false, + if (item.highlighted) { + classes.push(options.highlightedClass); + } - // A string suffix to the year number. - yearSuffix: '', + if (item.picked) { + classes.push(options.pickedClass); + } - // Days' name of the week. - days: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], + if (item.disabled) { + classes.push(options.disabledClass); + } - // Shorter days' name - daysShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], + return '<' + itemTag + ' class="' + classes.join(' ') + '" data-view="' + item.view + '">' + item.text + ''; + } + }, { + key: 'getValue', + value: function getValue() { + var $this = this.$element; - // Shortest days' name - daysMin: ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'], + return this.isInput ? $this.val() : $this.text(); + } + }, { + key: 'setValue', + value: function setValue() { + var value = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ''; - // Months' name - months: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'], + var $this = this.$element; - // Shorter months' name - monthsShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], + if (this.isInput) { + $this.val(value); + } else { + $this.text(value); + } + } + }], [{ + key: 'setDefaults', + value: function setDefaults() { + var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; - // A element tag for each item of years, months and days - itemTag: 'li', + $.extend(DEFAULTS, LANGUAGES[options.language], options); + } + }]); - // A class (CSS) for muted date item - mutedClass: 'muted', + return Datepicker; +}(); - // A class (CSS) for picked date item - pickedClass: 'picked', +$.extend(Datepicker.prototype, render, handlers, methods); - // A class (CSS) for disabled date item - disabledClass: 'disabled', +var AnotherDatepicker = $.fn.datepicker; - // A class (CSS) for highlight date item - highlightedClass: 'highlighted', +$.fn.datepicker = function jQueryDatepicker(option) { + for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { + args[_key - 1] = arguments[_key]; + } - // The template of the datepicker - template: ( - '
                          ' + - '
                          ' + - '
                            ' + - '
                          • ' + - '
                          • ' + - '
                          • ' + - '
                          ' + - '
                            ' + - '
                            ' + - '
                            ' + - '
                              ' + - '
                            • ' + - '
                            • ' + - '
                            • ' + - '
                            ' + - '
                              ' + - '
                              ' + - '
                              ' + - '
                                ' + - '
                              • ' + - '
                              • ' + - '
                              • ' + - '
                              ' + - '
                                ' + - '
                                  ' + - '
                                  ' + - '
                                  ' - ), + var result = void 0; - // The offset top or bottom of the datepicker from the element - offset: 10, + this.each(function each() { + var $this = $(this); + var data = $this.data('datepicker'); - // The `z-index` of the datepicker - zIndex: 1000, - - // Filter each date item (return `false` to disable a date item) - filter: null, - - // Event shortcuts - show: null, - hide: null, - pick: null - }; + if (!data) { + if (/destroy/.test(option)) { + return; + } - Datepicker.setDefaults = function (options) { - options = $.isPlainObject(options) ? options : {}; + var options = $.extend({}, $this.data(), $.isPlainObject(option) && option); - if (options.language) { - options = $.extend({}, Datepicker.LANGUAGES[options.language], options); + data = new Datepicker(this, options); + $this.data('datepicker', data); } - $.extend(Datepicker.DEFAULTS, options); - }; - - // Save the other datepicker - Datepicker.other = $.fn.datepicker; - - // Register as jQuery plugin - $.fn.datepicker = function (option) { - var args = toArray(arguments, 1); - var result; - - this.each(function () { - var $this = $(this); - var data = $this.data(NAMESPACE); - var options; - var fn; - - if (!data) { - if (/destroy/.test(option)) { - return; - } - - options = $.extend({}, $this.data(), $.isPlainObject(option) && option); - $this.data(NAMESPACE, (data = new Datepicker(this, options))); - } + if (typeof option === 'string') { + var fn = data[option]; - if (isString(option) && $.isFunction(fn = data[option])) { + if ($.isFunction(fn)) { result = fn.apply(data, args); } - }); - - return isUndefined(result) ? this : result; - }; + } + }); - $.fn.datepicker.Constructor = Datepicker; - $.fn.datepicker.languages = Datepicker.LANGUAGES; - $.fn.datepicker.setDefaults = Datepicker.setDefaults; + return typeof result !== 'undefined' ? result : this; +}; - // No conflict - $.fn.datepicker.noConflict = function () { - $.fn.datepicker = Datepicker.other; - return this; - }; +$.fn.datepicker.Constructor = Datepicker; +$.fn.datepicker.languages = LANGUAGES; +$.fn.datepicker.setDefaults = Datepicker.setDefaults; +$.fn.datepicker.noConflict = function noConflict() { + $.fn.datepicker = AnotherDatepicker; + return this; +}; -}); +}))); diff --git a/package.json b/package.json index 78a52d9..d96c8ba 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,10 @@ { "name": "@fengyuanchen/datepicker", "description": "A simple jQuery datepicker plugin.", - "version": "0.5.5", - "main": "dist/datepicker.js", + "version": "0.6.0", + "main": "dist/datepicker.common.js", + "module": "dist/datepicker.esm.js", + "browser": "dist/datepicker.js", "license": "MIT", "repository": "fengyuanchen/datepicker", "homepage": "https://github.com/fengyuanchen/datepicker",