text changes to registration mail content
[namibia] / public / js / vendor / bootstrap-datepicker.js
1 /* =========================================================
2  * bootstrap-datepicker.js
3  * http://www.eyecon.ro/bootstrap-datepicker
4  * =========================================================
5  * Copyright 2012 Stefan Petre
6  * Improvements by Andrew Rowls
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  * ========================================================= */
20
21 (function( $ ) {
22
23         var $window = $(window);
24
25         function UTCDate(){
26                 return new Date(Date.UTC.apply(Date, arguments));
27         }
28         function UTCToday(){
29                 var today = new Date();
30                 return UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
31         }
32
33
34         // Picker object
35
36         var Datepicker = function(element, options) {
37                 var that = this;
38
39                 this._process_options(options);
40
41                 this.element = $(element);
42                 this.isInline = false;
43                 this.isInput = this.element.is('input');
44                 this.component = this.element.is('.date') ? this.element.find('.add-on, .btn') : false;
45                 this.hasInput = this.component && this.element.find('input').length;
46                 if(this.component && this.component.length === 0)
47                         this.component = false;
48
49                 this.picker = $(DPGlobal.template);
50                 this._buildEvents();
51                 this._attachEvents();
52
53                 if(this.isInline) {
54                         this.picker.addClass('datepicker-inline').appendTo(this.element);
55                 } else {
56                         this.picker.addClass('datepicker-dropdown dropdown-menu');
57                 }
58
59                 if (this.o.rtl){
60                         this.picker.addClass('datepicker-rtl');
61                         this.picker.find('.prev i, .next i')
62                                                 .toggleClass('icon-arrow-left icon-arrow-right');
63                 }
64
65
66                 this.viewMode = this.o.startView;
67
68                 if (this.o.calendarWeeks)
69                         this.picker.find('tfoot th.today')
70                                                 .attr('colspan', function(i, val){
71                                                         return parseInt(val) + 1;
72                                                 });
73
74                 this._allow_update = false;
75
76                 this.setStartDate(this._o.startDate);
77                 this.setEndDate(this._o.endDate);
78                 this.setDaysOfWeekDisabled(this.o.daysOfWeekDisabled);
79
80                 this.fillDow();
81                 this.fillMonths();
82
83                 this._allow_update = true;
84
85                 this.update();
86                 this.showMode();
87
88                 if(this.isInline) {
89                         this.show();
90                 }
91         };
92
93         Datepicker.prototype = {
94                 constructor: Datepicker,
95
96                 _process_options: function(opts){
97                         // Store raw options for reference
98                         this._o = $.extend({}, this._o, opts);
99                         // Processed options
100                         var o = this.o = $.extend({}, this._o);
101
102                         // Check if "de-DE" style date is available, if not language should
103                         // fallback to 2 letter code eg "de"
104                         var lang = o.language;
105                         if (!dates[lang]) {
106                                 lang = lang.split('-')[0];
107                                 if (!dates[lang])
108                                         lang = defaults.language;
109                         }
110                         o.language = lang;
111
112                         switch(o.startView){
113                                 case 2:
114                                 case 'decade':
115                                         o.startView = 2;
116                                         break;
117                                 case 1:
118                                 case 'year':
119                                         o.startView = 1;
120                                         break;
121                                 default:
122                                         o.startView = 0;
123                         }
124
125                         switch (o.minViewMode) {
126                                 case 1:
127                                 case 'months':
128                                         o.minViewMode = 1;
129                                         break;
130                                 case 2:
131                                 case 'years':
132                                         o.minViewMode = 2;
133                                         break;
134                                 default:
135                                         o.minViewMode = 0;
136                         }
137
138                         o.startView = Math.max(o.startView, o.minViewMode);
139
140                         o.weekStart %= 7;
141                         o.weekEnd = ((o.weekStart + 6) % 7);
142
143                         var format = DPGlobal.parseFormat(o.format);
144                         if (o.startDate !== -Infinity) {
145                                 if (!!o.startDate) {
146                                         if (o.startDate instanceof Date)
147                                                 o.startDate = this._local_to_utc(this._zero_time(o.startDate));
148                                         else
149                                                 o.startDate = DPGlobal.parseDate(o.startDate, format, o.language);
150                                 } else {
151                                         o.startDate = -Infinity;
152                                 }
153                         }
154                         if (o.endDate !== Infinity) {
155                                 if (!!o.endDate) {
156                                         if (o.endDate instanceof Date)
157                                                 o.endDate = this._local_to_utc(this._zero_time(o.endDate));
158                                         else
159                                                 o.endDate = DPGlobal.parseDate(o.endDate, format, o.language);
160                                 } else {
161                                         o.endDate = Infinity;
162                                 }
163                         }
164
165                         o.daysOfWeekDisabled = o.daysOfWeekDisabled||[];
166                         if (!$.isArray(o.daysOfWeekDisabled))
167                                 o.daysOfWeekDisabled = o.daysOfWeekDisabled.split(/[,\s]*/);
168                         o.daysOfWeekDisabled = $.map(o.daysOfWeekDisabled, function (d) {
169                                 return parseInt(d, 10);
170                         });
171
172                         var plc = String(o.orientation).toLowerCase().split(/\s+/g),
173                                 _plc = o.orientation.toLowerCase();
174                         plc = $.grep(plc, function(word){
175                                 return (/^auto|left|right|top|bottom$/).test(word);
176                         });
177                         o.orientation = {x: 'auto', y: 'auto'};
178                         if (!_plc || _plc === 'auto')
179                                 ; // no action
180                         else if (plc.length === 1){
181                                 switch(plc[0]){
182                                         case 'top':
183                                         case 'bottom':
184                                                 o.orientation.y = plc[0];
185                                                 break;
186                                         case 'left':
187                                         case 'right':
188                                                 o.orientation.x = plc[0];
189                                                 break;
190                                 }
191                         }
192                         else {
193                                 _plc = $.grep(plc, function(word){
194                                         return (/^left|right$/).test(word);
195                                 });
196                                 o.orientation.x = _plc[0] || 'auto';
197
198                                 _plc = $.grep(plc, function(word){
199                                         return (/^top|bottom$/).test(word);
200                                 });
201                                 o.orientation.y = _plc[0] || 'auto';
202                         }
203                 },
204                 _events: [],
205                 _secondaryEvents: [],
206                 _applyEvents: function(evs){
207                         for (var i=0, el, ev; i<evs.length; i++){
208                                 el = evs[i][0];
209                                 ev = evs[i][1];
210                                 el.on(ev);
211                         }
212                 },
213                 _unapplyEvents: function(evs){
214                         for (var i=0, el, ev; i<evs.length; i++){
215                                 el = evs[i][0];
216                                 ev = evs[i][1];
217                                 el.off(ev);
218                         }
219                 },
220                 _buildEvents: function(){
221                         if (this.isInput) { // single input
222                                 this._events = [
223                                         [this.element, {
224                                                 focus: $.proxy(this.show, this),
225                                                 keyup: $.proxy(this.update, this),
226                                                 keydown: $.proxy(this.keydown, this)
227                                         }]
228                                 ];
229                         }
230                         else if (this.component && this.hasInput){ // component: input + button
231                                 this._events = [
232                                         // For components that are not readonly, allow keyboard nav
233                                         [this.element.find('input'), {
234                                                 focus: $.proxy(this.show, this),
235                                                 keyup: $.proxy(this.update, this),
236                                                 keydown: $.proxy(this.keydown, this)
237                                         }],
238                                         [this.component, {
239                                                 click: $.proxy(this.show, this)
240                                         }]
241                                 ];
242                         }
243                         else if (this.element.is('div')) {  // inline datepicker
244                                 this.isInline = true;
245                         }
246                         else {
247                                 this._events = [
248                                         [this.element, {
249                                                 click: $.proxy(this.show, this)
250                                         }]
251                                 ];
252                         }
253
254                         this._secondaryEvents = [
255                                 [this.picker, {
256                                         click: $.proxy(this.click, this)
257                                 }],
258                                 [$(window), {
259                                         resize: $.proxy(this.place, this)
260                                 }],
261                                 [$(document), {
262                                         'mousedown touchstart': $.proxy(function (e) {
263                                                 // Clicked outside the datepicker, hide it
264                                                 if (!(
265                                                         this.element.is(e.target) ||
266                                                         this.element.find(e.target).length ||
267                                                         this.picker.is(e.target) ||
268                                                         this.picker.find(e.target).length
269                                                 )) {
270                                                         this.hide();
271                                                 }
272                                         }, this)
273                                 }]
274                         ];
275                 },
276                 _attachEvents: function(){
277                         this._detachEvents();
278                         this._applyEvents(this._events);
279                 },
280                 _detachEvents: function(){
281                         this._unapplyEvents(this._events);
282                 },
283                 _attachSecondaryEvents: function(){
284                         this._detachSecondaryEvents();
285                         this._applyEvents(this._secondaryEvents);
286                 },
287                 _detachSecondaryEvents: function(){
288                         this._unapplyEvents(this._secondaryEvents);
289                 },
290                 _trigger: function(event, altdate){
291                         var date = altdate || this.date,
292                                 local_date = this._utc_to_local(date);
293
294                         this.element.trigger({
295                                 type: event,
296                                 date: local_date,
297                                 format: $.proxy(function(altformat){
298                                         var format = altformat || this.o.format;
299                                         return DPGlobal.formatDate(date, format, this.o.language);
300                                 }, this)
301                         });
302                 },
303
304                 show: function(e) {
305                         if (!this.isInline)
306                                 this.picker.appendTo('body');
307                         this.picker.show();
308                         this.height = this.component ? this.component.outerHeight() : this.element.outerHeight();
309                         this.place();
310                         this._attachSecondaryEvents();
311                         if (e) {
312                                 e.preventDefault();
313                         }
314                         this._trigger('show');
315                 },
316
317                 hide: function(e){
318                         if(this.isInline) return;
319                         if (!this.picker.is(':visible')) return;
320                         this.picker.hide().detach();
321                         this._detachSecondaryEvents();
322                         this.viewMode = this.o.startView;
323                         this.showMode();
324
325                         if (
326                                 this.o.forceParse &&
327                                 (
328                                         this.isInput && this.element.val() ||
329                                         this.hasInput && this.element.find('input').val()
330                                 )
331                         )
332                                 this.setValue();
333                         this._trigger('hide');
334                 },
335
336                 remove: function() {
337                         this.hide();
338                         this._detachEvents();
339                         this._detachSecondaryEvents();
340                         this.picker.remove();
341                         delete this.element.data().datepicker;
342                         if (!this.isInput) {
343                                 delete this.element.data().date;
344                         }
345                 },
346
347                 _utc_to_local: function(utc){
348                         return new Date(utc.getTime() + (utc.getTimezoneOffset()*60000));
349                 },
350                 _local_to_utc: function(local){
351                         return new Date(local.getTime() - (local.getTimezoneOffset()*60000));
352                 },
353                 _zero_time: function(local){
354                         return new Date(local.getFullYear(), local.getMonth(), local.getDate());
355                 },
356                 _zero_utc_time: function(utc){
357                         return new Date(Date.UTC(utc.getUTCFullYear(), utc.getUTCMonth(), utc.getUTCDate()));
358                 },
359
360                 getDate: function() {
361                         return this._utc_to_local(this.getUTCDate());
362                 },
363
364                 getUTCDate: function() {
365                         return this.date;
366                 },
367
368                 setDate: function(d) {
369                         this.setUTCDate(this._local_to_utc(d));
370                 },
371
372                 setUTCDate: function(d) {
373                         this.date = d;
374                         this.setValue();
375                 },
376
377                 setValue: function() {
378                         var formatted = this.getFormattedDate();
379                         if (!this.isInput) {
380                                 if (this.component){
381                                         this.element.find('input').val(formatted).change();
382                                 }
383                         } else {
384                                 this.element.val(formatted).change();
385                         }
386                 },
387
388                 getFormattedDate: function(format) {
389                         if (format === undefined)
390                                 format = this.o.format;
391                         return DPGlobal.formatDate(this.date, format, this.o.language);
392                 },
393
394                 setStartDate: function(startDate){
395                         this._process_options({startDate: startDate});
396                         this.update();
397                         this.updateNavArrows();
398                 },
399
400                 setEndDate: function(endDate){
401                         this._process_options({endDate: endDate});
402                         this.update();
403                         this.updateNavArrows();
404                 },
405
406                 setDaysOfWeekDisabled: function(daysOfWeekDisabled){
407                         this._process_options({daysOfWeekDisabled: daysOfWeekDisabled});
408                         this.update();
409                         this.updateNavArrows();
410                 },
411
412                 place: function(){
413                                                 if(this.isInline) return;
414                         var calendarWidth = this.picker.outerWidth(),
415                                 calendarHeight = this.picker.outerHeight(),
416                                 visualPadding = 10,
417                                 windowWidth = $window.width(),
418                                 windowHeight = $window.height(),
419                                 scrollTop = $window.scrollTop();
420
421                         var zIndex = parseInt(this.element.parents().filter(function() {
422                                                         return $(this).css('z-index') != 'auto';
423                                                 }).first().css('z-index'))+10;
424                         var offset = this.component ? this.component.parent().offset() : this.element.offset();
425                         var height = this.component ? this.component.outerHeight(true) : this.element.outerHeight(false);
426                         var width = this.component ? this.component.outerWidth(true) : this.element.outerWidth(false);
427                         var left = offset.left,
428                                 top = offset.top;
429
430                         this.picker.removeClass(
431                                 'datepicker-orient-top datepicker-orient-bottom '+
432                                 'datepicker-orient-right datepicker-orient-left'
433                         );
434
435                         if (this.o.orientation.x !== 'auto') {
436                                 this.picker.addClass('datepicker-orient-' + this.o.orientation.x);
437                                 if (this.o.orientation.x === 'right')
438                                         left -= calendarWidth - width;
439                         }
440                         // auto x orientation is best-placement: if it crosses a window
441                         // edge, fudge it sideways
442                         else {
443                                 // Default to left
444                                 this.picker.addClass('datepicker-orient-left');
445                                 if (offset.left < 0)
446                                         left -= offset.left - visualPadding;
447                                 else if (offset.left + calendarWidth > windowWidth)
448                                         left = windowWidth - calendarWidth - visualPadding;
449                         }
450
451                         // auto y orientation is best-situation: top or bottom, no fudging,
452                         // decision based on which shows more of the calendar
453                         var yorient = this.o.orientation.y,
454                                 top_overflow, bottom_overflow;
455                         if (yorient === 'auto') {
456                                 top_overflow = -scrollTop + offset.top - calendarHeight;
457                                 bottom_overflow = scrollTop + windowHeight - (offset.top + height + calendarHeight);
458                                 if (Math.max(top_overflow, bottom_overflow) === bottom_overflow)
459                                         yorient = 'top';
460                                 else
461                                         yorient = 'bottom';
462                         }
463                         this.picker.addClass('datepicker-orient-' + yorient);
464                         if (yorient === 'top')
465                                 top += height;
466                         else
467                                 top -= calendarHeight + parseInt(this.picker.css('padding-top'));
468
469                         this.picker.css({
470                                 top: top,
471                                 left: left,
472                                 zIndex: zIndex
473                         });
474                 },
475
476                 _allow_update: true,
477                 update: function(){
478                         if (!this._allow_update) return;
479
480                         var oldDate = new Date(this.date),
481                                 date, fromArgs = false;
482                         if(arguments && arguments.length && (typeof arguments[0] === 'string' || arguments[0] instanceof Date)) {
483                                 date = arguments[0];
484                                 if (date instanceof Date)
485                                         date = this._local_to_utc(date);
486                                 fromArgs = true;
487                         } else {
488                                 date = this.isInput ? this.element.val() : this.element.data('date') || this.element.find('input').val();
489                                 delete this.element.data().date;
490                         }
491
492                         this.date = DPGlobal.parseDate(date, this.o.format, this.o.language);
493
494                         if (fromArgs) {
495                                 // setting date by clicking
496                                 this.setValue();
497                         } else if (date) {
498                                 // setting date by typing
499                                 if (oldDate.getTime() !== this.date.getTime())
500                                         this._trigger('changeDate');
501                         } else {
502                                 // clearing date
503                                 this._trigger('clearDate');
504                         }
505
506                         if (this.date < this.o.startDate) {
507                                 this.viewDate = new Date(this.o.startDate);
508                                 this.date = new Date(this.o.startDate);
509                         } else if (this.date > this.o.endDate) {
510                                 this.viewDate = new Date(this.o.endDate);
511                                 this.date = new Date(this.o.endDate);
512                         } else {
513                                 this.viewDate = new Date(this.date);
514                                 this.date = new Date(this.date);
515                         }
516                         this.fill();
517                 },
518
519                 fillDow: function(){
520                         var dowCnt = this.o.weekStart,
521                         html = '<tr>';
522                         if(this.o.calendarWeeks){
523                                 var cell = '<th class="cw">&nbsp;</th>';
524                                 html += cell;
525                                 this.picker.find('.datepicker-days thead tr:first-child').prepend(cell);
526                         }
527                         while (dowCnt < this.o.weekStart + 7) {
528                                 html += '<th class="dow">'+dates[this.o.language].daysMin[(dowCnt++)%7]+'</th>';
529                         }
530                         html += '</tr>';
531                         this.picker.find('.datepicker-days thead').append(html);
532                 },
533
534                 fillMonths: function(){
535                         var html = '',
536                         i = 0;
537                         while (i < 12) {
538                                 html += '<span class="month">'+dates[this.o.language].monthsShort[i++]+'</span>';
539                         }
540                         this.picker.find('.datepicker-months td').html(html);
541                 },
542
543                 setRange: function(range){
544                         if (!range || !range.length)
545                                 delete this.range;
546                         else
547                                 this.range = $.map(range, function(d){ return d.valueOf(); });
548                         this.fill();
549                 },
550
551                 getClassNames: function(date){
552                         var cls = [],
553                                 year = this.viewDate.getUTCFullYear(),
554                                 month = this.viewDate.getUTCMonth(),
555                                 currentDate = this.date.valueOf(),
556                                 today = new Date();
557                         if (date.getUTCFullYear() < year || (date.getUTCFullYear() == year && date.getUTCMonth() < month)) {
558                                 cls.push('old');
559                         } else if (date.getUTCFullYear() > year || (date.getUTCFullYear() == year && date.getUTCMonth() > month)) {
560                                 cls.push('new');
561                         }
562                         // Compare internal UTC date with local today, not UTC today
563                         if (this.o.todayHighlight &&
564                                 date.getUTCFullYear() == today.getFullYear() &&
565                                 date.getUTCMonth() == today.getMonth() &&
566                                 date.getUTCDate() == today.getDate()) {
567                                 cls.push('today');
568                         }
569                         if (date.valueOf() == currentDate) {
570                                 cls.push('active');
571                         }
572                         if (date.valueOf() < this.o.startDate || date.valueOf() > this.o.endDate ||
573                                 $.inArray(date.getUTCDay(), this.o.daysOfWeekDisabled) !== -1) {
574                                 cls.push('disabled');
575                         }
576                         if (this.range){
577                                 if (date > this.range[0] && date < this.range[this.range.length-1]){
578                                         cls.push('range');
579                                 }
580                                 if ($.inArray(date.valueOf(), this.range) != -1){
581                                         cls.push('selected');
582                                 }
583                         }
584                         return cls;
585                 },
586
587                 fill: function() {
588                         var d = new Date(this.viewDate),
589                                 year = d.getUTCFullYear(),
590                                 month = d.getUTCMonth(),
591                                 startYear = this.o.startDate !== -Infinity ? this.o.startDate.getUTCFullYear() : -Infinity,
592                                 startMonth = this.o.startDate !== -Infinity ? this.o.startDate.getUTCMonth() : -Infinity,
593                                 endYear = this.o.endDate !== Infinity ? this.o.endDate.getUTCFullYear() : Infinity,
594                                 endMonth = this.o.endDate !== Infinity ? this.o.endDate.getUTCMonth() : Infinity,
595                                 currentDate = this.date && this.date.valueOf(),
596                                 tooltip;
597                         this.picker.find('.datepicker-days thead th.datepicker-switch')
598                                                 .text(dates[this.o.language].months[month]+' '+year);
599                         this.picker.find('tfoot th.today')
600                                                 .text(dates[this.o.language].today)
601                                                 .toggle(this.o.todayBtn !== false);
602                         this.picker.find('tfoot th.clear')
603                                                 .text(dates[this.o.language].clear)
604                                                 .toggle(this.o.clearBtn !== false);
605                         this.updateNavArrows();
606                         this.fillMonths();
607                         var prevMonth = UTCDate(year, month-1, 28,0,0,0,0),
608                                 day = DPGlobal.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
609                         prevMonth.setUTCDate(day);
610                         prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.o.weekStart + 7)%7);
611                         var nextMonth = new Date(prevMonth);
612                         nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
613                         nextMonth = nextMonth.valueOf();
614                         var html = [];
615                         var clsName;
616                         while(prevMonth.valueOf() < nextMonth) {
617                                 if (prevMonth.getUTCDay() == this.o.weekStart) {
618                                         html.push('<tr>');
619                                         if(this.o.calendarWeeks){
620                                                 // ISO 8601: First week contains first thursday.
621                                                 // ISO also states week starts on Monday, but we can be more abstract here.
622                                                 var
623                                                         // Start of current week: based on weekstart/current date
624                                                         ws = new Date(+prevMonth + (this.o.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
625                                                         // Thursday of this week
626                                                         th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
627                                                         // First Thursday of year, year from thursday
628                                                         yth = new Date(+(yth = UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
629                                                         // Calendar week: ms between thursdays, div ms per day, div 7 days
630                                                         calWeek =  (th - yth) / 864e5 / 7 + 1;
631                                                 html.push('<td class="cw">'+ calWeek +'</td>');
632
633                                         }
634                                 }
635                                 clsName = this.getClassNames(prevMonth);
636                                 clsName.push('day');
637
638                                 if (this.o.beforeShowDay !== $.noop){
639                                         var before = this.o.beforeShowDay(this._utc_to_local(prevMonth));
640                                         if (before === undefined)
641                                                 before = {};
642                                         else if (typeof(before) === 'boolean')
643                                                 before = {enabled: before};
644                                         else if (typeof(before) === 'string')
645                                                 before = {classes: before};
646                                         if (before.enabled === false)
647                                                 clsName.push('disabled');
648                                         if (before.classes)
649                                                 clsName = clsName.concat(before.classes.split(/\s+/));
650                                         if (before.tooltip)
651                                                 tooltip = before.tooltip;
652                                 }
653
654                                 clsName = $.unique(clsName);
655                                 html.push('<td class="'+clsName.join(' ')+'"' + (tooltip ? ' title="'+tooltip+'"' : '') + '>'+prevMonth.getUTCDate() + '</td>');
656                                 if (prevMonth.getUTCDay() == this.o.weekEnd) {
657                                         html.push('</tr>');
658                                 }
659                                 prevMonth.setUTCDate(prevMonth.getUTCDate()+1);
660                         }
661                         this.picker.find('.datepicker-days tbody').empty().append(html.join(''));
662                         var currentYear = this.date && this.date.getUTCFullYear();
663
664                         var months = this.picker.find('.datepicker-months')
665                                                 .find('th:eq(1)')
666                                                         .text(year)
667                                                         .end()
668                                                 .find('span').removeClass('active');
669                         if (currentYear && currentYear == year) {
670                                 months.eq(this.date.getUTCMonth()).addClass('active');
671                         }
672                         if (year < startYear || year > endYear) {
673                                 months.addClass('disabled');
674                         }
675                         if (year == startYear) {
676                                 months.slice(0, startMonth).addClass('disabled');
677                         }
678                         if (year == endYear) {
679                                 months.slice(endMonth+1).addClass('disabled');
680                         }
681
682                         html = '';
683                         year = parseInt(year/10, 10) * 10;
684                         var yearCont = this.picker.find('.datepicker-years')
685                                                                 .find('th:eq(1)')
686                                                                         .text(year + '-' + (year + 9))
687                                                                         .end()
688                                                                 .find('td');
689                         year -= 1;
690                         for (var i = -1; i < 11; i++) {
691                                 html += '<span class="year'+(i == -1 ? ' old' : i == 10 ? ' new' : '')+(currentYear == year ? ' active' : '')+(year < startYear || year > endYear ? ' disabled' : '')+'">'+year+'</span>';
692                                 year += 1;
693                         }
694                         yearCont.html(html);
695                 },
696
697                 updateNavArrows: function() {
698                         if (!this._allow_update) return;
699
700                         var d = new Date(this.viewDate),
701                                 year = d.getUTCFullYear(),
702                                 month = d.getUTCMonth();
703                         switch (this.viewMode) {
704                                 case 0:
705                                         if (this.o.startDate !== -Infinity && year <= this.o.startDate.getUTCFullYear() && month <= this.o.startDate.getUTCMonth()) {
706                                                 this.picker.find('.prev').css({visibility: 'hidden'});
707                                         } else {
708                                                 this.picker.find('.prev').css({visibility: 'visible'});
709                                         }
710                                         if (this.o.endDate !== Infinity && year >= this.o.endDate.getUTCFullYear() && month >= this.o.endDate.getUTCMonth()) {
711                                                 this.picker.find('.next').css({visibility: 'hidden'});
712                                         } else {
713                                                 this.picker.find('.next').css({visibility: 'visible'});
714                                         }
715                                         break;
716                                 case 1:
717                                 case 2:
718                                         if (this.o.startDate !== -Infinity && year <= this.o.startDate.getUTCFullYear()) {
719                                                 this.picker.find('.prev').css({visibility: 'hidden'});
720                                         } else {
721                                                 this.picker.find('.prev').css({visibility: 'visible'});
722                                         }
723                                         if (this.o.endDate !== Infinity && year >= this.o.endDate.getUTCFullYear()) {
724                                                 this.picker.find('.next').css({visibility: 'hidden'});
725                                         } else {
726                                                 this.picker.find('.next').css({visibility: 'visible'});
727                                         }
728                                         break;
729                         }
730                 },
731
732                 click: function(e) {
733                         e.preventDefault();
734                         var target = $(e.target).closest('span, td, th');
735                         if (target.length == 1) {
736                                 switch(target[0].nodeName.toLowerCase()) {
737                                         case 'th':
738                                                 switch(target[0].className) {
739                                                         case 'datepicker-switch':
740                                                                 this.showMode(1);
741                                                                 break;
742                                                         case 'prev':
743                                                         case 'next':
744                                                                 var dir = DPGlobal.modes[this.viewMode].navStep * (target[0].className == 'prev' ? -1 : 1);
745                                                                 switch(this.viewMode){
746                                                                         case 0:
747                                                                                 this.viewDate = this.moveMonth(this.viewDate, dir);
748                                                                                 this._trigger('changeMonth', this.viewDate);
749                                                                                 break;
750                                                                         case 1:
751                                                                         case 2:
752                                                                                 this.viewDate = this.moveYear(this.viewDate, dir);
753                                                                                 if (this.viewMode === 1)
754                                                                                         this._trigger('changeYear', this.viewDate);
755                                                                                 break;
756                                                                 }
757                                                                 this.fill();
758                                                                 break;
759                                                         case 'today':
760                                                                 var date = new Date();
761                                                                 date = UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
762
763                                                                 this.showMode(-2);
764                                                                 var which = this.o.todayBtn == 'linked' ? null : 'view';
765                                                                 this._setDate(date, which);
766                                                                 break;
767                                                         case 'clear':
768                                                                 var element;
769                                                                 if (this.isInput)
770                                                                         element = this.element;
771                                                                 else if (this.component)
772                                                                         element = this.element.find('input');
773                                                                 if (element)
774                                                                         element.val("").change();
775                                                                 this._trigger('changeDate');
776                                                                 this.update();
777                                                                 if (this.o.autoclose)
778                                                                         this.hide();
779                                                                 break;
780                                                 }
781                                                 break;
782                                         case 'span':
783                                                 if (!target.is('.disabled')) {
784                                                         this.viewDate.setUTCDate(1);
785                                                         if (target.is('.month')) {
786                                                                 var day = 1;
787                                                                 var month = target.parent().find('span').index(target);
788                                                                 var year = this.viewDate.getUTCFullYear();
789                                                                 this.viewDate.setUTCMonth(month);
790                                                                 this._trigger('changeMonth', this.viewDate);
791                                                                 if (this.o.minViewMode === 1) {
792                                                                         this._setDate(UTCDate(year, month, day,0,0,0,0));
793                                                                 }
794                                                         } else {
795                                                                 var year = parseInt(target.text(), 10)||0;
796                                                                 var day = 1;
797                                                                 var month = 0;
798                                                                 this.viewDate.setUTCFullYear(year);
799                                                                 this._trigger('changeYear', this.viewDate);
800                                                                 if (this.o.minViewMode === 2) {
801                                                                         this._setDate(UTCDate(year, month, day,0,0,0,0));
802                                                                 }
803                                                         }
804                                                         this.showMode(-1);
805                                                         this.fill();
806                                                 }
807                                                 break;
808                                         case 'td':
809                                                 if (target.is('.day') && !target.is('.disabled')){
810                                                         var day = parseInt(target.text(), 10)||1;
811                                                         var year = this.viewDate.getUTCFullYear(),
812                                                                 month = this.viewDate.getUTCMonth();
813                                                         if (target.is('.old')) {
814                                                                 if (month === 0) {
815                                                                         month = 11;
816                                                                         year -= 1;
817                                                                 } else {
818                                                                         month -= 1;
819                                                                 }
820                                                         } else if (target.is('.new')) {
821                                                                 if (month == 11) {
822                                                                         month = 0;
823                                                                         year += 1;
824                                                                 } else {
825                                                                         month += 1;
826                                                                 }
827                                                         }
828                                                         this._setDate(UTCDate(year, month, day,0,0,0,0));
829                                                 }
830                                                 break;
831                                 }
832                         }
833                 },
834
835                 _setDate: function(date, which){
836                         if (!which || which == 'date')
837                                 this.date = new Date(date);
838                         if (!which || which  == 'view')
839                                 this.viewDate = new Date(date);
840                         this.fill();
841                         this.setValue();
842                         this._trigger('changeDate');
843                         var element;
844                         if (this.isInput) {
845                                 element = this.element;
846                         } else if (this.component){
847                                 element = this.element.find('input');
848                         }
849                         if (element) {
850                                 element.change();
851                         }
852                         if (this.o.autoclose && (!which || which == 'date')) {
853                                 this.hide();
854                         }
855                 },
856
857                 moveMonth: function(date, dir){
858                         if (!dir) return date;
859                         var new_date = new Date(date.valueOf()),
860                                 day = new_date.getUTCDate(),
861                                 month = new_date.getUTCMonth(),
862                                 mag = Math.abs(dir),
863                                 new_month, test;
864                         dir = dir > 0 ? 1 : -1;
865                         if (mag == 1){
866                                 test = dir == -1
867                                         // If going back one month, make sure month is not current month
868                                         // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
869                                         ? function(){ return new_date.getUTCMonth() == month; }
870                                         // If going forward one month, make sure month is as expected
871                                         // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
872                                         : function(){ return new_date.getUTCMonth() != new_month; };
873                                 new_month = month + dir;
874                                 new_date.setUTCMonth(new_month);
875                                 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
876                                 if (new_month < 0 || new_month > 11)
877                                         new_month = (new_month + 12) % 12;
878                         } else {
879                                 // For magnitudes >1, move one month at a time...
880                                 for (var i=0; i<mag; i++)
881                                         // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
882                                         new_date = this.moveMonth(new_date, dir);
883                                 // ...then reset the day, keeping it in the new month
884                                 new_month = new_date.getUTCMonth();
885                                 new_date.setUTCDate(day);
886                                 test = function(){ return new_month != new_date.getUTCMonth(); };
887                         }
888                         // Common date-resetting loop -- if date is beyond end of month, make it
889                         // end of month
890                         while (test()){
891                                 new_date.setUTCDate(--day);
892                                 new_date.setUTCMonth(new_month);
893                         }
894                         return new_date;
895                 },
896
897                 moveYear: function(date, dir){
898                         return this.moveMonth(date, dir*12);
899                 },
900
901                 dateWithinRange: function(date){
902                         return date >= this.o.startDate && date <= this.o.endDate;
903                 },
904
905                 keydown: function(e){
906                         if (this.picker.is(':not(:visible)')){
907                                 if (e.keyCode == 27) // allow escape to hide and re-show picker
908                                         this.show();
909                                 return;
910                         }
911                         var dateChanged = false,
912                                 dir, day, month,
913                                 newDate, newViewDate;
914                         switch(e.keyCode){
915                                 case 27: // escape
916                                         this.hide();
917                                         e.preventDefault();
918                                         break;
919                                 case 37: // left
920                                 case 39: // right
921                                         if (!this.o.keyboardNavigation) break;
922                                         dir = e.keyCode == 37 ? -1 : 1;
923                                         if (e.ctrlKey){
924                                                 newDate = this.moveYear(this.date, dir);
925                                                 newViewDate = this.moveYear(this.viewDate, dir);
926                                                 this._trigger('changeYear', this.viewDate);
927                                         } else if (e.shiftKey){
928                                                 newDate = this.moveMonth(this.date, dir);
929                                                 newViewDate = this.moveMonth(this.viewDate, dir);
930                                                 this._trigger('changeMonth', this.viewDate);
931                                         } else {
932                                                 newDate = new Date(this.date);
933                                                 newDate.setUTCDate(this.date.getUTCDate() + dir);
934                                                 newViewDate = new Date(this.viewDate);
935                                                 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
936                                         }
937                                         if (this.dateWithinRange(newDate)){
938                                                 this.date = newDate;
939                                                 this.viewDate = newViewDate;
940                                                 this.setValue();
941                                                 this.update();
942                                                 e.preventDefault();
943                                                 dateChanged = true;
944                                         }
945                                         break;
946                                 case 38: // up
947                                 case 40: // down
948                                         if (!this.o.keyboardNavigation) break;
949                                         dir = e.keyCode == 38 ? -1 : 1;
950                                         if (e.ctrlKey){
951                                                 newDate = this.moveYear(this.date, dir);
952                                                 newViewDate = this.moveYear(this.viewDate, dir);
953                                                 this._trigger('changeYear', this.viewDate);
954                                         } else if (e.shiftKey){
955                                                 newDate = this.moveMonth(this.date, dir);
956                                                 newViewDate = this.moveMonth(this.viewDate, dir);
957                                                 this._trigger('changeMonth', this.viewDate);
958                                         } else {
959                                                 newDate = new Date(this.date);
960                                                 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
961                                                 newViewDate = new Date(this.viewDate);
962                                                 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
963                                         }
964                                         if (this.dateWithinRange(newDate)){
965                                                 this.date = newDate;
966                                                 this.viewDate = newViewDate;
967                                                 this.setValue();
968                                                 this.update();
969                                                 e.preventDefault();
970                                                 dateChanged = true;
971                                         }
972                                         break;
973                                 case 13: // enter
974                                         this.hide();
975                                         e.preventDefault();
976                                         break;
977                                 case 9: // tab
978                                         this.hide();
979                                         break;
980                         }
981                         if (dateChanged){
982                                 this._trigger('changeDate');
983                                 var element;
984                                 if (this.isInput) {
985                                         element = this.element;
986                                 } else if (this.component){
987                                         element = this.element.find('input');
988                                 }
989                                 if (element) {
990                                         element.change();
991                                 }
992                         }
993                 },
994
995                 showMode: function(dir) {
996                         if (dir) {
997                                 this.viewMode = Math.max(this.o.minViewMode, Math.min(2, this.viewMode + dir));
998                         }
999                         /*
1000                                 vitalets: fixing bug of very special conditions:
1001                                 jquery 1.7.1 + webkit + show inline datepicker in bootstrap popover.
1002                                 Method show() does not set display css correctly and datepicker is not shown.
1003                                 Changed to .css('display', 'block') solve the problem.
1004                                 See https://github.com/vitalets/x-editable/issues/37
1005
1006                                 In jquery 1.7.2+ everything works fine.
1007                         */
1008                         //this.picker.find('>div').hide().filter('.datepicker-'+DPGlobal.modes[this.viewMode].clsName).show();
1009                         this.picker.find('>div').hide().filter('.datepicker-'+DPGlobal.modes[this.viewMode].clsName).css('display', 'block');
1010                         this.updateNavArrows();
1011                 }
1012         };
1013
1014         var DateRangePicker = function(element, options){
1015                 this.element = $(element);
1016                 this.inputs = $.map(options.inputs, function(i){ return i.jquery ? i[0] : i; });
1017                 delete options.inputs;
1018
1019                 $(this.inputs)
1020                         .datepicker(options)
1021                         .bind('changeDate', $.proxy(this.dateUpdated, this));
1022
1023                 this.pickers = $.map(this.inputs, function(i){ return $(i).data('datepicker'); });
1024                 this.updateDates();
1025         };
1026         DateRangePicker.prototype = {
1027                 updateDates: function(){
1028                         this.dates = $.map(this.pickers, function(i){ return i.date; });
1029                         this.updateRanges();
1030                 },
1031                 updateRanges: function(){
1032                         var range = $.map(this.dates, function(d){ return d.valueOf(); });
1033                         $.each(this.pickers, function(i, p){
1034                                 p.setRange(range);
1035                         });
1036                 },
1037                 dateUpdated: function(e){
1038                         var dp = $(e.target).data('datepicker'),
1039                                 new_date = dp.getUTCDate(),
1040                                 i = $.inArray(e.target, this.inputs),
1041                                 l = this.inputs.length;
1042                         if (i == -1) return;
1043
1044                         if (new_date < this.dates[i]){
1045                                 // Date being moved earlier/left
1046                                 while (i>=0 && new_date < this.dates[i]){
1047                                         this.pickers[i--].setUTCDate(new_date);
1048                                 }
1049                         }
1050                         else if (new_date > this.dates[i]){
1051                                 // Date being moved later/right
1052                                 while (i<l && new_date > this.dates[i]){
1053                                         this.pickers[i++].setUTCDate(new_date);
1054                                 }
1055                         }
1056                         this.updateDates();
1057                 },
1058                 remove: function(){
1059                         $.map(this.pickers, function(p){ p.remove(); });
1060                         delete this.element.data().datepicker;
1061                 }
1062         };
1063
1064         function opts_from_el(el, prefix){
1065                 // Derive options from element data-attrs
1066                 var data = $(el).data(),
1067                         out = {}, inkey,
1068                         replace = new RegExp('^' + prefix.toLowerCase() + '([A-Z])'),
1069                         prefix = new RegExp('^' + prefix.toLowerCase());
1070                 for (var key in data)
1071                         if (prefix.test(key)){
1072                                 inkey = key.replace(replace, function(_,a){ return a.toLowerCase(); });
1073                                 out[inkey] = data[key];
1074                         }
1075                 return out;
1076         }
1077
1078         function opts_from_locale(lang){
1079                 // Derive options from locale plugins
1080                 var out = {};
1081                 // Check if "de-DE" style date is available, if not language should
1082                 // fallback to 2 letter code eg "de"
1083                 if (!dates[lang]) {
1084                         lang = lang.split('-')[0]
1085                         if (!dates[lang])
1086                                 return;
1087                 }
1088                 var d = dates[lang];
1089                 $.each(locale_opts, function(i,k){
1090                         if (k in d)
1091                                 out[k] = d[k];
1092                 });
1093                 return out;
1094         }
1095
1096         var old = $.fn.datepicker;
1097         $.fn.datepicker = function ( option ) {
1098                 var args = Array.apply(null, arguments);
1099                 args.shift();
1100                 var internal_return,
1101                         this_return;
1102                 this.each(function () {
1103                         var $this = $(this),
1104                                 data = $this.data('datepicker'),
1105                                 options = typeof option == 'object' && option;
1106                         if (!data) {
1107                                 var elopts = opts_from_el(this, 'date'),
1108                                         // Preliminary otions
1109                                         xopts = $.extend({}, defaults, elopts, options),
1110                                         locopts = opts_from_locale(xopts.language),
1111                                         // Options priority: js args, data-attrs, locales, defaults
1112                                         opts = $.extend({}, defaults, locopts, elopts, options);
1113                                 if ($this.is('.input-daterange') || opts.inputs){
1114                                         var ropts = {
1115                                                 inputs: opts.inputs || $this.find('input').toArray()
1116                                         };
1117                                         $this.data('datepicker', (data = new DateRangePicker(this, $.extend(opts, ropts))));
1118                                 }
1119                                 else{
1120                                         $this.data('datepicker', (data = new Datepicker(this, opts)));
1121                                 }
1122                         }
1123                         if (typeof option == 'string' && typeof data[option] == 'function') {
1124                                 internal_return = data[option].apply(data, args);
1125                                 if (internal_return !== undefined)
1126                                         return false;
1127                         }
1128                 });
1129                 if (internal_return !== undefined)
1130                         return internal_return;
1131                 else
1132                         return this;
1133         };
1134
1135         var defaults = $.fn.datepicker.defaults = {
1136                 autoclose: false,
1137                 beforeShowDay: $.noop,
1138                 calendarWeeks: false,
1139                 clearBtn: false,
1140                 daysOfWeekDisabled: [],
1141                 endDate: Infinity,
1142                 forceParse: true,
1143                 format: 'mm/dd/yyyy',
1144                 keyboardNavigation: true,
1145                 language: 'en',
1146                 minViewMode: 0,
1147                 orientation: "auto",
1148                 rtl: false,
1149                 startDate: -Infinity,
1150                 startView: 0,
1151                 todayBtn: false,
1152                 todayHighlight: false,
1153                 weekStart: 0
1154         };
1155         var locale_opts = $.fn.datepicker.locale_opts = [
1156                 'format',
1157                 'rtl',
1158                 'weekStart'
1159         ];
1160         $.fn.datepicker.Constructor = Datepicker;
1161         var dates = $.fn.datepicker.dates = {
1162                 en: {
1163                         days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
1164                         daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
1165                         daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
1166                         months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
1167                         monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
1168                         today: "Today",
1169                         clear: "Clear"
1170                 }
1171         };
1172
1173         var DPGlobal = {
1174                 modes: [
1175                         {
1176                                 clsName: 'days',
1177                                 navFnc: 'Month',
1178                                 navStep: 1
1179                         },
1180                         {
1181                                 clsName: 'months',
1182                                 navFnc: 'FullYear',
1183                                 navStep: 1
1184                         },
1185                         {
1186                                 clsName: 'years',
1187                                 navFnc: 'FullYear',
1188                                 navStep: 10
1189                 }],
1190                 isLeapYear: function (year) {
1191                         return (((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0));
1192                 },
1193                 getDaysInMonth: function (year, month) {
1194                         return [31, (DPGlobal.isLeapYear(year) ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month];
1195                 },
1196                 validParts: /dd?|DD?|mm?|MM?|yy(?:yy)?/g,
1197                 nonpunctuation: /[^ -\/:-@\[\u3400-\u9fff-`{-~\t\n\r]+/g,
1198                 parseFormat: function(format){
1199                         // IE treats \0 as a string end in inputs (truncating the value),
1200                         // so it's a bad format delimiter, anyway
1201                         var separators = format.replace(this.validParts, '\0').split('\0'),
1202                                 parts = format.match(this.validParts);
1203                         if (!separators || !separators.length || !parts || parts.length === 0){
1204                                 throw new Error("Invalid date format.");
1205                         }
1206                         return {separators: separators, parts: parts};
1207                 },
1208                 parseDate: function(date, format, language) {
1209                         if (date instanceof Date) return date;
1210                         if (typeof format === 'string')
1211                                 format = DPGlobal.parseFormat(format);
1212                         if (/^[\-+]\d+[dmwy]([\s,]+[\-+]\d+[dmwy])*$/.test(date)) {
1213                                 var part_re = /([\-+]\d+)([dmwy])/,
1214                                         parts = date.match(/([\-+]\d+)([dmwy])/g),
1215                                         part, dir;
1216                                 date = new Date();
1217                                 for (var i=0; i<parts.length; i++) {
1218                                         part = part_re.exec(parts[i]);
1219                                         dir = parseInt(part[1]);
1220                                         switch(part[2]){
1221                                                 case 'd':
1222                                                         date.setUTCDate(date.getUTCDate() + dir);
1223                                                         break;
1224                                                 case 'm':
1225                                                         date = Datepicker.prototype.moveMonth.call(Datepicker.prototype, date, dir);
1226                                                         break;
1227                                                 case 'w':
1228                                                         date.setUTCDate(date.getUTCDate() + dir * 7);
1229                                                         break;
1230                                                 case 'y':
1231                                                         date = Datepicker.prototype.moveYear.call(Datepicker.prototype, date, dir);
1232                                                         break;
1233                                         }
1234                                 }
1235                                 return UTCDate(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), 0, 0, 0);
1236                         }
1237                         var parts = date && date.match(this.nonpunctuation) || [],
1238                                 date = new Date(),
1239                                 parsed = {},
1240                                 setters_order = ['yyyy', 'yy', 'M', 'MM', 'm', 'mm', 'd', 'dd'],
1241                                 setters_map = {
1242                                         yyyy: function(d,v){ return d.setUTCFullYear(v); },
1243                                         yy: function(d,v){ return d.setUTCFullYear(2000+v); },
1244                                         m: function(d,v){
1245                                                 if (isNaN(d))
1246                                                         return d;
1247                                                 v -= 1;
1248                                                 while (v<0) v += 12;
1249                                                 v %= 12;
1250                                                 d.setUTCMonth(v);
1251                                                 while (d.getUTCMonth() != v)
1252                                                         d.setUTCDate(d.getUTCDate()-1);
1253                                                 return d;
1254                                         },
1255                                         d: function(d,v){ return d.setUTCDate(v); }
1256                                 },
1257                                 val, filtered, part;
1258                         setters_map['M'] = setters_map['MM'] = setters_map['mm'] = setters_map['m'];
1259                         setters_map['dd'] = setters_map['d'];
1260                         date = UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
1261                         var fparts = format.parts.slice();
1262                         // Remove noop parts
1263                         if (parts.length != fparts.length) {
1264                                 fparts = $(fparts).filter(function(i,p){
1265                                         return $.inArray(p, setters_order) !== -1;
1266                                 }).toArray();
1267                         }
1268                         // Process remainder
1269                         if (parts.length == fparts.length) {
1270                                 for (var i=0, cnt = fparts.length; i < cnt; i++) {
1271                                         val = parseInt(parts[i], 10);
1272                                         part = fparts[i];
1273                                         if (isNaN(val)) {
1274                                                 switch(part) {
1275                                                         case 'MM':
1276                                                                 filtered = $(dates[language].months).filter(function(){
1277                                                                         var m = this.slice(0, parts[i].length),
1278                                                                                 p = parts[i].slice(0, m.length);
1279                                                                         return m == p;
1280                                                                 });
1281                                                                 val = $.inArray(filtered[0], dates[language].months) + 1;
1282                                                                 break;
1283                                                         case 'M':
1284                                                                 filtered = $(dates[language].monthsShort).filter(function(){
1285                                                                         var m = this.slice(0, parts[i].length),
1286                                                                                 p = parts[i].slice(0, m.length);
1287                                                                         return m == p;
1288                                                                 });
1289                                                                 val = $.inArray(filtered[0], dates[language].monthsShort) + 1;
1290                                                                 break;
1291                                                 }
1292                                         }
1293                                         parsed[part] = val;
1294                                 }
1295                                 for (var i=0, _date, s; i<setters_order.length; i++){
1296                                         s = setters_order[i];
1297                                         if (s in parsed && !isNaN(parsed[s])){
1298                                                 _date = new Date(date);
1299                                                 setters_map[s](_date, parsed[s]);
1300                                                 if (!isNaN(_date))
1301                                                         date = _date;
1302                                         }
1303                                 }
1304                         }
1305                         return date;
1306                 },
1307                 formatDate: function(date, format, language){
1308                         if (typeof format === 'string')
1309                                 format = DPGlobal.parseFormat(format);
1310                         var val = {
1311                                 d: date.getUTCDate(),
1312                                 D: dates[language].daysShort[date.getUTCDay()],
1313                                 DD: dates[language].days[date.getUTCDay()],
1314                                 m: date.getUTCMonth() + 1,
1315                                 M: dates[language].monthsShort[date.getUTCMonth()],
1316                                 MM: dates[language].months[date.getUTCMonth()],
1317                                 yy: date.getUTCFullYear().toString().substring(2),
1318                                 yyyy: date.getUTCFullYear()
1319                         };
1320                         val.dd = (val.d < 10 ? '0' : '') + val.d;
1321                         val.mm = (val.m < 10 ? '0' : '') + val.m;
1322                         var date = [],
1323                                 seps = $.extend([], format.separators);
1324                         for (var i=0, cnt = format.parts.length; i <= cnt; i++) {
1325                                 if (seps.length)
1326                                         date.push(seps.shift());
1327                                 date.push(val[format.parts[i]]);
1328                         }
1329                         return date.join('');
1330                 },
1331                 headTemplate: '<thead>'+
1332                                                         '<tr>'+
1333                                                                 '<th class="prev">&laquo;</th>'+
1334                                                                 '<th colspan="5" class="datepicker-switch"></th>'+
1335                                                                 '<th class="next">&raquo;</th>'+
1336                                                         '</tr>'+
1337                                                 '</thead>',
1338                 contTemplate: '<tbody><tr><td colspan="7"></td></tr></tbody>',
1339                 footTemplate: '<tfoot><tr><th colspan="7" class="today"></th></tr><tr><th colspan="7" class="clear"></th></tr></tfoot>'
1340         };
1341         DPGlobal.template = '<div class="datepicker">'+
1342                                                         '<div class="datepicker-days">'+
1343                                                                 '<table class=" table-condensed">'+
1344                                                                         DPGlobal.headTemplate+
1345                                                                         '<tbody></tbody>'+
1346                                                                         DPGlobal.footTemplate+
1347                                                                 '</table>'+
1348                                                         '</div>'+
1349                                                         '<div class="datepicker-months">'+
1350                                                                 '<table class="table-condensed">'+
1351                                                                         DPGlobal.headTemplate+
1352                                                                         DPGlobal.contTemplate+
1353                                                                         DPGlobal.footTemplate+
1354                                                                 '</table>'+
1355                                                         '</div>'+
1356                                                         '<div class="datepicker-years">'+
1357                                                                 '<table class="table-condensed">'+
1358                                                                         DPGlobal.headTemplate+
1359                                                                         DPGlobal.contTemplate+
1360                                                                         DPGlobal.footTemplate+
1361                                                                 '</table>'+
1362                                                         '</div>'+
1363                                                 '</div>';
1364
1365         $.fn.datepicker.DPGlobal = DPGlobal;
1366
1367
1368         /* DATEPICKER NO CONFLICT
1369         * =================== */
1370
1371         $.fn.datepicker.noConflict = function(){
1372                 $.fn.datepicker = old;
1373                 return this;
1374         };
1375
1376
1377         /* DATEPICKER DATA-API
1378         * ================== */
1379
1380         $(document).on(
1381                 'focus.datepicker.data-api click.datepicker.data-api',
1382                 '[data-provide="datepicker"]',
1383                 function(e){
1384                         var $this = $(this);
1385                         if ($this.data('datepicker')) return;
1386                         e.preventDefault();
1387                         // component click requires us to explicitly show it
1388                         $this.datepicker('show');
1389                 }
1390         );
1391         $(function(){
1392                 $('[data-provide="datepicker-inline"]').datepicker();
1393         });
1394
1395 }( window.jQuery ));