Udgin

Bootstrap Datepicker Weekly

Jul 24th, 2013
244
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /* =========================================================
  2.  * bootstrap-datepicker.js
  3.  * http://www.eyecon.ro/bootstrap-datepicker
  4.  * =========================================================
  5.  * Copyright 2012 Stefan Petre
  6.  *
  7.  * Licensed under the Apache License, Version 2.0 (the "License");
  8.  * you may not use this file except in compliance with the License.
  9.  * You may obtain a copy of the License at
  10.  *
  11.  * http://www.apache.org/licenses/LICENSE-2.0
  12.  *
  13.  * Unless required by applicable law or agreed to in writing, software
  14.  * distributed under the License is distributed on an "AS IS" BASIS,
  15.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  16.  * See the License for the specific language governing permissions and
  17.  * limitations under the License.
  18.  * ========================================================= */
  19.  
  20. !function ($) {
  21.  
  22.     // Picker object
  23.  
  24.     var Datepicker = function (element, options) {
  25.         this.element = $(element);
  26.         this.format = DPGlobal.parseFormat(options.format || this.element.data('date-format') || 'mm/dd/yyyy');
  27.  
  28.         this.isInput = this.element.is('input');
  29.         this.component = this.element.is('.date') ? this.element.find('.add-on') : false;
  30.  
  31.         if (this.isInput) {
  32.             this.element.on({
  33.                 focus: $.proxy(this.show, this),
  34.                 //blur: $.proxy(this.hide, this),
  35.                 keyup: $.proxy(this.update, this)
  36.             });
  37.         } else {
  38.             if (this.component) {
  39.                 this.component.on('click', $.proxy(this.show, this));
  40.             } else {
  41.                 this.element.on('click', $.proxy(this.show, this));
  42.             }
  43.         }
  44.  
  45.         this.minViewMode = options.minViewMode || this.element.data('date-minviewmode') || 0;
  46.         if (typeof this.minViewMode === 'string') {
  47.             switch (this.minViewMode) {
  48.                 case 'months':
  49.                     this.minViewMode = 1;
  50.                     break;
  51.                 case 'years':
  52.                     this.minViewMode = 2;
  53.                     break;
  54.                 default:
  55.                     this.minViewMode = 0;
  56.                     break;
  57.             }
  58.         }
  59.         this.viewMode = options.viewMode || this.element.data('date-viewmode') || 0;
  60.         if (typeof this.viewMode === 'string') {
  61.             switch (this.viewMode) {
  62.                 case 'months':
  63.                     this.viewMode = 1;
  64.                     break;
  65.                 case 'years':
  66.                     this.viewMode = 2;
  67.                     break;
  68.                 default:
  69.                     this.viewMode = 0;
  70.                     break;
  71.             }
  72.         }
  73.         this.weekMode = options.weekMode || this.element.data('date-weekmode') || false;
  74.  
  75.         if (this.weekMode == true) {
  76.             this.picker = $(DPGlobal.templateW)
  77.                 .appendTo('body')
  78.                 .on({
  79.                     click: $.proxy(this.click, this)//,
  80.                     //mousedown: $.proxy(this.mousedown, this)
  81.                 });
  82.         } else {
  83.             this.picker = $(DPGlobal.template)
  84.                 .appendTo('body')
  85.                 .on({
  86.                     click: $.proxy(this.click, this)//,
  87.                     //mousedown: $.proxy(this.mousedown, this)
  88.                 });
  89.         }
  90.  
  91.         this.startViewMode = this.viewMode;
  92.         this.weekStart = options.weekStart || this.element.data('date-weekstart') || 0;
  93.         this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
  94.         this.onRender = options.onRender;
  95.         this.fillDow();
  96.         this.fillMonths();
  97.         this.update();
  98.         this.showMode();
  99.     };
  100.  
  101.     Datepicker.prototype = {
  102.         constructor: Datepicker,
  103.        
  104.         getWeek: function (date, dowOffset) {
  105.             dowOffset = dowOffset ? dowOffset : 0; //default dowOffset to zero
  106.             var newYear = new Date(date.getFullYear(), 0, 1);
  107.             var day = newYear.getDay() - dowOffset; //the day of week the year begins on
  108.             day = (day >= 0 ? day : day + 7);
  109.             var daynum = Math.floor((date.getTime() - newYear.getTime() -
  110.             (date.getTimezoneOffset() - newYear.getTimezoneOffset()) * 60000) / 86400000) + 1;
  111.             var weeknum;
  112.             //if the year starts before the middle of a week
  113.             if (day < 4) {
  114.                 weeknum = Math.floor((daynum + day - 1) / 7) + 1;
  115.                 if (weeknum > 52) {
  116.                     nYear = new Date(date.getFullYear() + 1, 0, 1);
  117.                     nday = nYear.getDay() - dowOffset;
  118.                     nday = nday >= 0 ? nday : nday + 7;
  119.                     /*if the next year starts before the middle of
  120.                       the week, it is week #1 of that year*/
  121.                     weeknum = nday < 4 ? 1 : 53;
  122.                 }
  123.             }
  124.             else {
  125.                 weeknum = Math.floor((daynum + day - 1) / 7);
  126.             }
  127.             return weeknum;
  128.         },
  129.        
  130.         show: function (e) {
  131.             this.picker.show();
  132.             this.height = this.component ? this.component.outerHeight() : this.element.outerHeight();
  133.             this.place();
  134.             $(window).on('resize', $.proxy(this.place, this));
  135.             if (e) {
  136.                 e.stopPropagation();
  137.                 e.preventDefault();
  138.             }
  139.             if (!this.isInput) {
  140.             }
  141.             var that = this;
  142.             $(document).on('mousedown', function (ev) {
  143.                 if ($(ev.target).closest('.datepicker').length == 0) {
  144.                     that.hide();
  145.                 }
  146.             });
  147.             this.element.trigger({
  148.                 type: 'show',
  149.                 date: this.date
  150.             });
  151.         },
  152.  
  153.         hide: function () {
  154.             this.picker.hide();
  155.             $(window).off('resize', this.place);
  156.             this.viewMode = this.startViewMode;
  157.             this.showMode();
  158.             if (!this.isInput) {
  159.                 $(document).off('mousedown', this.hide);
  160.             }
  161.             //this.set();
  162.             this.element.trigger({
  163.                 type: 'hide',
  164.                 date: this.date
  165.             });
  166.         },
  167.  
  168.         set: function () {
  169.             var formated = DPGlobal.formatDate(this.date, this.format);
  170.             if (this.weekMode == true) {
  171.                 var formatedWeekStart = DPGlobal.formatDate(this.weekStart1, this.format);
  172.                 var formatedWeekEnd = DPGlobal.formatDate(this.weekEnd1, this.format);
  173.                 formated = this.getWeek(this.date, this.weekStart) + ' ' + formatedWeekStart + ' - ' + formatedWeekEnd;
  174.             }
  175.             if (!this.isInput) {
  176.                 if (this.component) {
  177.                     this.element.find('input').prop('value', formated);
  178.                 }
  179.                 this.element.data('date', formated);
  180.             } else {
  181.                 this.element.prop('value', formated);
  182.             }
  183.         },
  184.  
  185.         setValue: function (newDate) {
  186.             if (typeof newDate === 'string') {
  187.                 this.date = DPGlobal.parseDate(newDate, this.format);
  188.             } else {
  189.                 this.date = new Date(newDate);
  190.             }
  191.             this.set();
  192.             this.viewDate = new Date(this.date.getFullYear(), this.date.getMonth(), 1, 0, 0, 0, 0);
  193.             this.fill();
  194.         },
  195.  
  196.         place: function () {
  197.             var offset = this.component ? this.component.offset() : this.element.offset();
  198.             this.picker.css({
  199.                 top: offset.top + this.height,
  200.                 left: offset.left
  201.             });
  202.         },
  203.  
  204.         update: function (newDate) {
  205.             this.date = DPGlobal.parseDate(
  206.                 typeof newDate === 'string' ? newDate : (this.isInput ? this.element.prop('value') : this.element.data('date')),
  207.                 this.format
  208.             );
  209.             this.viewDate = new Date(this.date.getFullYear(), this.date.getMonth(), 1, 0, 0, 0, 0);
  210.             this.fill();
  211.         },
  212.  
  213.         fillDow: function () {
  214.             var dowCnt = this.weekStart;
  215.             var html = this.weekMode == true ? '<tr><th></th>' : '<tr>';
  216.             while (dowCnt < this.weekStart + 7) {
  217.                 html += '<th class="dow">' + DPGlobal.dates.daysMin[(dowCnt++) % 7] + '</th>';
  218.             }
  219.             html += '</tr>';
  220.             this.picker.find('.datepicker-days thead').append(html);
  221.         },
  222.  
  223.         fillMonths: function () {
  224.             var html = '';
  225.             var i = 0
  226.             while (i < 12) {
  227.                 html += '<span class="month">' + DPGlobal.dates.monthsShort[i++] + '</span>';
  228.             }
  229.             this.picker.find('.datepicker-months td').append(html);
  230.         },
  231.  
  232.         fill: function () {
  233.             var d = new Date(this.viewDate),
  234.                 year = d.getFullYear(),
  235.                 month = d.getMonth(),
  236.                 currentDate = this.date.valueOf();
  237.             this.picker.find('.datepicker-days th:eq(1)')
  238.                         .text(DPGlobal.dates.months[month] + ' ' + year);
  239.             var prevMonth = new Date(year, month - 1, 28, 0, 0, 0, 0),
  240.                 day = DPGlobal.getDaysInMonth(prevMonth.getFullYear(), prevMonth.getMonth());
  241.             prevMonth.setDate(day);
  242.             prevMonth.setDate(day - (prevMonth.getDay() - this.weekStart + 7) % 7);
  243.             var nextMonth = new Date(prevMonth);
  244.             nextMonth.setDate(nextMonth.getDate() + 42);
  245.             nextMonth = nextMonth.valueOf();
  246.             var html = [];
  247.             var clsName,
  248.                 prevY,
  249.                 prevM;
  250.             while (prevMonth.valueOf() < nextMonth) {
  251.                 if (prevMonth.getDay() == this.weekStart) {
  252.                     if (this.weekMode == true && currentDate >= prevMonth.valueOf() && currentDate < (new Date(prevMonth.valueOf())).setDate(prevMonth.getDate() + 7).valueOf()) {
  253.                         this.weekStart1 = new Date(prevMonth.valueOf());
  254.                         this.weekEnd1 = new Date(new Date(prevMonth.valueOf()).setDate(prevMonth.getDate() + 6));
  255.                         html.push('<tr class="text-info">');
  256.                     } else {
  257.                         html.push('<tr>');
  258.                     }
  259.                     if (this.weekMode == true) {
  260.                         html.push('<td class="week"><small><i>' + this.getWeek(prevMonth, this.weekStart) + '</i></small></td>');
  261.                     }
  262.                 }
  263.                 clsName = this.onRender(prevMonth);
  264.                 prevY = prevMonth.getFullYear();
  265.                 prevM = prevMonth.getMonth();
  266.                 if ((prevM < month && prevY === year) || prevY < year) {
  267.                     clsName += ' old';
  268.                 } else if ((prevM > month && prevY === year) || prevY > year) {
  269.                     clsName += ' new';
  270.                 }
  271.                 if (prevMonth.valueOf() === currentDate && this.weekMode != true) {
  272.                     clsName += ' active';
  273.                 }
  274.                 html.push('<td class="day ' + clsName + '">' + prevMonth.getDate() + '</td>');
  275.                 if (prevMonth.getDay() === this.weekEnd) {
  276.                     html.push('</tr>');
  277.                 }
  278.                 prevMonth.setDate(prevMonth.getDate() + 1);
  279.             }
  280.             this.picker.find('.datepicker-days tbody').empty().append(html.join(''));
  281.             this.picker.find('.datepicker-days tbody').find('tr.active-week').css('background', '#eeeeee');
  282.             var currentYear = this.date.getFullYear();
  283.  
  284.             var months = this.picker.find('.datepicker-months')
  285.                         .find('th:eq(1)')
  286.                             .text(year)
  287.                             .end()
  288.                         .find('span').removeClass('active');
  289.             if (currentYear === year) {
  290.                 months.eq(this.date.getMonth()).addClass('active');
  291.             }
  292.  
  293.             html = '';
  294.             year = parseInt(year / 10, 10) * 10;
  295.             var yearCont = this.picker.find('.datepicker-years')
  296.                                 .find('th:eq(1)')
  297.                                     .text(year + '-' + (year + 9))
  298.                                     .end()
  299.                                 .find('td');
  300.             year -= 1;
  301.             for (var i = -1; i < 11; i++) {
  302.                 html += '<span class="year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + '">' + year + '</span>';
  303.                 year += 1;
  304.             }
  305.             yearCont.html(html);
  306.            
  307.         },
  308.  
  309.         click: function (e) {
  310.             e.stopPropagation();
  311.             e.preventDefault();
  312.             var target = $(e.target).closest('span, td, th');
  313.             if (target.length === 1) {
  314.                 switch (target[0].nodeName.toLowerCase()) {
  315.                     case 'th':
  316.                         switch (target[0].className) {
  317.                             case 'switch':
  318.                                 this.showMode(1);
  319.                                 break;
  320.                             case 'prev':
  321.                             case 'next':
  322.                                 this.viewDate['set' + DPGlobal.modes[this.viewMode].navFnc].call(
  323.                                     this.viewDate,
  324.                                     this.viewDate['get' + DPGlobal.modes[this.viewMode].navFnc].call(this.viewDate) +
  325.                                     DPGlobal.modes[this.viewMode].navStep * (target[0].className === 'prev' ? -1 : 1)
  326.                                 );
  327.                                 this.fill();
  328.                                 this.set();
  329.                                 break;
  330.                         }
  331.                         break;
  332.                     case 'span':
  333.                         if (target.is('.month')) {
  334.                             var month = target.parent().find('span').index(target);
  335.                             this.viewDate.setMonth(month);
  336.                         } else {
  337.                             var year = parseInt(target.text(), 10) || 0;
  338.                             this.viewDate.setFullYear(year);
  339.                         }
  340.                         if (this.viewMode !== 0) {
  341.                             this.date = new Date(this.viewDate);
  342.                             this.element.trigger({
  343.                                 type: 'changeDate',
  344.                                 date: this.date,
  345.                                 viewMode: DPGlobal.modes[this.viewMode].clsName
  346.                             });
  347.                         }
  348.                         this.showMode(-1);
  349.                         this.fill();
  350.                         this.set();
  351.                         break;
  352.                     case 'td':
  353.                         if (target.is('.day') && !target.is('.disabled')) {
  354.                             var day = parseInt(target.text(), 10) || 1;
  355.                             var month = this.viewDate.getMonth();
  356.                             if (target.is('.old')) {
  357.                                 month -= 1;
  358.                             } else if (target.is('.new')) {
  359.                                 month += 1;
  360.                             }
  361.                             var year = this.viewDate.getFullYear();
  362.                             this.date = new Date(year, month, day, 0, 0, 0, 0);
  363.                             this.viewDate = new Date(year, month, Math.min(28, day), 0, 0, 0, 0);
  364.                             this.fill();
  365.                             this.set();
  366.                             this.element.trigger({
  367.                                 type: 'changeDate',
  368.                                 date: this.date,
  369.                                 viewMode: DPGlobal.modes[this.viewMode].clsName
  370.                             });
  371.                         }
  372.                         break;
  373.                 }
  374.             }
  375.         },
  376.  
  377.         mousedown: function (e) {
  378.             e.stopPropagation();
  379.             e.preventDefault();
  380.         },
  381.  
  382.         showMode: function (dir) {
  383.             if (dir) {
  384.                 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
  385.             }
  386.             this.picker.find('>div').hide().filter('.datepicker-' + DPGlobal.modes[this.viewMode].clsName).show();
  387.         }
  388.     };
  389.  
  390.     $.fn.datepicker = function (option, val) {
  391.         return this.each(function () {
  392.             var $this = $(this),
  393.                 data = $this.data('datepicker'),
  394.                 options = typeof option === 'object' && option;
  395.             if (!data) {
  396.                 $this.data('datepicker', (data = new Datepicker(this, $.extend({}, $.fn.datepicker.defaults, options))));
  397.             }
  398.             if (typeof option === 'string') data[option](val);
  399.         });
  400.     };
  401.  
  402.     $.fn.datepicker.defaults = {
  403.         onRender: function (date) {
  404.             return '';
  405.         }
  406.     };
  407.     $.fn.datepicker.Constructor = Datepicker;
  408.  
  409.     var DPGlobal = {
  410.         modes: [
  411.             {
  412.                 clsName: 'days',
  413.                 navFnc: 'Month',
  414.                 navStep: 1
  415.             },
  416.             {
  417.                 clsName: 'months',
  418.                 navFnc: 'FullYear',
  419.                 navStep: 1
  420.             },
  421.             {
  422.                 clsName: 'years',
  423.                 navFnc: 'FullYear',
  424.                 navStep: 10
  425.             }],
  426.         dates: {
  427.             days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
  428.             daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
  429.             daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
  430.             months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
  431.             monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
  432.         },
  433.         isLeapYear: function (year) {
  434.             return (((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0))
  435.         },
  436.         getDaysInMonth: function (year, month) {
  437.             return [31, (DPGlobal.isLeapYear(year) ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month]
  438.         },
  439.         parseFormat: function (format) {
  440.             var separator = format.match(/[.\/\-\s].*?/),
  441.                 parts = format.split(/\W+/);
  442.             if (!separator || !parts || parts.length === 0) {
  443.                 throw new Error("Invalid date format.");
  444.             }
  445.             return { separator: separator, parts: parts };
  446.         },
  447.         parseDate: function (date, format) {
  448.             var parts = date.split(format.separator),
  449.                 date = new Date(),
  450.                 val;
  451.             date.setHours(0);
  452.             date.setMinutes(0);
  453.             date.setSeconds(0);
  454.             date.setMilliseconds(0);
  455.             if (parts.length === format.parts.length) {
  456.                 var year = date.getFullYear(), day = date.getDate(), month = date.getMonth();
  457.                 for (var i = 0, cnt = format.parts.length; i < cnt; i++) {
  458.                     val = parseInt(parts[i], 10) || 1;
  459.                     switch (format.parts[i]) {
  460.                         case 'dd':
  461.                         case 'd':
  462.                             day = val;
  463.                             date.setDate(val);
  464.                             break;
  465.                         case 'mm':
  466.                         case 'm':
  467.                             month = val - 1;
  468.                             date.setMonth(val - 1);
  469.                             break;
  470.                         case 'yy':
  471.                             year = 2000 + val;
  472.                             date.setFullYear(2000 + val);
  473.                             break;
  474.                         case 'yyyy':
  475.                             year = val;
  476.                             date.setFullYear(val);
  477.                             break;
  478.                     }
  479.                 }
  480.                 date = new Date(year, month, day, 0, 0, 0);
  481.             }
  482.             return date;
  483.         },
  484.         formatDate: function (date, format) {
  485.             var val = {
  486.                 d: date.getDate(),
  487.                 m: date.getMonth() + 1,
  488.                 yy: date.getFullYear().toString().substring(2),
  489.                 yyyy: date.getFullYear()
  490.             };
  491.             val.dd = (val.d < 10 ? '0' : '') + val.d;
  492.             val.mm = (val.m < 10 ? '0' : '') + val.m;
  493.             var date = [];
  494.             for (var i = 0, cnt = format.parts.length; i < cnt; i++) {
  495.                 date.push(val[format.parts[i]]);
  496.             }
  497.             return date.join(format.separator);
  498.         },
  499.         headTemplate: '<thead>' +
  500.                             '<tr>' +
  501.                                 '<th class="prev">&lsaquo;</th>' +
  502.                                 '<th colspan="5" class="switch"></th>' +
  503.                                 '<th class="next">&rsaquo;</th>' +
  504.                             '</tr>' +
  505.                         '</thead>',
  506.         contTemplate: '<tbody><tr><td colspan="7"></td></tr></tbody>',
  507.         headTemplateW: '<thead>' +
  508.                             '<tr>' +
  509.                                 '<th class="prev"><i class="icon-arrow-left"/></th>' +
  510.                                 '<th colspan="6" class="switch"></th>' +
  511.                                 '<th class="next"><i class="icon-arrow-right"/></th>' +
  512.                             '</tr>' +
  513.                         '</thead>',
  514.         contTemplateW: '<tbody><tr><td colspan="8"></td></tr></tbody>'
  515.     };
  516.     DPGlobal.template = '<div class="datepicker dropdown-menu">' +
  517.                             '<div class="datepicker-days">' +
  518.                                 '<table class=" table-condensed">' +
  519.                                     DPGlobal.headTemplate +
  520.                                     '<tbody></tbody>' +
  521.                                 '</table>' +
  522.                             '</div>' +
  523.                             '<div class="datepicker-months">' +
  524.                                 '<table class="table-condensed">' +
  525.                                     DPGlobal.headTemplate +
  526.                                     DPGlobal.contTemplate +
  527.                                 '</table>' +
  528.                             '</div>' +
  529.                             '<div class="datepicker-years">' +
  530.                                 '<table class="table-condensed">' +
  531.                                     DPGlobal.headTemplate +
  532.                                     DPGlobal.contTemplate +
  533.                                 '</table>' +
  534.                             '</div>' +
  535.                         '</div>';
  536.     DPGlobal.templateW = '<div class="datepicker dropdown-menu">' +
  537.                             '<div class="datepicker-days">' +
  538.                                 '<table class=" table-condensed">' +
  539.                                     DPGlobal.headTemplateW +
  540.                                     '<tbody></tbody>' +
  541.                                 '</table>' +
  542.                             '</div>' +
  543.                             '<div class="datepicker-months">' +
  544.                                 '<table class="table-condensed">' +
  545.                                     DPGlobal.headTemplateW +
  546.                                     DPGlobal.contTemplateW +
  547.                                 '</table>' +
  548.                             '</div>' +
  549.                             '<div class="datepicker-years">' +
  550.                                 '<table class="table-condensed">' +
  551.                                     DPGlobal.headTemplateW +
  552.                                     DPGlobal.contTemplateW +
  553.                                 '</table>' +
  554.                             '</div>' +
  555.                         '</div>';
  556.  
  557. }(window.jQuery);
Add Comment
Please, Sign In to add comment