/*!
* Datepicker v0.2.1
* https://github.com/fengyuanchen/datepicker
*
* Copyright (c) 2014-2015 Fengyuan Chen
* Released under the MIT license
*
* Date: 2015-10-26T02:21:30.292Z
*/
"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);
}
})(function ($) {
'use strict';
var $window = $(window);
var document = window.document;
var $document = $(document);
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 = 'datepicker-inline';
var CLASS_DROPDOWN = 'datepicker-dropdown';
var CLASS_TOP_LEFT = 'datepicker-top-left';
var CLASS_TOP_RIGHT = 'datepicker-top-right';
var CLASS_BOTTOM_LEFT = 'datepicker-bottom-left';
var CLASS_BOTTOM_RIGHT = 'datepicker-bottom-right';
var CLASS_PLACEMENTS = [
CLASS_TOP_LEFT,
CLASS_TOP_RIGHT,
CLASS_BOTTOM_LEFT,
CLASS_BOTTOM_RIGHT
].join(' ');
var CLASS_HIDE = 'datepicker-hide';
// Maths
var num = Number;
var min = Math.min;
// Utilities
var toString = Object.prototype.toString;
function isString(str) {
return typeof str === 'string';
}
function isNumber(num) {
return typeof num === 'number' && !isNaN(num);
}
function isUndefined(obj) {
return typeof obj === 'undefined';
}
function isDate(date) {
if (typeof date !== 'object' || date === null) {
return false;
}
return toString.call(date) === '[object Date]';
}
function toArray(obj, offset) {
var args = [];
// This is necessary for IE8
if (isNumber(offset)) {
args.push(offset);
}
return args.slice.apply(obj, args);
}
// Custom proxy to avoid jQuery's guid
function proxy(fn, context) {
var args = toArray(arguments, 2);
return function () {
return fn.apply(context, args.concat(toArray(arguments)));
};
}
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 parseFormat(format) {
var source = String(format).toLowerCase();
var parts = source.match(REGEXP_FORMAT);
var length;
var i;
if (!parts || parts.length === 0) {
throw new Error('Invalid date format.');
}
format = {
source: source,
parts: parts
};
length = parts.length;
for (i = 0; i < length; i++) {
switch (parts[i]) {
case 'dd':
case 'd':
format.hasDay = true;
break;
case 'mm':
case 'm':
format.hasMonth = true;
break;
case 'yyyy':
case 'yy':
format.hasYear = true;
break;
// No default
}
}
return format;
}
function Datepicker(element, options) {
this.$element = $(element);
this.options = $.extend({}, Datepicker.DEFAULTS, $.isPlainObject(options) && 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();
}
Datepicker.prototype = {
constructor: Datepicker,
version: '0.2.1',
init: function () {
var options = this.options;
var $this = this.$element;
var startDate = options.startDate;
var endDate = options.endDate;
var date = options.date;
if (options.language) {
$.extend(options, Datepicker.LANGUAGES[options.language]);
}
this.$trigger = $(options.trigger || $this);
this.isInput = $this.is('input') || $this.is('textarea');
this.isInline = options.inline && (options.container || !this.isInput);
this.format = parseFormat(options.format);
this.initialValue = this.getValue();
date = this.parseDate(date || this.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.isInline) {
this.show();
}
if (options.autopick) {
this.pick();
}
},
build: function () {
var options = this.options;
var $this = this.$element;
var $picker;
if (this.isBuilt) {
return;
}
this.isBuilt = true;
this.$picker = $picker = $(options.template);
this.$week = $picker.find('[data-view="week"]');
// 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"]');
// 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();
},
unbuild: function () {
if (!this.isBuilt) {
return;
}
this.isBuilt = false;
this.$picker.remove();
},
bind: function () {
var options = this.options;
var $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 (!options.trigger) {
$this.on(EVENT_FOCUS, $.proxy(this.show, this));
}
}
this.$trigger.on(EVENT_CLICK, $.proxy(this.show, this));
},
unbind: function () {
var options = this.options;
var $this = this.$element;
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 (!options.trigger) {
$this.off(EVENT_FOCUS, this.show);
}
}
this.$trigger.off(EVENT_CLICK, this.show);
},
showView: function (view) {
var $yearsPicker = this.$yearsPicker;
var $monthsPicker = this.$monthsPicker;
var $daysPicker = this.$daysPicker;
var format = this.format;
if (format.hasYear || format.hasMonth || format.hasDay) {
switch (num(view)) {
case 2:
case 'years':
$monthsPicker.addClass(CLASS_HIDE);
$daysPicker.addClass(CLASS_HIDE);
if (format.hasYear) {
this.fillYears();
$yearsPicker.removeClass(CLASS_HIDE);
} else {
this.showView(0);
}
break;
case 1:
case 'months':
$yearsPicker.addClass(CLASS_HIDE);
$daysPicker.addClass(CLASS_HIDE);
if (format.hasMonth) {
this.fillMonths();
$monthsPicker.removeClass(CLASS_HIDE);
} else {
this.showView(2);
}
break;
// case 0:
// case 'days':
default:
$yearsPicker.addClass(CLASS_HIDE);
$monthsPicker.addClass(CLASS_HIDE);
if (format.hasDay) {
this.fillDays();
$daysPicker.removeClass(CLASS_HIDE);
} else {
this.showView(1);
}
}
}
},
hideView: function () {
if (this.options.autohide) {
this.hide();
}
},
place: function () {
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;
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');
}
$picker.removeClass(CLASS_PLACEMENTS).addClass(placement).css({
top: top,
left: left,
zIndex: parseInt(options.zIndex, 10)
});
},
// A shortcut for triggering custom events
trigger: function (type, data) {
var e = $.Event(type, data);
this.$element.trigger(e);
return e;
},
createItem: function (data) {
var options = this.options;
var itemTag = options.itemTag;
var defaults = {
text: '',
view: '',
muted: false,
picked: false,
disabled: false
};
$.extend(defaults, data);
return (
'<' + itemTag + ' ' +
(defaults.disabled ? 'class="' + options.disabledClass + '"' :
defaults.picked ? 'class="' + options.pickedClass + '"' :
defaults.muted ? 'class="' + options.mutedClass + '"' : '') +
(defaults.view ? ' data-view="' + defaults.view + '"' : '') +
'>' +
defaults.text +
'</' + itemTag + '>'
);
},
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;
days = $.merge(days.slice(weekStart), days.slice(0, weekStart));
for (i = 0; i <= 6; i++) {
list += this.createItem({
text: days[i]
});
}
this.$week.html(list);
},
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 viewMonth = viewDate.getMonth();
var viewDay = viewDate.getDate();
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, viewMonth, viewDay);
isMuted = i === start || i === end;
isPicked = (viewYear + i) === year;
isDisabled = false;
if (startDate) {
isDisabled = date.getFullYear() < startDate.getFullYear();
if (i === start) {
isPrevDisabled = isDisabled;
}
}
if (!isDisabled && endDate) {
isDisabled = date.getFullYear() > endDate.getFullYear();
if (i === end) {
isNextDisabled = isDisabled;
}
}
if (!isDisabled && filter) {
isDisabled = filter.call(this.$element, date) === false;
}
list += this.createItem({
text: viewYear + i,
view: isDisabled ? 'year disabled' : isPicked ? 'year picked' : 'year',
muted: isMuted,
picked: isPicked,
disabled: isDisabled
});
}
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);
},
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 viewDay = viewDate.getDate();
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, viewDay);
isPicked = viewYear === year && i === month;
isDisabled = false;
if (startDate) {
isPrevDisabled = date.getFullYear() === startDate.getFullYear();
isDisabled = isPrevDisabled && date.getMonth() < startDate.getMonth();
}
if (!isDisabled && endDate) {
isNextDisabled = date.getFullYear() === endDate.getFullYear();
isDisabled = isNextDisabled && date.getMonth() > endDate.getMonth();
}
if (!isDisabled && filter) {
isDisabled = filter.call(this.$element, date) === false;
}
list += this.createItem({
index: i,
text: months[i],
view: isDisabled ? 'month disabled' : isPicked ? 'month picked' : 'month',
picked: isPicked,
disabled: isDisabled
});
}
this.$yearPrev.toggleClass(disabledClass, isPrevDisabled);
this.$yearNext.toggleClass(disabledClass, isNextDisabled);
this.$yearCurrent.
toggleClass(disabledClass, isPrevDisabled && isNextDisabled).
html(viewYear + options.yearSuffix || '');
this.$months.html(list);
},
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 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;
}
// The length of the days of previous month
length = getDaysInMonth(prevViewYear, prevViewMonth);
// The first day of current month
date = new Date(viewYear, viewMonth, 1);
// 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;
// [-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) {
isPrevDisabled = date.getTime() <= startDate.getTime();
}
for (i = length - (n - 1); i <= length; i++) {
date = new Date(prevViewYear, prevViewMonth, i);
isDisabled = false;
if (startDate) {
isDisabled = date.getTime() < startDate.getTime();
}
if (!isDisabled && filter) {
isDisabled = filter.call(this.$element, date) === false;
}
prevItems.push(this.createItem({
text: i,
view: 'day prev',
muted: true,
disabled: isDisabled
}));
}
// Days of next month
// -----------------------------------------------------------------------
if (viewMonth === 11) {
nextViewYear += 1;
nextViewYear = 0;
} else {
nextViewMonth += 1;
}
// The length of the days of current month
length = getDaysInMonth(viewYear, viewMonth);
// The visible length of next month
n = total - (prevItems.length + length);
// The last day of current month
date = new Date(viewYear, viewMonth, length);
if (endDate) {
isNextDisabled = date.getTime() >= endDate.getTime();
}
for (i = 1; i <= n; i++) {
date = new Date(nextViewYear, nextViewMonth, i);
isDisabled = false;
if (endDate) {
isDisabled = date.getTime() > endDate.getTime();
}
if (!isDisabled && filter) {
isDisabled = filter.call(this.$element, date) === false;
}
nextItems.push(this.createItem({
text: i,
view: 'day next',
muted: true,
disabled: isDisabled
}));
}
// Days of current month
// -----------------------------------------------------------------------
for (i = 1; i <= length; i++) {
date = new Date(viewYear, viewMonth, i);
isPicked = viewYear === year && viewMonth === month && i === day;
isDisabled = false;
if (startDate) {
isDisabled = date.getTime() < startDate.getTime();
}
if (!isDisabled && endDate) {
isDisabled = date.getTime() > endDate.getTime();
}
if (!isDisabled && filter) {
isDisabled = filter.call(this.$element, date) === false;
}
items.push(this.createItem({
text: i,
view: isDisabled ? 'day disabled' : isPicked ? 'day picked' : 'day',
picked: isPicked,
disabled: isDisabled
}));
}
// 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 viewDate = this.viewDate;
var viewYear;
var viewMonth;
var viewDay;
var isYear;
var year;
var view;
e.stopPropagation();
e.preventDefault();
if ($target.hasClass('disabled')) {
return;
}
viewYear = viewDate.getFullYear();
viewMonth = viewDate.getMonth();
viewDay = viewDate.getDate();
view = $target.data('view');
switch (view) {
case 'years prev':
case 'years next':
viewYear = view === 'years prev' ? viewYear - 10 : viewYear + 10;
year = $target.text();
isYear = REGEXP_YEAR.test(year);
if (isYear) {
viewYear = parseInt(year, 10);
this.date = new Date(viewYear, viewMonth, min(viewDay, 28));
}
this.viewDate = new Date(viewYear, viewMonth, min(viewDay, 28));
this.fillYears();
if (isYear) {
this.showView(1);
this.pick('year');
}
break;
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;
case 'year current':
if (this.format.hasYear) {
this.showView(2);
}
break;
case 'year picked':
if (this.format.hasMonth) {
this.showView(1);
} else {
this.hideView();
}
break;
case 'year':
viewYear = parseInt($target.text(), 10);
this.date = new Date(viewYear, viewMonth, min(viewDay, 28));
this.viewDate = new Date(viewYear, viewMonth, min(viewDay, 28));
if (this.format.hasMonth) {
this.showView(1);
} else {
this.hideView();
}
this.pick('year');
break;
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;
case 'month current':
if (this.format.hasMonth) {
this.showView(1);
}
break;
case 'month picked':
if (this.format.hasDay) {
this.showView(0);
} else {
this.hideView();
}
break;
case 'month':
viewMonth = $.inArray($target.text(), this.options.monthsShort);
this.date = new Date(viewYear, viewMonth, min(viewDay, 28));
this.viewDate = new Date(viewYear, viewMonth, min(viewDay, 28));
if (this.format.hasDay) {
this.showView(0);
} else {
this.hideView();
}
this.pick('month');
break;
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();
if (view === 'day') {
this.hideView();
}
this.pick('day');
break;
case 'day picked':
this.hideView();
this.pick('day');
break;
// No default
}
},
clickDoc: function (e) {
var target = e.target;
var trigger = this.$trigger[0];
var ignored;
while (target !== document) {
if (target === trigger) {
ignored = true;
break;
}
target = target.parentNode;
}
if (!ignored) {
this.hide();
}
},
keyup: function () {
this.update();
},
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();
}
return val;
},
setValue: function (val) {
var $this = this.$element;
val = isString(val) ? val : '';
if (this.isInput) {
$this.val(val);
} else if (this.isInline) {
if (this.options.container) {
$this.text(val);
}
} else {
$this.text(val);
}
},
// Methods
// -------------------------------------------------------------------------
// Show the datepicker
show: function () {
if (!this.isBuilt) {
this.build();
}
if (this.isShown) {
return;
}
if (this.trigger(EVENT_SHOW).isDefaultPrevented()) {
return;
}
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)));
this.place();
}
},
// Hide the datepicker
hide: function () {
if (!this.isShown) {
return;
}
if (this.trigger(EVENT_HIDE).isDefaultPrevented()) {
return;
}
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);
}
},
// Update the datepicker with the current input value
update: function () {
this.setDate(this.getValue(), true);
},
/**
* 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;
}
this.setValue(date = this.formatDate(this.date));
if (this.isInput) {
$this.trigger('change');
}
},
// Reset the datepicker
reset: function () {
this.setDate(this.initialDate, true);
this.setValue(this.initialValue);
if (this.isShown) {
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 (month, short) {
var options = this.options;
var months = options.months;
if ($.isNumeric(month)) {
month = num(month);
} else if (isUndefined(short)) {
short = month;
}
if (short === true) {
months = options.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 (day, short, min) {
var options = this.options;
var days = options.days;
if ($.isNumeric(day)) {
day = num(day);
} else {
if (isUndefined(min)) {
min = short;
}
if (isUndefined(short)) {
short = day;
}
}
days = min === true ? options.daysMin : short === true ? options.daysShort : days;
return days[isNumber(day) ? day : this.date.getDay()];
},
/**
* Get the current date
*
* @param {Boolean} formated (optional)
* @return {Date|String} (date)
*/
getDate: function (formated) {
var date = this.date;
return formated ? 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;
}
this.date = date;
this.viewDate = new Date(date);
if (!_isUpdated) {
this.pick();
}
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();
}
}
},
/**
* 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);
} 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
}
}
}
return new Date(year, month, day);
},
/**
* Format a date object to a string with the set date format
*
* @param {Date} date
* @return {String} (formated date)
*/
formatDate: function (date) {
var format = this.format;
var formated = '';
var length;
var year;
var part;
var val;
var i;
if (isDate(date)) {
formated = 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];
formated = formated.replace(part, val[part]);
}
}
return formated;
},
// Destroy the datepicker and remove the instance from the target element
destroy: function () {
this.unbind();
this.unbuild();
this.$element.removeData(NAMESPACE);
}
};
Datepicker.LANGUAGES = {};
Datepicker.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
weekStart: 0, // 0 for Sunday, 1 for Monday, 2 for Tuesday, 3 for Wednesday, 4 for Thursday, 5 for Friday, 6 for Saturday
// 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',
// The template of the datepicker
template: (
'<div class="datepicker-container">' +
'<div class="datepicker-panel" data-view="years picker">' +
'<ul>' +
'<li data-view="years prev">‹</li>' +
'<li data-view="years current"></li>' +
'<li data-view="years next">›</li>' +
'</ul>' +
'<ul data-view="years"></ul>' +
'</div>' +
'<div class="datepicker-panel" data-view="months picker">' +
'<ul>' +
'<li data-view="year prev">‹</li>' +
'<li data-view="year current"></li>' +
'<li data-view="year next">›</li>' +
'</ul>' +
'<ul data-view="months"></ul>' +
'</div>' +
'<div class="datepicker-panel" data-view="days picker">' +
'<ul>' +
'<li data-view="month prev">‹</li>' +
'<li data-view="month current"></li>' +
'<li data-view="month next">›</li>' +
'</ul>' +
'<ul data-view="week"></ul>' +
'<ul data-view="days"></ul>' +
'</div>' +
'</div>'
),
// The offset top or bottom of the datepicker from the element
offset: 10,
// The `z-index` of the datepicker
zIndex: 1,
// Filter each date item (return `false` to disable a date item)
filter: null,
// Event shortcuts
show: null,
hide: null,
pick: null
};
Datepicker.setDefaults = function (options) {
$.extend(Datepicker.DEFAULTS, $.isPlainObject(options) && 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 (isString(option) && $.isFunction(fn = data[option])) {
result = fn.apply(data, args);
}
});
return isUndefined(result) ? this : result;
};
$.fn.datepicker.Constructor = Datepicker;
$.fn.datepicker.languages = Datepicker.LANGUAGES;
$.fn.datepicker.setDefaults = Datepicker.setDefaults;
// No conflict
$.fn.datepicker.noConflict = function () {
$.fn.datepicker = Datepicker.other;
return this;
};
});