text: ;(function () {
      var templates = {
          days:'' +
          '<div class="datepicker--days datepicker--body">' +
          '<div class="datepicker--days-names"></div>' +
          '<div class="datepicker--cells datepicker--cells-days"></div>' +
          '</div>',
          months: '' +
          '<div class="datepicker--months datepicker--body">' +
          '<div class="datepicker--cells datepicker--cells-months"></div>' +
          '</div>',
          years: '' +
          '<div class="datepicker--years datepicker--body">' +
          '<div class="datepicker--cells datepicker--cells-years"></div>' +
          '</div>'
          },
          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 += '<div class="datepicker--day-name' + (this.d.isWeekend(curDay) ? " -weekend-" : "") + '">' + this.d.loc.daysMin[curDay] + '</div>';
  
              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 '<div class="' + content.classes + '" ' +
                  'data-date="' + date.getDate() + '" ' +
                  'data-month="' + date.getMonth() + '" ' +
                  'data-year="' + date.getFullYear() + '">' + content.html + '</div>';
          },
  
          /**
           * 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 '<div class="' + content.classes + '" data-month="' + date.getMonth() + '">' + content.html + '</div>'
          },
  
          _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 '<div class="' + content.classes + '" data-year="' + date.getFullYear() + '">' + content.html + '</div>'
          },
  
          _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);
          }
      };
  })();
  