source: pro-violet-viettel/docs/Space/assets/js/uncompressed/date-time/bootstrap-datepicker.js @ 290

Last change on this file since 290 was 290, checked in by lamdt, 11 years ago
File size: 31.3 KB
Line 
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        function UTCDate(){
24                return new Date(Date.UTC.apply(Date, arguments));
25        }
26        function UTCToday(){
27                var today = new Date();
28                return UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
29        }
30
31        // Picker object
32
33        var Datepicker = function(element, options) {
34                var that = this;
35
36                this.element = $(element);
37                this.language = options.language||this.element.data('date-language')||"en";
38                this.language = this.language in dates ? this.language : this.language.split('-')[0]; //Check if "de-DE" style date is available, if not language should fallback to 2 letter code eg "de"
39                this.language = this.language in dates ? this.language : "en";
40                this.isRTL = dates[this.language].rtl||false;
41                this.format = DPGlobal.parseFormat(options.format||this.element.data('date-format')||dates[this.language].format||'mm/dd/yyyy');
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._attachEvents();
50
51                this.forceParse = true;
52                if ('forceParse' in options) {
53                        this.forceParse = options.forceParse;
54                } else if ('dateForceParse' in this.element.data()) {
55                        this.forceParse = this.element.data('date-force-parse');
56                }
57
58
59                this.picker = $(DPGlobal.template)
60                                                        .appendTo(this.isInline ? this.element : 'body')
61                                                        .on({
62                                                                click: $.proxy(this.click, this),
63                                                                mousedown: $.proxy(this.mousedown, this)
64                                                        });
65
66                if(this.isInline) {
67                        this.picker.addClass('datepicker-inline');
68                } else {
69                        this.picker.addClass('datepicker-dropdown dropdown-menu');
70                }
71                if (this.isRTL){
72                        this.picker.addClass('datepicker-rtl');
73                        this.picker.find('.prev i, .next i')
74                                                .toggleClass('icon-arrow-left icon-arrow-right');
75                }
76                $(document).on('mousedown', function (e) {
77                        // Clicked outside the datepicker, hide it
78                        if ($(e.target).closest('.datepicker.datepicker-inline, .datepicker.datepicker-dropdown').length === 0) {
79                                that.hide();
80                        }
81                });
82
83                this.autoclose = false;
84                if ('autoclose' in options) {
85                        this.autoclose = options.autoclose;
86                } else if ('dateAutoclose' in this.element.data()) {
87                        this.autoclose = this.element.data('date-autoclose');
88                }
89
90                this.keyboardNavigation = true;
91                if ('keyboardNavigation' in options) {
92                        this.keyboardNavigation = options.keyboardNavigation;
93                } else if ('dateKeyboardNavigation' in this.element.data()) {
94                        this.keyboardNavigation = this.element.data('date-keyboard-navigation');
95                }
96
97                this.viewMode = this.startViewMode = 0;
98                switch(options.startView || this.element.data('date-start-view')){
99                        case 2:
100                        case 'decade':
101                                this.viewMode = this.startViewMode = 2;
102                                break;
103                        case 1:
104                        case 'year':
105                                this.viewMode = this.startViewMode = 1;
106                                break;
107                }
108
109                this.minViewMode = options.minViewMode||this.element.data('date-min-view-mode')||0;
110                if (typeof this.minViewMode === 'string') {
111                        switch (this.minViewMode) {
112                                case 'months':
113                                        this.minViewMode = 1;
114                                        break;
115                                case 'years':
116                                        this.minViewMode = 2;
117                                        break;
118                                default:
119                                        this.minViewMode = 0;
120                                        break;
121                        }
122                }
123
124                this.viewMode = this.startViewMode = Math.max(this.startViewMode, this.minViewMode);
125
126                this.todayBtn = (options.todayBtn||this.element.data('date-today-btn')||false);
127                this.todayHighlight = (options.todayHighlight||this.element.data('date-today-highlight')||false);
128
129                this.calendarWeeks = false;
130                if ('calendarWeeks' in options) {
131                        this.calendarWeeks = options.calendarWeeks;
132                } else if ('dateCalendarWeeks' in this.element.data()) {
133                        this.calendarWeeks = this.element.data('date-calendar-weeks');
134                }
135                if (this.calendarWeeks)
136                        this.picker.find('tfoot th.today')
137                                                .attr('colspan', function(i, val){
138                                                        return parseInt(val) + 1;
139                                                });
140
141                this.weekStart = ((options.weekStart||this.element.data('date-weekstart')||dates[this.language].weekStart||0) % 7);
142                this.weekEnd = ((this.weekStart + 6) % 7);
143                this.startDate = -Infinity;
144                this.endDate = Infinity;
145                this.daysOfWeekDisabled = [];
146                this.setStartDate(options.startDate||this.element.data('date-startdate'));
147                this.setEndDate(options.endDate||this.element.data('date-enddate'));
148                this.setDaysOfWeekDisabled(options.daysOfWeekDisabled||this.element.data('date-days-of-week-disabled'));
149                this.fillDow();
150                this.fillMonths();
151                this.update();
152                this.showMode();
153
154                if(this.isInline) {
155                        this.show();
156                }
157        };
158
159        Datepicker.prototype = {
160                constructor: Datepicker,
161
162                _events: [],
163                _attachEvents: function(){
164                        this._detachEvents();
165                        if (this.isInput) { // single input
166                                this._events = [
167                                        [this.element, {
168                                                focus: $.proxy(this.show, this),
169                                                keyup: $.proxy(this.update, this),
170                                                keydown: $.proxy(this.keydown, this)
171                                        }]
172                                ];
173                        }
174                        else if (this.component && this.hasInput){ // component: input + button
175                                this._events = [
176                                        // For components that are not readonly, allow keyboard nav
177                                        [this.element.find('input'), {
178                                                focus: $.proxy(this.show, this),
179                                                keyup: $.proxy(this.update, this),
180                                                keydown: $.proxy(this.keydown, this)
181                                        }],
182                                        [this.component, {
183                                                click: $.proxy(this.show, this)
184                                        }]
185                                ];
186                        }
187                                                else if (this.element.is('div')) {  // inline datepicker
188                                                        this.isInline = true;
189                                                }
190                        else {
191                                this._events = [
192                                        [this.element, {
193                                                click: $.proxy(this.show, this)
194                                        }]
195                                ];
196                        }
197                        for (var i=0, el, ev; i<this._events.length; i++){
198                                el = this._events[i][0];
199                                ev = this._events[i][1];
200                                el.on(ev);
201                        }
202                },
203                _detachEvents: function(){
204                        for (var i=0, el, ev; i<this._events.length; i++){
205                                el = this._events[i][0];
206                                ev = this._events[i][1];
207                                el.off(ev);
208                        }
209                        this._events = [];
210                },
211
212                show: function(e) {
213                        this.picker.show();
214                        this.height = this.component ? this.component.outerHeight() : this.element.outerHeight();
215                        this.update();
216                        this.place();
217                        $(window).on('resize', $.proxy(this.place, this));
218                        if (e) {
219                                e.preventDefault();
220                        }
221                        this.element.trigger({
222                                type: 'show',
223                                date: this.date
224                        });
225                },
226
227                hide: function(e){
228                        if(this.isInline) return;
229                        if (!this.picker.is(':visible')) return;
230                        this.picker.hide();
231                        $(window).off('resize', this.place);
232                        this.viewMode = this.startViewMode;
233                        this.showMode();
234                        if (!this.isInput) {
235                                $(document).off('mousedown', this.hide);
236                        }
237
238                        if (
239                                this.forceParse &&
240                                (
241                                        this.isInput && this.element.val() ||
242                                        this.hasInput && this.element.find('input').val()
243                                )
244                        )
245                                this.setValue();
246                        this.element.trigger({
247                                type: 'hide',
248                                date: this.date
249                        });
250                },
251
252                remove: function() {
253                        this._detachEvents();
254                        this.picker.remove();
255                        delete this.element.data().datepicker;
256                        if (!this.isInput) {
257                                delete this.element.data().date;
258                        }
259                },
260
261                getDate: function() {
262                        var d = this.getUTCDate();
263                        return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
264                },
265
266                getUTCDate: function() {
267                        return this.date;
268                },
269
270                setDate: function(d) {
271                        this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
272                },
273
274                setUTCDate: function(d) {
275                        this.date = d;
276                        this.setValue();
277                },
278
279                setValue: function() {
280                        var formatted = this.getFormattedDate();
281                        if (!this.isInput) {
282                                if (this.component){
283                                        this.element.find('input').val(formatted);
284                                }
285                                this.element.data('date', formatted);
286                        } else {
287                                this.element.val(formatted);
288                        }
289                },
290
291                getFormattedDate: function(format) {
292                        if (format === undefined)
293                                format = this.format;
294                        return DPGlobal.formatDate(this.date, format, this.language);
295                },
296
297                setStartDate: function(startDate){
298                        this.startDate = startDate||-Infinity;
299                        if (this.startDate !== -Infinity) {
300                                this.startDate = DPGlobal.parseDate(this.startDate, this.format, this.language);
301                        }
302                        this.update();
303                        this.updateNavArrows();
304                },
305
306                setEndDate: function(endDate){
307                        this.endDate = endDate||Infinity;
308                        if (this.endDate !== Infinity) {
309                                this.endDate = DPGlobal.parseDate(this.endDate, this.format, this.language);
310                        }
311                        this.update();
312                        this.updateNavArrows();
313                },
314
315                setDaysOfWeekDisabled: function(daysOfWeekDisabled){
316                        this.daysOfWeekDisabled = daysOfWeekDisabled||[];
317                        if (!$.isArray(this.daysOfWeekDisabled)) {
318                                this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
319                        }
320                        this.daysOfWeekDisabled = $.map(this.daysOfWeekDisabled, function (d) {
321                                return parseInt(d, 10);
322                        });
323                        this.update();
324                        this.updateNavArrows();
325                },
326
327                place: function(){
328                                                if(this.isInline) return;
329                        var zIndex = parseInt(this.element.parents().filter(function() {
330                                                        return $(this).css('z-index') != 'auto';
331                                                }).first().css('z-index'))+10;
332                        var offset = this.component ? this.component.parent().offset() : this.element.offset();
333                        var height = this.component ? this.component.outerHeight(true) : this.element.outerHeight(true);
334                        this.picker.css({
335                                top: offset.top + height,
336                                left: offset.left,
337                                zIndex: zIndex
338                        });
339                },
340
341                update: function(){
342                        var date, fromArgs = false;
343                        if(arguments && arguments.length && (typeof arguments[0] === 'string' || arguments[0] instanceof Date)) {
344                                date = arguments[0];
345                                fromArgs = true;
346                        } else {
347                                date = this.isInput ? this.element.val() : this.element.data('date') || this.element.find('input').val();
348                        }
349
350                        this.date = DPGlobal.parseDate(date, this.format, this.language);
351
352                        if(fromArgs) this.setValue();
353
354                        if (this.date < this.startDate) {
355                                this.viewDate = new Date(this.startDate);
356                        } else if (this.date > this.endDate) {
357                                this.viewDate = new Date(this.endDate);
358                        } else {
359                                this.viewDate = new Date(this.date);
360                        }
361                        this.fill();
362                },
363
364                fillDow: function(){
365                        var dowCnt = this.weekStart,
366                        html = '<tr>';
367                        if(this.calendarWeeks){
368                                var cell = '<th class="cw">&nbsp;</th>';
369                                html += cell;
370                                this.picker.find('.datepicker-days thead tr:first-child').prepend(cell);
371                        }
372                        while (dowCnt < this.weekStart + 7) {
373                                html += '<th class="dow">'+dates[this.language].daysMin[(dowCnt++)%7]+'</th>';
374                        }
375                        html += '</tr>';
376                        this.picker.find('.datepicker-days thead').append(html);
377                },
378
379                fillMonths: function(){
380                        var html = '',
381                        i = 0;
382                        while (i < 12) {
383                                html += '<span class="month">'+dates[this.language].monthsShort[i++]+'</span>';
384                        }
385                        this.picker.find('.datepicker-months td').html(html);
386                },
387
388                fill: function() {
389                        var d = new Date(this.viewDate),
390                                year = d.getUTCFullYear(),
391                                month = d.getUTCMonth(),
392                                startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
393                                startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
394                                endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
395                                endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
396                                currentDate = this.date && this.date.valueOf(),
397                                today = new Date();
398                        this.picker.find('.datepicker-days thead th.switch')
399                                                .text(dates[this.language].months[month]+' '+year);
400                        this.picker.find('tfoot th.today')
401                                                .text(dates[this.language].today)
402                                                .toggle(this.todayBtn !== false);
403                        this.updateNavArrows();
404                        this.fillMonths();
405                        var prevMonth = UTCDate(year, month-1, 28,0,0,0,0),
406                                day = DPGlobal.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
407                        prevMonth.setUTCDate(day);
408                        prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
409                        var nextMonth = new Date(prevMonth);
410                        nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
411                        nextMonth = nextMonth.valueOf();
412                        var html = [];
413                        var clsName;
414                        while(prevMonth.valueOf() < nextMonth) {
415                                if (prevMonth.getUTCDay() == this.weekStart) {
416                                        html.push('<tr>');
417                                        if(this.calendarWeeks){
418                                                // ISO 8601: First week contains first thursday.
419                                                // ISO also states week starts on Monday, but we can be more abstract here.
420                                                var
421                                                        // Start of current week: based on weekstart/current date
422                                                        ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
423                                                        // Thursday of this week
424                                                        th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
425                                                        // First Thursday of year, year from thursday
426                                                        yth = new Date(+(yth = UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
427                                                        // Calendar week: ms between thursdays, div ms per day, div 7 days
428                                                        calWeek =  (th - yth) / 864e5 / 7 + 1;
429                                                html.push('<td class="cw">'+ calWeek +'</td>');
430
431                                        }
432                                }
433                                clsName = '';
434                                if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
435                                        clsName += ' old';
436                                } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
437                                        clsName += ' new';
438                                }
439                                // Compare internal UTC date with local today, not UTC today
440                                if (this.todayHighlight &&
441                                        prevMonth.getUTCFullYear() == today.getFullYear() &&
442                                        prevMonth.getUTCMonth() == today.getMonth() &&
443                                        prevMonth.getUTCDate() == today.getDate()) {
444                                        clsName += ' today';
445                                }
446                                if (currentDate && prevMonth.valueOf() == currentDate) {
447                                        clsName += ' active';
448                                }
449                                if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
450                                        $.inArray(prevMonth.getUTCDay(), this.daysOfWeekDisabled) !== -1) {
451                                        clsName += ' disabled';
452                                }
453                                html.push('<td class="day'+clsName+'">'+prevMonth.getUTCDate() + '</td>');
454                                if (prevMonth.getUTCDay() == this.weekEnd) {
455                                        html.push('</tr>');
456                                }
457                                prevMonth.setUTCDate(prevMonth.getUTCDate()+1);
458                        }
459                        this.picker.find('.datepicker-days tbody').empty().append(html.join(''));
460                        var currentYear = this.date && this.date.getUTCFullYear();
461
462                        var months = this.picker.find('.datepicker-months')
463                                                .find('th:eq(1)')
464                                                        .text(year)
465                                                        .end()
466                                                .find('span').removeClass('active');
467                        if (currentYear && currentYear == year) {
468                                months.eq(this.date.getUTCMonth()).addClass('active');
469                        }
470                        if (year < startYear || year > endYear) {
471                                months.addClass('disabled');
472                        }
473                        if (year == startYear) {
474                                months.slice(0, startMonth).addClass('disabled');
475                        }
476                        if (year == endYear) {
477                                months.slice(endMonth+1).addClass('disabled');
478                        }
479
480                        html = '';
481                        year = parseInt(year/10, 10) * 10;
482                        var yearCont = this.picker.find('.datepicker-years')
483                                                                .find('th:eq(1)')
484                                                                        .text(year + '-' + (year + 9))
485                                                                        .end()
486                                                                .find('td');
487                        year -= 1;
488                        for (var i = -1; i < 11; i++) {
489                                html += '<span class="year'+(i == -1 || i == 10 ? ' old' : '')+(currentYear == year ? ' active' : '')+(year < startYear || year > endYear ? ' disabled' : '')+'">'+year+'</span>';
490                                year += 1;
491                        }
492                        yearCont.html(html);
493                },
494
495                updateNavArrows: function() {
496                        var d = new Date(this.viewDate),
497                                year = d.getUTCFullYear(),
498                                month = d.getUTCMonth();
499                        switch (this.viewMode) {
500                                case 0:
501                                        if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
502                                                this.picker.find('.prev').css({visibility: 'hidden'});
503                                        } else {
504                                                this.picker.find('.prev').css({visibility: 'visible'});
505                                        }
506                                        if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
507                                                this.picker.find('.next').css({visibility: 'hidden'});
508                                        } else {
509                                                this.picker.find('.next').css({visibility: 'visible'});
510                                        }
511                                        break;
512                                case 1:
513                                case 2:
514                                        if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
515                                                this.picker.find('.prev').css({visibility: 'hidden'});
516                                        } else {
517                                                this.picker.find('.prev').css({visibility: 'visible'});
518                                        }
519                                        if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
520                                                this.picker.find('.next').css({visibility: 'hidden'});
521                                        } else {
522                                                this.picker.find('.next').css({visibility: 'visible'});
523                                        }
524                                        break;
525                        }
526                },
527
528                click: function(e) {
529                        e.preventDefault();
530                        var target = $(e.target).closest('span, td, th');
531                        if (target.length == 1) {
532                                switch(target[0].nodeName.toLowerCase()) {
533                                        case 'th':
534                                                switch(target[0].className) {
535                                                        case 'switch':
536                                                                this.showMode(1);
537                                                                break;
538                                                        case 'prev':
539                                                        case 'next':
540                                                                var dir = DPGlobal.modes[this.viewMode].navStep * (target[0].className == 'prev' ? -1 : 1);
541                                                                switch(this.viewMode){
542                                                                        case 0:
543                                                                                this.viewDate = this.moveMonth(this.viewDate, dir);
544                                                                                break;
545                                                                        case 1:
546                                                                        case 2:
547                                                                                this.viewDate = this.moveYear(this.viewDate, dir);
548                                                                                break;
549                                                                }
550                                                                this.fill();
551                                                                break;
552                                                        case 'today':
553                                                                var date = new Date();
554                                                                date = UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
555
556                                                                this.showMode(-2);
557                                                                var which = this.todayBtn == 'linked' ? null : 'view';
558                                                                this._setDate(date, which);
559                                                                break;
560                                                }
561                                                break;
562                                        case 'span':
563                                                if (!target.is('.disabled')) {
564                                                        this.viewDate.setUTCDate(1);
565                                                        if (target.is('.month')) {
566                                                                var day = 1;
567                                                                var month = target.parent().find('span').index(target);
568                                                                var year = this.viewDate.getUTCFullYear();
569                                                                this.viewDate.setUTCMonth(month);
570                                                                this.element.trigger({
571                                                                        type: 'changeMonth',
572                                                                        date: this.viewDate
573                                                                });
574                                                                if ( this.minViewMode == 1 ) {
575                                                                        this._setDate(UTCDate(year, month, day,0,0,0,0));
576                                                                }
577                                                        } else {
578                                                                var year = parseInt(target.text(), 10)||0;
579                                                                var day = 1;
580                                                                var month = 0;
581                                                                this.viewDate.setUTCFullYear(year);
582                                                                this.element.trigger({
583                                                                        type: 'changeYear',
584                                                                        date: this.viewDate
585                                                                });
586                                                                if ( this.minViewMode == 2 ) {
587                                                                        this._setDate(UTCDate(year, month, day,0,0,0,0));
588                                                                }
589                                                        }
590                                                        this.showMode(-1);
591                                                        this.fill();
592                                                }
593                                                break;
594                                        case 'td':
595                                                if (target.is('.day') && !target.is('.disabled')){
596                                                        var day = parseInt(target.text(), 10)||1;
597                                                        var year = this.viewDate.getUTCFullYear(),
598                                                                month = this.viewDate.getUTCMonth();
599                                                        if (target.is('.old')) {
600                                                                if (month === 0) {
601                                                                        month = 11;
602                                                                        year -= 1;
603                                                                } else {
604                                                                        month -= 1;
605                                                                }
606                                                        } else if (target.is('.new')) {
607                                                                if (month == 11) {
608                                                                        month = 0;
609                                                                        year += 1;
610                                                                } else {
611                                                                        month += 1;
612                                                                }
613                                                        }
614                                                        this._setDate(UTCDate(year, month, day,0,0,0,0));
615                                                }
616                                                break;
617                                }
618                        }
619                },
620
621                _setDate: function(date, which){
622                        if (!which || which == 'date')
623                                this.date = date;
624                        if (!which || which  == 'view')
625                                this.viewDate = date;
626                        this.fill();
627                        this.setValue();
628                        this.element.trigger({
629                                type: 'changeDate',
630                                date: this.date
631                        });
632                        var element;
633                        if (this.isInput) {
634                                element = this.element;
635                        } else if (this.component){
636                                element = this.element.find('input');
637                        }
638                        if (element) {
639                                element.change();
640                                if (this.autoclose && (!which || which == 'date')) {
641                                        this.hide();
642                                }
643                        }
644                },
645
646                moveMonth: function(date, dir){
647                        if (!dir) return date;
648                        var new_date = new Date(date.valueOf()),
649                                day = new_date.getUTCDate(),
650                                month = new_date.getUTCMonth(),
651                                mag = Math.abs(dir),
652                                new_month, test;
653                        dir = dir > 0 ? 1 : -1;
654                        if (mag == 1){
655                                test = dir == -1
656                                        // If going back one month, make sure month is not current month
657                                        // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
658                                        ? function(){ return new_date.getUTCMonth() == month; }
659                                        // If going forward one month, make sure month is as expected
660                                        // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
661                                        : function(){ return new_date.getUTCMonth() != new_month; };
662                                new_month = month + dir;
663                                new_date.setUTCMonth(new_month);
664                                // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
665                                if (new_month < 0 || new_month > 11)
666                                        new_month = (new_month + 12) % 12;
667                        } else {
668                                // For magnitudes >1, move one month at a time...
669                                for (var i=0; i<mag; i++)
670                                        // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
671                                        new_date = this.moveMonth(new_date, dir);
672                                // ...then reset the day, keeping it in the new month
673                                new_month = new_date.getUTCMonth();
674                                new_date.setUTCDate(day);
675                                test = function(){ return new_month != new_date.getUTCMonth(); };
676                        }
677                        // Common date-resetting loop -- if date is beyond end of month, make it
678                        // end of month
679                        while (test()){
680                                new_date.setUTCDate(--day);
681                                new_date.setUTCMonth(new_month);
682                        }
683                        return new_date;
684                },
685
686                moveYear: function(date, dir){
687                        return this.moveMonth(date, dir*12);
688                },
689
690                dateWithinRange: function(date){
691                        return date >= this.startDate && date <= this.endDate;
692                },
693
694                keydown: function(e){
695                        if (this.picker.is(':not(:visible)')){
696                                if (e.keyCode == 27) // allow escape to hide and re-show picker
697                                        this.show();
698                                return;
699                        }
700                        var dateChanged = false,
701                                dir, day, month,
702                                newDate, newViewDate;
703                        switch(e.keyCode){
704                                case 27: // escape
705                                        this.hide();
706                                        e.preventDefault();
707                                        break;
708                                case 37: // left
709                                case 39: // right
710                                        if (!this.keyboardNavigation) break;
711                                        dir = e.keyCode == 37 ? -1 : 1;
712                                        if (e.ctrlKey){
713                                                newDate = this.moveYear(this.date, dir);
714                                                newViewDate = this.moveYear(this.viewDate, dir);
715                                        } else if (e.shiftKey){
716                                                newDate = this.moveMonth(this.date, dir);
717                                                newViewDate = this.moveMonth(this.viewDate, dir);
718                                        } else {
719                                                newDate = new Date(this.date);
720                                                newDate.setUTCDate(this.date.getUTCDate() + dir);
721                                                newViewDate = new Date(this.viewDate);
722                                                newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
723                                        }
724                                        if (this.dateWithinRange(newDate)){
725                                                this.date = newDate;
726                                                this.viewDate = newViewDate;
727                                                this.setValue();
728                                                this.update();
729                                                e.preventDefault();
730                                                dateChanged = true;
731                                        }
732                                        break;
733                                case 38: // up
734                                case 40: // down
735                                        if (!this.keyboardNavigation) break;
736                                        dir = e.keyCode == 38 ? -1 : 1;
737                                        if (e.ctrlKey){
738                                                newDate = this.moveYear(this.date, dir);
739                                                newViewDate = this.moveYear(this.viewDate, dir);
740                                        } else if (e.shiftKey){
741                                                newDate = this.moveMonth(this.date, dir);
742                                                newViewDate = this.moveMonth(this.viewDate, dir);
743                                        } else {
744                                                newDate = new Date(this.date);
745                                                newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
746                                                newViewDate = new Date(this.viewDate);
747                                                newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
748                                        }
749                                        if (this.dateWithinRange(newDate)){
750                                                this.date = newDate;
751                                                this.viewDate = newViewDate;
752                                                this.setValue();
753                                                this.update();
754                                                e.preventDefault();
755                                                dateChanged = true;
756                                        }
757                                        break;
758                                case 13: // enter
759                                        this.hide();
760                                        e.preventDefault();
761                                        break;
762                                case 9: // tab
763                                        this.hide();
764                                        break;
765                        }
766                        if (dateChanged){
767                                this.element.trigger({
768                                        type: 'changeDate',
769                                        date: this.date
770                                });
771                                var element;
772                                if (this.isInput) {
773                                        element = this.element;
774                                } else if (this.component){
775                                        element = this.element.find('input');
776                                }
777                                if (element) {
778                                        element.change();
779                                }
780                        }
781                },
782
783                showMode: function(dir) {
784                        if (dir) {
785                                this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
786                        }
787                        /*
788                                vitalets: fixing bug of very special conditions:
789                                jquery 1.7.1 + webkit + show inline datepicker in bootstrap popover.
790                                Method show() does not set display css correctly and datepicker is not shown.
791                                Changed to .css('display', 'block') solve the problem.
792                                See https://github.com/vitalets/x-editable/issues/37
793
794                                In jquery 1.7.2+ everything works fine.
795                        */
796                        //this.picker.find('>div').hide().filter('.datepicker-'+DPGlobal.modes[this.viewMode].clsName).show();
797                        this.picker.find('>div').hide().filter('.datepicker-'+DPGlobal.modes[this.viewMode].clsName).css('display', 'block');
798                        this.updateNavArrows();
799                }
800        };
801
802        $.fn.datepicker = function ( option ) {
803                var args = Array.apply(null, arguments);
804                args.shift();
805                return this.each(function () {
806                        var $this = $(this),
807                                data = $this.data('datepicker'),
808                                options = typeof option == 'object' && option;
809                        if (!data) {
810                                $this.data('datepicker', (data = new Datepicker(this, $.extend({}, $.fn.datepicker.defaults,options))));
811                        }
812                        if (typeof option == 'string' && typeof data[option] == 'function') {
813                                data[option].apply(data, args);
814                        }
815                });
816        };
817
818        $.fn.datepicker.defaults = {
819        };
820        $.fn.datepicker.Constructor = Datepicker;
821        var dates = $.fn.datepicker.dates = {
822                en: {
823                        days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
824                        daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
825                        daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
826                        months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
827                        monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
828                        today: "Today"
829                }
830        };
831
832        var DPGlobal = {
833                modes: [
834                        {
835                                clsName: 'days',
836                                navFnc: 'Month',
837                                navStep: 1
838                        },
839                        {
840                                clsName: 'months',
841                                navFnc: 'FullYear',
842                                navStep: 1
843                        },
844                        {
845                                clsName: 'years',
846                                navFnc: 'FullYear',
847                                navStep: 10
848                }],
849                isLeapYear: function (year) {
850                        return (((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0));
851                },
852                getDaysInMonth: function (year, month) {
853                        return [31, (DPGlobal.isLeapYear(year) ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month];
854                },
855                validParts: /dd?|DD?|mm?|MM?|yy(?:yy)?/g,
856                nonpunctuation: /[^ -\/:-@\[\u3400-\u9fff-`{-~\t\n\r]+/g,
857                parseFormat: function(format){
858                        // IE treats \0 as a string end in inputs (truncating the value),
859                        // so it's a bad format delimiter, anyway
860                        var separators = format.replace(this.validParts, '\0').split('\0'),
861                                parts = format.match(this.validParts);
862                        if (!separators || !separators.length || !parts || parts.length === 0){
863                                throw new Error("Invalid date format.");
864                        }
865                        return {separators: separators, parts: parts};
866                },
867                parseDate: function(date, format, language) {
868                        if (date instanceof Date) return date;
869                        if (/^[\-+]\d+[dmwy]([\s,]+[\-+]\d+[dmwy])*$/.test(date)) {
870                                var part_re = /([\-+]\d+)([dmwy])/,
871                                        parts = date.match(/([\-+]\d+)([dmwy])/g),
872                                        part, dir;
873                                date = new Date();
874                                for (var i=0; i<parts.length; i++) {
875                                        part = part_re.exec(parts[i]);
876                                        dir = parseInt(part[1]);
877                                        switch(part[2]){
878                                                case 'd':
879                                                        date.setUTCDate(date.getUTCDate() + dir);
880                                                        break;
881                                                case 'm':
882                                                        date = Datepicker.prototype.moveMonth.call(Datepicker.prototype, date, dir);
883                                                        break;
884                                                case 'w':
885                                                        date.setUTCDate(date.getUTCDate() + dir * 7);
886                                                        break;
887                                                case 'y':
888                                                        date = Datepicker.prototype.moveYear.call(Datepicker.prototype, date, dir);
889                                                        break;
890                                        }
891                                }
892                                return UTCDate(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), 0, 0, 0);
893                        }
894                        var parts = date && date.match(this.nonpunctuation) || [],
895                                date = new Date(),
896                                parsed = {},
897                                setters_order = ['yyyy', 'yy', 'M', 'MM', 'm', 'mm', 'd', 'dd'],
898                                setters_map = {
899                                        yyyy: function(d,v){ return d.setUTCFullYear(v); },
900                                        yy: function(d,v){ return d.setUTCFullYear(2000+v); },
901                                        m: function(d,v){
902                                                v -= 1;
903                                                while (v<0) v += 12;
904                                                v %= 12;
905                                                d.setUTCMonth(v);
906                                                while (d.getUTCMonth() != v)
907                                                        d.setUTCDate(d.getUTCDate()-1);
908                                                return d;
909                                        },
910                                        d: function(d,v){ return d.setUTCDate(v); }
911                                },
912                                val, filtered, part;
913                        setters_map['M'] = setters_map['MM'] = setters_map['mm'] = setters_map['m'];
914                        setters_map['dd'] = setters_map['d'];
915                        date = UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
916                        var fparts = format.parts.slice();
917                        // Remove noop parts
918                        if (parts.length != fparts.length) {
919                                fparts = $(fparts).filter(function(i,p){
920                                        return $.inArray(p, setters_order) !== -1;
921                                }).toArray();
922                        }
923                        // Process remainder
924                        if (parts.length == fparts.length) {
925                                for (var i=0, cnt = fparts.length; i < cnt; i++) {
926                                        val = parseInt(parts[i], 10);
927                                        part = fparts[i];
928                                        if (isNaN(val)) {
929                                                switch(part) {
930                                                        case 'MM':
931                                                                filtered = $(dates[language].months).filter(function(){
932                                                                        var m = this.slice(0, parts[i].length),
933                                                                                p = parts[i].slice(0, m.length);
934                                                                        return m == p;
935                                                                });
936                                                                val = $.inArray(filtered[0], dates[language].months) + 1;
937                                                                break;
938                                                        case 'M':
939                                                                filtered = $(dates[language].monthsShort).filter(function(){
940                                                                        var m = this.slice(0, parts[i].length),
941                                                                                p = parts[i].slice(0, m.length);
942                                                                        return m == p;
943                                                                });
944                                                                val = $.inArray(filtered[0], dates[language].monthsShort) + 1;
945                                                                break;
946                                                }
947                                        }
948                                        parsed[part] = val;
949                                }
950                                for (var i=0, s; i<setters_order.length; i++){
951                                        s = setters_order[i];
952                                        if (s in parsed && !isNaN(parsed[s]))
953                                                setters_map[s](date, parsed[s]);
954                                }
955                        }
956                        return date;
957                },
958                formatDate: function(date, format, language){
959                        var val = {
960                                d: date.getUTCDate(),
961                                D: dates[language].daysShort[date.getUTCDay()],
962                                DD: dates[language].days[date.getUTCDay()],
963                                m: date.getUTCMonth() + 1,
964                                M: dates[language].monthsShort[date.getUTCMonth()],
965                                MM: dates[language].months[date.getUTCMonth()],
966                                yy: date.getUTCFullYear().toString().substring(2),
967                                yyyy: date.getUTCFullYear()
968                        };
969                        val.dd = (val.d < 10 ? '0' : '') + val.d;
970                        val.mm = (val.m < 10 ? '0' : '') + val.m;
971                        var date = [],
972                                seps = $.extend([], format.separators);
973                        for (var i=0, cnt = format.parts.length; i < cnt; i++) {
974                                if (seps.length)
975                                        date.push(seps.shift());
976                                date.push(val[format.parts[i]]);
977                        }
978                        return date.join('');
979                },
980                headTemplate: '<thead>'+
981                                                        '<tr>'+
982                                                                '<th class="prev"><i class="icon-arrow-left"/></th>'+
983                                                                '<th colspan="5" class="switch"></th>'+
984                                                                '<th class="next"><i class="icon-arrow-right"/></th>'+
985                                                        '</tr>'+
986                                                '</thead>',
987                contTemplate: '<tbody><tr><td colspan="7"></td></tr></tbody>',
988                footTemplate: '<tfoot><tr><th colspan="7" class="today"></th></tr></tfoot>'
989        };
990        DPGlobal.template = '<div class="datepicker">'+
991                                                        '<div class="datepicker-days">'+
992                                                                '<table class=" table-condensed">'+
993                                                                        DPGlobal.headTemplate+
994                                                                        '<tbody></tbody>'+
995                                                                        DPGlobal.footTemplate+
996                                                                '</table>'+
997                                                        '</div>'+
998                                                        '<div class="datepicker-months">'+
999                                                                '<table class="table-condensed">'+
1000                                                                        DPGlobal.headTemplate+
1001                                                                        DPGlobal.contTemplate+
1002                                                                        DPGlobal.footTemplate+
1003                                                                '</table>'+
1004                                                        '</div>'+
1005                                                        '<div class="datepicker-years">'+
1006                                                                '<table class="table-condensed">'+
1007                                                                        DPGlobal.headTemplate+
1008                                                                        DPGlobal.contTemplate+
1009                                                                        DPGlobal.footTemplate+
1010                                                                '</table>'+
1011                                                        '</div>'+
1012                                                '</div>';
1013
1014        $.fn.datepicker.DPGlobal = DPGlobal;
1015
1016}( window.jQuery );
Note: See TracBrowser for help on using the repository browser.