bf627c91eb27bb366ffeeccd0e7eb6e7846bcca1
[bootswatch] / material-kit / js / bootstrap-datepicker.js
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  var color = '';
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                 this.picker = $(DPGlobal.template)
28                                                         .appendTo('body')
29                                                         .on({
30                                                                 click: $.proxy(this.click, this)//,
31                                                                 //mousedown: $.proxy(this.mousedown, this)
32                                                         });
33                 this.isInput = this.element.is('input');
34                 this.component = this.element.is('.date') ? this.element.find('.add-on') : false;
35                 
36                 if (this.isInput) {
37                         this.element.on({
38                                 focus: $.proxy(this.show, this),
39                                 //blur: $.proxy(this.hide, this),
40                                 keyup: $.proxy(this.update, this)
41                         });
42                 } else {
43                         if (this.component){
44                                 this.component.on('click', $.proxy(this.show, this));
45                         } else {
46                                 this.element.on('click', $.proxy(this.show, this));
47                         }
48                 }
49         
50                 this.minViewMode = options.minViewMode||this.element.data('date-minviewmode')||0;
51                 if (typeof this.minViewMode === 'string') {
52                         switch (this.minViewMode) {
53                                 case 'months':
54                                         this.minViewMode = 1;
55                                         break;
56                                 case 'years':
57                                         this.minViewMode = 2;
58                                         break;
59                                 default:
60                                         this.minViewMode = 0;
61                                         break;
62                         }
63                 }
64                 this.viewMode = options.viewMode||this.element.data('date-viewmode')||0;
65                 if (typeof this.viewMode === 'string') {
66                         switch (this.viewMode) {
67                                 case 'months':
68                                         this.viewMode = 1;
69                                         break;
70                                 case 'years':
71                                         this.viewMode = 2;
72                                         break;
73                                 default:
74                                         this.viewMode = 0;
75                                         break;
76                         }
77                 }
78                 this.color = options.color||'azure';
79                 this.startViewMode = this.viewMode;
80                 this.weekStart = options.weekStart||this.element.data('date-weekstart')||0;
81                 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
82                 this.onRender = options.onRender;
83                 this.fillDow();
84                 this.fillMonths();
85                 this.update();
86                 this.showMode();
87                 
88         };
89         
90         
91         
92         Datepicker.prototype = {
93                 constructor: Datepicker,
94                 
95                 show: function(e) {
96                     var datepicker = this.picker;
97
98                         this.picker.show();
99                         this.height = this.component ? this.component.outerHeight() : this.element.outerHeight();
100                         this.place();
101                         $(window).on('resize', $.proxy(this.place, this));
102                         if (e ) {
103                                 e.stopPropagation();
104                                 e.preventDefault();
105                         }
106                         if (!this.isInput) {
107                         }
108                         var that = this;
109                         $(document).on('mousedown', function(ev){
110                                 if ($(ev.target).closest('.datepicker').length == 0) {
111                                         that.hide();
112                                 }
113                         });
114                         this.element.trigger({
115                                 type: 'show',
116                                 date: this.date
117                         });
118                         
119                         setTimeout(function(){
120                         datepicker.addClass('open');
121                         }, 170);
122                 },
123                 
124                 hide: function(){
125                         var datepicker = this.picker;
126                         datepicker.removeClass('open');
127                         
128                         setTimeout(function(){
129                         this.picker.hide();
130                         }, 500);
131                         
132                         $(window).off('resize', this.place);
133                         this.viewMode = this.startViewMode;
134                         this.showMode();
135                         if (!this.isInput) {
136                                 $(document).off('mousedown', this.hide);
137                         }
138                         //this.set();
139                         this.element.trigger({
140                                 type: 'hide',
141                                 date: this.date
142                         });
143                         
144         },
145                 
146                 set: function() {
147                         var formated = DPGlobal.formatDate(this.date, this.format);
148                         console.log(formated);
149                         if (!this.isInput) {
150                                 if (this.component){
151                                         this.element.find('input').prop('value', formated);
152                                 }
153                                 this.element.data('date', formated);
154                         } else {
155                                 this.element.prop('value', formated);
156                         }
157                 },
158                 
159                 setValue: function(newDate) {
160                         if (typeof newDate === 'string') {
161                                 this.date = DPGlobal.parseDate(newDate, this.format);
162                         } else {
163                                 this.date = new Date(newDate);
164                         }
165                         this.set();
166                         this.viewDate = new Date(this.date.getFullYear(), this.date.getMonth(), 1, 0, 0, 0, 0);
167                         this.fill();
168                 },
169                 
170                 place: function(){
171                         var offset = this.component ? this.component.offset() : this.element.offset();
172                         this.picker.css({
173                                 top: offset.top + this.height,
174                                 left: offset.left
175                         });
176                 },
177                 
178                 update: function(newDate){
179                         this.date = DPGlobal.parseDate(
180                                 typeof newDate === 'string' ? newDate : (this.isInput ? this.element.prop('value') : this.element.data('date')),
181                                 this.format
182                         );
183                         this.viewDate = new Date(this.date.getFullYear(), this.date.getMonth(), 1, 0, 0, 0, 0);
184                         this.fill();
185                 },
186                 
187                 fillDow: function(){
188                         var dowCnt = this.weekStart;
189                         var html = '<tr>';
190                         while (dowCnt < this.weekStart + 7) {
191                                 html += '<th class="dow">'+DPGlobal.dates.daysMin[(dowCnt++)%7]+'</th>';
192                         }
193                         html += '</tr>';
194                         this.picker.find('.datepicker-days thead').append(html);
195                 },
196                 
197                 fillMonths: function(){
198                         var html = '';
199                         var i = 0
200                         while (i < 12) {
201                                 html += '<span class="month">'+DPGlobal.dates.monthsShort[i++]+'</span>';
202                         }
203                         this.picker.find('.datepicker-months td').append(html);
204                 },
205                 
206                 fill: function() {
207                         var d = new Date(this.viewDate),
208                                 year = d.getFullYear(),
209                                 month = d.getMonth(),
210                                 currentDate = this.date.valueOf();
211                         this.picker.find('.datepicker-days th:eq(1)')
212                                                 .text(DPGlobal.dates.months[month]+' '+year);
213                         var prevMonth = new Date(year, month-1, 28,0,0,0,0),
214                                 day = DPGlobal.getDaysInMonth(prevMonth.getFullYear(), prevMonth.getMonth());
215                         prevMonth.setDate(day);
216                         prevMonth.setDate(day - (prevMonth.getDay() - this.weekStart + 7)%7);
217                         var nextMonth = new Date(prevMonth);
218                         nextMonth.setDate(nextMonth.getDate() + 42);
219                         nextMonth = nextMonth.valueOf();
220                         var html = [];
221                         var clsName,
222                                 prevY,
223                                 prevM;
224                         while(prevMonth.valueOf() < nextMonth) {
225                                 if (prevMonth.getDay() === this.weekStart) {
226                                         html.push('<tr>');
227                                 }
228                                 clsName = this.onRender(prevMonth);
229                                 prevY = prevMonth.getFullYear();
230                                 prevM = prevMonth.getMonth();
231                                 if ((prevM < month &&  prevY === year) ||  prevY < year) {
232                                         clsName += ' old';
233                                 } else if ((prevM > month && prevY === year) || prevY > year) {
234                                         clsName += ' new';
235                                 }
236                                 if (prevMonth.valueOf() === currentDate) {
237                                         clsName += ' active ' + this.color;
238                                 }
239                                 html.push('<td class="day '+clsName+'"><p>'+prevMonth.getDate() + '</p></td>');
240                                 if (prevMonth.getDay() === this.weekEnd) {
241                                         html.push('</tr>');
242                                 }
243                                 prevMonth.setDate(prevMonth.getDate()+1);
244                         }
245                         this.picker.find('.datepicker-days tbody').empty().append(html.join(''));
246                         var currentYear = this.date.getFullYear();
247                         
248                         var months = this.picker.find('.datepicker-months')
249                                                 .find('th:eq(1)')
250                                                         .text(year)
251                                                         .end()
252                                                 .find('span').removeClass('active');
253                         if (currentYear === year) {
254                                 months.eq(this.date.getMonth()).addClass('active').addClass(this.color);
255                         }
256                         
257                         html = '';
258                         year = parseInt(year/10, 10) * 10;
259                         var yearCont = this.picker.find('.datepicker-years')
260                                                                 .find('th:eq(1)')
261                                                                         .text(year + '-' + (year + 9))
262                                                                         .end()
263                                                                 .find('td');
264                         year -= 1;
265                         for (var i = -1; i < 11; i++) {
266                                 html += '<span class="year'+(i === -1 || i === 10 ? ' old' : '')+(currentYear === year ? ' active ' : '')+ this.color + '">'+year+'</span>';
267                                 year += 1;
268                         }
269                         yearCont.html(html);
270                 },
271                 
272                 click: function(e) {
273                         e.stopPropagation();
274                         e.preventDefault();
275                         var target = $(e.target).closest('span, td, th');
276                         if (target.length === 1) {
277                                 switch(target[0].nodeName.toLowerCase()) {
278                                         case 'th':
279                                                 switch(target[0].className) {
280                                                         case 'switch-datepicker':
281                                                                 this.showMode(1);
282                                                                 break;
283                                                         case 'prev':
284                                                         case 'next':
285                                                                 this.viewDate['set'+DPGlobal.modes[this.viewMode].navFnc].call(
286                                                                         this.viewDate,
287                                                                         this.viewDate['get'+DPGlobal.modes[this.viewMode].navFnc].call(this.viewDate) + 
288                                                                         DPGlobal.modes[this.viewMode].navStep * (target[0].className === 'prev' ? -1 : 1)
289                                                                 );
290                                                                 this.fill();
291                                                                 this.set();
292                                                                 break;
293                                                 }
294                                                 break;
295                                         case 'span':
296                                                 if (target.is('.month')) {
297                                                         var month = target.parent().find('span').index(target);
298                                                         this.viewDate.setMonth(month);
299                                                 } else {
300                                                         var year = parseInt(target.text(), 10)||0;
301                                                         this.viewDate.setFullYear(year);
302                                                 }
303                                                 if (this.viewMode !== 0) {
304                                                         this.date = new Date(this.viewDate);
305                                                         this.element.trigger({
306                                                                 type: 'changeDate',
307                                                                 date: this.date,
308                                                                 viewMode: DPGlobal.modes[this.viewMode].clsName
309                                                         });
310                                                 }
311                                                 this.showMode(-1);
312                                                 this.fill();
313                                                 this.set();
314                                                 break;
315                                         case 'td':
316                                                 if (target.is('.day') && !target.is('.disabled')){
317                                                         var day = parseInt(target.text(), 10)||1;
318                                                         var month = this.viewDate.getMonth();
319                                                         if (target.is('.old')) {
320                                                                 month -= 1;
321                                                         } else if (target.is('.new')) {
322                                                                 month += 1;
323                                                         }
324                                                         var year = this.viewDate.getFullYear();
325                                                         this.date = new Date(year, month, day,0,0,0,0);
326                                                         this.viewDate = new Date(year, month, Math.min(28, day),0,0,0,0);
327                                                         this.fill();
328                                                         this.set();
329                                                         this.element.trigger({
330                                                                 type: 'changeDate',
331                                                                 date: this.date,
332                                                                 viewMode: DPGlobal.modes[this.viewMode].clsName
333                                                         });
334                                                 }
335                                                 break;
336                                 }
337                         }
338                 },
339                 
340                 mousedown: function(e){
341                         e.stopPropagation();
342                         e.preventDefault();
343                 },
344                 
345                 showMode: function(dir) {
346                         if (dir) {
347                                 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
348                         }
349                         this.picker.find('>div').hide().filter('.datepicker-'+DPGlobal.modes[this.viewMode].clsName).show();
350                 }
351         };
352         
353         $.fn.datepicker = function ( option, val ) {
354                 return this.each(function () {
355                         var $this = $(this),
356                                 data = $this.data('datepicker'),
357                                 options = typeof option === 'object' && option;
358                         if (!data) {
359                                 $this.data('datepicker', (data = new Datepicker(this, $.extend({}, $.fn.datepicker.defaults,options))));
360                         }
361                         if (typeof option === 'string') data[option](val);
362                 });
363         };
364
365         $.fn.datepicker.defaults = {
366                 onRender: function(date) {
367                         return '';
368                 }
369         };
370         $.fn.datepicker.Constructor = Datepicker;
371         
372         var DPGlobal = {
373                 modes: [
374                         {
375                                 clsName: 'days',
376                                 navFnc: 'Month',
377                                 navStep: 1
378                         },
379                         {
380                                 clsName: 'months',
381                                 navFnc: 'FullYear',
382                                 navStep: 1
383                         },
384                         {
385                                 clsName: 'years',
386                                 navFnc: 'FullYear',
387                                 navStep: 10
388                 }],
389                 dates:{
390                         days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
391                         daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
392                         daysMin: ["S", "M", "T", "W", "T", "F", "S", "S"],
393                         months: ["JAN.", "FEB.", "MAR.", "APR.", "MAY", "JUN.", "JUL.", "AUG.", "SEPT.", "OCT.", "NOV.", "DEC."],
394                         monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
395                 },
396                 isLeapYear: function (year) {
397                         return (((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0))
398                 },
399                 getDaysInMonth: function (year, month) {
400                         return [31, (DPGlobal.isLeapYear(year) ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month]
401                 },
402                 parseFormat: function(format){
403                         var separator = format.match(/[.\/\-\s].*?/),
404                                 parts = format.split(/\W+/);
405                         if (!separator || !parts || parts.length === 0){
406                                 throw new Error("Invalid date format.");
407                         }
408                         return {separator: separator, parts: parts};
409                 },
410                 parseDate: function(date, format) {
411                         var parts = date.split(format.separator),
412                                 date = new Date(),
413                                 val;
414                         date.setHours(0);
415                         date.setMinutes(0);
416                         date.setSeconds(0);
417                         date.setMilliseconds(0);
418                         if (parts.length === format.parts.length) {
419                                 var year = date.getFullYear(), day = date.getDate(), month = date.getMonth();
420                                 for (var i=0, cnt = format.parts.length; i < cnt; i++) {
421                                         val = parseInt(parts[i], 10)||1;
422                                         switch(format.parts[i]) {
423                                                 case 'dd':
424                                                 case 'd':
425                                                         day = val;
426                                                         date.setDate(val);
427                                                         break;
428                                                 case 'mm':
429                                                 case 'm':
430                                                         month = val - 1;
431                                                         date.setMonth(val - 1);
432                                                         break;
433                                                 case 'yy':
434                                                         year = 2000 + val;
435                                                         date.setFullYear(2000 + val);
436                                                         break;
437                                                 case 'yyyy':
438                                                         year = val;
439                                                         date.setFullYear(val);
440                                                         break;
441                                         }
442                                 }
443                                 date = new Date(year, month, day, 0 ,0 ,0);
444                         }
445                         return date;
446                 },
447                 formatDate: function(date, format){
448                         var val = {
449                                 d: date.getDate(),
450                                 m: date.getMonth() + 1,
451                                 yy: date.getFullYear().toString().substring(2),
452                                 yyyy: date.getFullYear()
453                         };
454                         val.dd = (val.d < 10 ? '0' : '') + val.d;
455                         val.mm = (val.m < 10 ? '0' : '') + val.m;
456                         var date = [];
457                         for (var i=0, cnt = format.parts.length; i < cnt; i++) {
458                                 date.push(val[format.parts[i]]);
459                         }
460                         return date.join(format.separator);
461                 },
462                 headTemplate: '<thead>'+
463                                                         '<tr>'+
464                                                                 '<th class="prev"><p>&lsaquo;</p></th>'+
465                                                                 '<th colspan="5" class="switch-datepicker"></th>'+
466                                                                 '<th class="next"><p>&rsaquo;</p></th>'+
467                                                         '</tr>'+
468                                                 '</thead>',
469                 contTemplate: '<tbody><tr><td colspan="7"></td></tr></tbody>'
470         };
471         
472         DPGlobal.template = '<div class="datepicker dropdown-menu">'+
473                                                         '<div class="datepicker-days">'+
474                                                                 '<table class=" table-condensed">'+
475                                                                         DPGlobal.headTemplate+
476                                                                         '<tbody></tbody>'+
477                                                                 '</table>'+
478                                                         '</div>'+
479                                                         '<div class="datepicker-months">'+
480                                                                 '<table class="table-condensed">'+
481                                                                         DPGlobal.headTemplate+
482                                                                         DPGlobal.contTemplate+
483                                                                 '</table>'+
484                                                         '</div>'+
485                                                         '<div class="datepicker-years">'+
486                                                                 '<table class="table-condensed">'+
487                                                                         DPGlobal.headTemplate+
488                                                                         DPGlobal.contTemplate+
489                                                                 '</table>'+
490                                                         '</div>'+
491                                                 '</div>';
492
493 }( window.jQuery );