;(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); } }; })();