views:

154

answers:

3

In jQuery DatePicker there is one annoying thing, if you using it as a calendar and depend on selected date. While navigationg from month to month it keep selected day activated for all months. I know that this issue exist for more than 6 months and I have reported it to jQuery Team.However I would like to know is there any workarounds on hot to disable this behaviour?

Calendar example can be found here

+2  A: 

Include this script after you've included jQuery UI. You can include it inline, or put it in its own file. edit: This hack fixes your issue for version 1.8.5 of jQuery UI. I have tested a number of usage cases in FF 3.6.10 and IE 8. It is entirely possible that this hack does not work under all possible circumstances. If I notice any, I'll probably try to fix them, but for now, it is provided as is. I've thrown together a demo. Shows it's working with jQuery 1.8.4, too. Just to be clear... my solution is not a quick and dirty workaround, it's an actual fix of the bug in the datepicker code. It's so long, because it overwrites an original method (and thus contains the original code in its entirety). The fix itself is a change in just one line. But I've provided the fix as a script that can just be included without having to edit the original code at all, for convenience.

$.extend(
    $.datepicker,
    {
        _generateHTML:
            function(inst) {
                if (!inst.dpuuid)
                {
                    for(attr in window)
                    {
                        if(/^DP_jQuery_/.test(attr))
                        {
                            inst.dpuuid = attr.replace(/^DP_jQuery_([0-9]+)/, '$1');
                        }
                    }
                }
                var dpuuid = inst.dpuuid;
                var today = new Date();
                today = this._daylightSavingAdjust(
                    new Date(today.getFullYear(), today.getMonth(), today.getDate())); // clear time
                var isRTL = this._get(inst, 'isRTL');
                var showButtonPanel = this._get(inst, 'showButtonPanel');
                var hideIfNoPrevNext = this._get(inst, 'hideIfNoPrevNext');
                var navigationAsDateFormat = this._get(inst, 'navigationAsDateFormat');
                var numMonths = this._getNumberOfMonths(inst);
                var showCurrentAtPos = this._get(inst, 'showCurrentAtPos');
                var stepMonths = this._get(inst, 'stepMonths');
                var isMultiMonth = (numMonths[0] != 1 || numMonths[1] != 1);
                var currentDate = this._daylightSavingAdjust((!inst.currentDay ? new Date(9999, 9, 9) :
                    new Date(inst.currentYear, inst.currentMonth, inst.currentDay)));
                var minDate = this._getMinMaxDate(inst, 'min');
                var maxDate = this._getMinMaxDate(inst, 'max');
                var drawMonth = inst.drawMonth - showCurrentAtPos;
                var drawYear = inst.drawYear;
                if (drawMonth < 0) {
                    drawMonth += 12;
                    drawYear--;
                }
                if (maxDate) {
                    var maxDraw = this._daylightSavingAdjust(new Date(maxDate.getFullYear(),
                        maxDate.getMonth() - (numMonths[0] * numMonths[1]) + 1, maxDate.getDate()));
                    maxDraw = (minDate && maxDraw < minDate ? minDate : maxDraw);
                    while (this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1)) > maxDraw) {
                        drawMonth--;
                        if (drawMonth < 0) {
                            drawMonth = 11;
                            drawYear--;
                        }
                    }
                }
                inst.drawMonth = drawMonth;
                inst.drawYear = drawYear;
                var prevText = this._get(inst, 'prevText');
                prevText = (!navigationAsDateFormat ? prevText : this.formatDate(prevText,
                    this._daylightSavingAdjust(new Date(drawYear, drawMonth - stepMonths, 1)),
                    this._getFormatConfig(inst)));
                var prev = (this._canAdjustMonth(inst, -1, drawYear, drawMonth) ?
                    '<a class="ui-datepicker-prev ui-corner-all" onclick="DP_jQuery_' + dpuuid +
                    '.datepicker._adjustDate(\'#' + inst.id + '\', -' + stepMonths + ', \'M\');"' +
                    ' title="' + prevText + '"><span class="ui-icon ui-icon-circle-triangle-' + ( isRTL ? 'e' : 'w') + '">' + prevText + '</span></a>' :
                    (hideIfNoPrevNext ? '' : '<a class="ui-datepicker-prev ui-corner-all ui-state-disabled" title="'+ prevText +'"><span class="ui-icon ui-icon-circle-triangle-' + ( isRTL ? 'e' : 'w') + '">' + prevText + '</span></a>'));
                var nextText = this._get(inst, 'nextText');
                nextText = (!navigationAsDateFormat ? nextText : this.formatDate(nextText,
                    this._daylightSavingAdjust(new Date(drawYear, drawMonth + stepMonths, 1)),
                    this._getFormatConfig(inst)));
                var next = (this._canAdjustMonth(inst, +1, drawYear, drawMonth) ?
                    '<a class="ui-datepicker-next ui-corner-all" onclick="DP_jQuery_' + dpuuid +
                    '.datepicker._adjustDate(\'#' + inst.id + '\', +' + stepMonths + ', \'M\');"' +
                    ' title="' + nextText + '"><span class="ui-icon ui-icon-circle-triangle-' + ( isRTL ? 'w' : 'e') + '">' + nextText + '</span></a>' :
                    (hideIfNoPrevNext ? '' : '<a class="ui-datepicker-next ui-corner-all ui-state-disabled" title="'+ nextText + '"><span class="ui-icon ui-icon-circle-triangle-' + ( isRTL ? 'w' : 'e') + '">' + nextText + '</span></a>'));
                var currentText = this._get(inst, 'currentText');
                var gotoDate = (this._get(inst, 'gotoCurrent') && inst.currentDay ? currentDate : today);
                currentText = (!navigationAsDateFormat ? currentText :
                    this.formatDate(currentText, gotoDate, this._getFormatConfig(inst)));
                var controls = (!inst.inline ? '<button type="button" class="ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all" onclick="DP_jQuery_' + dpuuid +
                    '.datepicker._hideDatepicker();">' + this._get(inst, 'closeText') + '</button>' : '');
                var buttonPanel = (showButtonPanel) ? '<div class="ui-datepicker-buttonpane ui-widget-content">' + (isRTL ? controls : '') +
                    (this._isInRange(inst, gotoDate) ? '<button type="button" class="ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all" onclick="DP_jQuery_' + dpuuid +
                    '.datepicker._gotoToday(\'#' + inst.id + '\');"' +
                    '>' + currentText + '</button>' : '') + (isRTL ? '' : controls) + '</div>' : '';
                var firstDay = parseInt(this._get(inst, 'firstDay'),10);
                firstDay = (isNaN(firstDay) ? 0 : firstDay);
                var showWeek = this._get(inst, 'showWeek');
                var dayNames = this._get(inst, 'dayNames');
                var dayNamesShort = this._get(inst, 'dayNamesShort');
                var dayNamesMin = this._get(inst, 'dayNamesMin');
                var monthNames = this._get(inst, 'monthNames');
                var monthNamesShort = this._get(inst, 'monthNamesShort');
                var beforeShowDay = this._get(inst, 'beforeShowDay');
                var showOtherMonths = this._get(inst, 'showOtherMonths');
                var selectOtherMonths = this._get(inst, 'selectOtherMonths');
                var calculateWeek = this._get(inst, 'calculateWeek') || this.iso8601Week;
                var defaultDate = this._getDefaultDate(inst);
                var html = '';
                for (var row = 0; row < numMonths[0]; row++) {
                    var group = '';
                    for (var col = 0; col < numMonths[1]; col++) {
                        var selectedDate = this._daylightSavingAdjust(new Date(inst.currentYear, inst.currentMonth, inst.selectedDay));
                        var cornerClass = ' ui-corner-all';
                        var calender = '';
                        if (isMultiMonth) {
                            calender += '<div class="ui-datepicker-group';
                            if (numMonths[1] > 1)
                                switch (col) {
                                    case 0: calender += ' ui-datepicker-group-first';
                                        cornerClass = ' ui-corner-' + (isRTL ? 'right' : 'left'); break;
                                    case numMonths[1]-1: calender += ' ui-datepicker-group-last';
                                        cornerClass = ' ui-corner-' + (isRTL ? 'left' : 'right'); break;
                                    default: calender += ' ui-datepicker-group-middle'; cornerClass = ''; break;
                                }
                            calender += '">';
                        }
                        calender += '<div class="ui-datepicker-header ui-widget-header ui-helper-clearfix' + cornerClass + '">' +
                            (/all|left/.test(cornerClass) && row == 0 ? (isRTL ? next : prev) : '') +
                            (/all|right/.test(cornerClass) && row == 0 ? (isRTL ? prev : next) : '') +
                            this._generateMonthYearHeader(inst, drawMonth, drawYear, minDate, maxDate,
                            row > 0 || col > 0, monthNames, monthNamesShort) + // draw month headers
                            '</div><table class="ui-datepicker-calendar"><thead>' +
                            '<tr>';
                        var thead = (showWeek ? '<th class="ui-datepicker-week-col">' + this._get(inst, 'weekHeader') + '</th>' : '');
                        for (var dow = 0; dow < 7; dow++) { // days of the week
                            var day = (dow + firstDay) % 7;
                            thead += '<th' + ((dow + firstDay + 6) % 7 >= 5 ? ' class="ui-datepicker-week-end"' : '') + '>' +
                                '<span title="' + dayNames[day] + '">' + dayNamesMin[day] + '</span></th>';
                        }
                        calender += thead + '</tr></thead><tbody>';
                        var daysInMonth = this._getDaysInMonth(drawYear, drawMonth);
                        if (drawYear == inst.selectedYear && drawMonth == inst.selectedMonth)
                            inst.selectedDay = Math.min(inst.selectedDay, daysInMonth);
                        var leadDays = (this._getFirstDayOfMonth(drawYear, drawMonth) - firstDay + 7) % 7;
                        var numRows = (isMultiMonth ? 6 : Math.ceil((leadDays + daysInMonth) / 7)); // calculate the number of rows to generate
                        var printDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1 - leadDays));
                        for (var dRow = 0; dRow < numRows; dRow++) { // create date picker rows
                            calender += '<tr>';
                            var tbody = (!showWeek ? '' : '<td class="ui-datepicker-week-col">' +
                                this._get(inst, 'calculateWeek')(printDate) + '</td>');
                            for (var dow = 0; dow < 7; dow++) { // create date picker days
                                var daySettings = (beforeShowDay ?
                                    beforeShowDay.apply((inst.input ? inst.input[0] : null), [printDate]) : [true, '']);
                                var otherMonth = (printDate.getMonth() != drawMonth);
                                var unselectable = (otherMonth && !selectOtherMonths) || !daySettings[0] ||
                                    (minDate && printDate < minDate) || (maxDate && printDate > maxDate);
                                tbody += '<td class="' +
                                    ((dow + firstDay + 6) % 7 >= 5 ? ' ui-datepicker-week-end' : '') + // highlight weekends
                                    (otherMonth ? ' ui-datepicker-other-month' : '') + // highlight days from other months
                                    ((printDate.getTime() == selectedDate.getTime() && drawMonth == inst.selectedMonth && inst._keyEvent) || // user pressed key
                                    (defaultDate.getTime() == printDate.getTime() && defaultDate.getTime() == selectedDate.getTime()) ?
                                    // or defaultDate is current printedDate and defaultDate is selectedDate
                                    ' ' + this._dayOverClass : '') + // highlight selected day
                                    (unselectable ? ' ' + this._unselectableClass + ' ui-state-disabled': '') +  // highlight unselectable days
                                    (otherMonth && !showOtherMonths ? '' : ' ' + daySettings[1] + // highlight custom dates
                                    (printDate.getTime() == currentDate.getTime() ? ' ' + this._currentClass : '') + // highlight selected day
                                    (printDate.getTime() == today.getTime() ? ' ui-datepicker-today' : '')) + '"' + // highlight today (if different)
                                    ((!otherMonth || showOtherMonths) && daySettings[2] ? ' title="' + daySettings[2] + '"' : '') + // cell title
                                    (unselectable ? '' : ' onclick="DP_jQuery_' + dpuuid + '.datepicker._selectDay(\'#' +
                                    inst.id + '\',' + printDate.getMonth() + ',' + printDate.getFullYear() + ', this);return false;"') + '>' + // actions
                                    (otherMonth && !showOtherMonths ? '&#xa0;' : // display for other months
                                    (unselectable ? '<span class="ui-state-default">' + printDate.getDate() + '</span>' : '<a class="ui-state-default' +
                                    (printDate.getTime() == today.getTime() ? ' ui-state-highlight' : '') +
                                    (printDate.getTime() == selectedDate.getTime() ? ' ui-state-active' : '') + // highlight selected day
                                    (otherMonth ? ' ui-priority-secondary' : '') + // distinguish dates from other months
                                    '" href="#">' + printDate.getDate() + '</a>')) + '</td>'; // display selectable date
                                printDate.setDate(printDate.getDate() + 1);
                                printDate = this._daylightSavingAdjust(printDate);
                            }
                            calender += tbody + '</tr>';
                        }
                        drawMonth++;
                        if (drawMonth > 11) {
                            drawMonth = 0;
                            drawYear++;
                        }
                        calender += '</tbody></table>' + (isMultiMonth ? '</div>' +
                                    ((numMonths[0] > 0 && col == numMonths[1]-1) ? '<div class="ui-datepicker-row-break"></div>' : '') : '');
                        group += calender;
                    }
                    html += group;
                }
                html += buttonPanel + ($.browser.msie && parseInt($.browser.version,10) < 7 && !inst.inline ?
                    '<iframe src="javascript:false;" class="ui-datepicker-cover" frameborder="0"></iframe>' : '');
                inst._keyEvent = false;
                return html;
            }
    }
);
Thomas
+5  A: 

here's a workaround I figured out.

$(function() {

    $("#datepicker").datepicker({
        onChangeMonthYear: function(year, month, inst) {
            var bMonth = (new Date(this.value)).getMonth() != month - 1;
            var bYear = (new Date(this.value)).getFullYear() != year;
            if (bMonth || bYear) {
            setTimeout(function() {
                $('.ui-state-active').removeClass('ui-state-active');
            }, 5);
            }
        }
    });
});​

crazy demo

Reigel
you can see it deselect the day when switching
Natrium
A: 

Here's the ticket:

http://dev.jqueryui.com/ticket/5984

It includes the fix and a workaround for the compressed version.

I think you can modify your copy of jQuery UI safely. The issue is already solved so it should show up in next stable release.

Álvaro G. Vicario