;(function () {
var templates = {
days:'' +
'
',
months: '' +
'',
years: '' +
''
},
datepicker = $.fn.datepicker,
dp = datepicker.Constructor;
datepicker.Body = function (d, type, opts) {
this.d = d;
this.type = type;
this.opts = opts;
this.$el = $('');
if (this.opts.onlyTimepicker) return;
this.init();
};
datepicker.Body.prototype = {
init: function () {
this._buildBaseHtml();
this._render();
this._bindEvents();
},
_bindEvents: function () {
this.$el.on('click', '.datepicker--cell', $.proxy(this._onClickCell, this));
},
_buildBaseHtml: function () {
this.$el = $(templates[this.type]).appendTo(this.d.$content);
this.$names = $('.datepicker--days-names', this.$el);
this.$cells = $('.datepicker--cells', this.$el);
},
_getDayNamesHtml: function (firstDay, curDay, html, i) {
curDay = curDay != undefined ? curDay : firstDay;
html = html ? html : '';
i = i != undefined ? i : 0;
if (i > 7) return html;
if (curDay == 7) return this._getDayNamesHtml(firstDay, 0, html, ++i);
html += '' + this.d.loc.daysMin[curDay] + '
';
return this._getDayNamesHtml(firstDay, ++curDay, html, ++i);
},
_getCellContents: function (date, type) {
var classes = "datepicker--cell datepicker--cell-" + type,
currentDate = new Date(),
parent = this.d,
minRange = dp.resetTime(parent.minRange),
maxRange = dp.resetTime(parent.maxRange),
opts = parent.opts,
d = dp.getParsedDate(date),
render = {},
html = d.date;
switch (type) {
case 'day':
if (parent.isWeekend(d.day)) classes += " -weekend-";
if (d.month != this.d.parsedDate.month) {
classes += " -other-month-";
if (!opts.selectOtherMonths) {
classes += " -disabled-";
}
if (!opts.showOtherMonths) html = '';
}
break;
case 'month':
html = parent.loc[parent.opts.monthsField][d.month];
break;
case 'year':
var decade = parent.curDecade;
html = d.year;
if (d.year < decade[0] || d.year > decade[1]) {
classes += ' -other-decade-';
if (!opts.selectOtherYears) {
classes += " -disabled-";
}
if (!opts.showOtherYears) html = '';
}
break;
}
if (opts.onRenderCell) {
render = opts.onRenderCell(date, type) || {};
html = render.html ? render.html : html;
classes += render.classes ? ' ' + render.classes : '';
}
if (opts.range) {
if (dp.isSame(minRange, date, type)) classes += ' -range-from-';
if (dp.isSame(maxRange, date, type)) classes += ' -range-to-';
if (parent.selectedDates.length == 1 && parent.focused) {
if (
(dp.bigger(minRange, date) && dp.less(parent.focused, date)) ||
(dp.less(maxRange, date) && dp.bigger(parent.focused, date)))
{
classes += ' -in-range-'
}
if (dp.less(maxRange, date) && dp.isSame(parent.focused, date)) {
classes += ' -range-from-'
}
if (dp.bigger(minRange, date) && dp.isSame(parent.focused, date)) {
classes += ' -range-to-'
}
} else if (parent.selectedDates.length == 2) {
if (dp.bigger(minRange, date) && dp.less(maxRange, date)) {
classes += ' -in-range-'
}
}
}
if (dp.isSame(currentDate, date, type)) classes += ' -current-';
if (parent.focused && dp.isSame(date, parent.focused, type)) classes += ' -focus-';
if (parent._isSelected(date, type)) classes += ' -selected-';
if (!parent._isInRange(date, type) || render.disabled) classes += ' -disabled-';
return {
html: html,
classes: classes
}
},
/**
* Calculates days number to render. Generates days html and returns it.
* @param {object} date - Date object
* @returns {string}
* @private
*/
_getDaysHtml: function (date) {
var totalMonthDays = dp.getDaysCount(date),
firstMonthDay = new Date(date.getFullYear(), date.getMonth(), 1).getDay(),
lastMonthDay = new Date(date.getFullYear(), date.getMonth(), totalMonthDays).getDay(),
daysFromPevMonth = firstMonthDay - this.d.loc.firstDay,
daysFromNextMonth = 6 - lastMonthDay + this.d.loc.firstDay;
daysFromPevMonth = daysFromPevMonth < 0 ? daysFromPevMonth + 7 : daysFromPevMonth;
daysFromNextMonth = daysFromNextMonth > 6 ? daysFromNextMonth - 7 : daysFromNextMonth;
var startDayIndex = -daysFromPevMonth + 1,
m, y,
html = '';
for (var i = startDayIndex, max = totalMonthDays + daysFromNextMonth; i <= max; i++) {
y = date.getFullYear();
m = date.getMonth();
html += this._getDayHtml(new Date(y, m, i))
}
return html;
},
_getDayHtml: function (date) {
var content = this._getCellContents(date, 'day');
return '' + content.html + '
';
},
/**
* Generates months html
* @param {object} date - date instance
* @returns {string}
* @private
*/
_getMonthsHtml: function (date) {
var html = '',
d = dp.getParsedDate(date),
i = 0;
while(i < 12) {
html += this._getMonthHtml(new Date(d.year, i));
i++
}
return html;
},
_getMonthHtml: function (date) {
var content = this._getCellContents(date, 'month');
return '' + content.html + '
'
},
_getYearsHtml: function (date) {
var d = dp.getParsedDate(date),
decade = dp.getDecade(date),
firstYear = decade[0] - 1,
html = '',
i = firstYear;
for (i; i <= decade[1] + 1; i++) {
html += this._getYearHtml(new Date(i , 0));
}
return html;
},
_getYearHtml: function (date) {
var content = this._getCellContents(date, 'year');
return '' + content.html + '
'
},
_renderTypes: {
days: function () {
var dayNames = this._getDayNamesHtml(this.d.loc.firstDay),
days = this._getDaysHtml(this.d.currentDate);
this.$cells.html(days);
this.$names.html(dayNames)
},
months: function () {
var html = this._getMonthsHtml(this.d.currentDate);
this.$cells.html(html)
},
years: function () {
var html = this._getYearsHtml(this.d.currentDate);
this.$cells.html(html)
}
},
_render: function () {
if (this.opts.onlyTimepicker) return;
this._renderTypes[this.type].bind(this)();
},
_update: function () {
var $cells = $('.datepicker--cell', this.$cells),
_this = this,
classes,
$cell,
date;
$cells.each(function (cell, i) {
$cell = $(this);
date = _this.d._getDateFromCell($(this));
classes = _this._getCellContents(date, _this.d.cellType);
$cell.attr('class',classes.classes)
});
},
show: function () {
if (this.opts.onlyTimepicker) return;
this.$el.addClass('active');
this.acitve = true;
},
hide: function () {
this.$el.removeClass('active');
this.active = false;
},
// Events
// -------------------------------------------------
_handleClick: function (el) {
var date = el.data('date') || 1,
month = el.data('month') || 0,
year = el.data('year') || this.d.parsedDate.year,
dp = this.d;
// Change view if min view does not reach yet
if (dp.view != this.opts.minView) {
dp.down(new Date(year, month, date));
return;
}
// Select date if min view is reached
var selectedDate = new Date(year, month, date),
alreadySelected = this.d._isSelected(selectedDate, this.d.cellType);
if (!alreadySelected) {
dp._trigger('clickCell', selectedDate);
return;
}
dp._handleAlreadySelectedDates.bind(dp, alreadySelected, selectedDate)();
},
_onClickCell: function (e) {
var $el = $(e.target).closest('.datepicker--cell');
if ($el.hasClass('-disabled-')) return;
this._handleClick.bind(this)($el);
}
};
})();