Skip to content
Extraits de code Groupes Projets
calendar.js 22,3 ko
Newer Older
  • Learn to ignore specific revisions
  • robocoder's avatar
    robocoder a validé
    /*!
    
     * Piwik - free/libre analytics platform
    
    robocoder's avatar
    robocoder a validé
     *
     * @link http://piwik.org
     * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
     */
    
    (function ($) {
    
        Date.prototype.getWeek = function () {
            var onejan = new Date(this.getFullYear(), 0, 1), // needed for getDay()
    
            // use UTC times since getTime() can differ based on user's timezone
                onejan_utc = Date.UTC(this.getFullYear(), 0, 1),
                this_utc = Date.UTC(this.getFullYear(), this.getMonth(), this.getDate()),
    
                daysSinceYearStart = (this_utc - onejan_utc) / 86400000; // constant is millisecs in one day
    
            return Math.ceil((daysSinceYearStart + onejan.getDay()) / 7);
    
    
        var currentYear, currentMonth, currentDay, currentDate, currentWeek;
    
        function setCurrentDate(dateStr) {
            var splitDate = dateStr.split("-");
            currentYear = splitDate[0];
            currentMonth = splitDate[1] - 1;
            currentDay = splitDate[2];
            currentDate = new Date(currentYear, currentMonth, currentDay);
            currentWeek = currentDate.getWeek();
        }
    
    
        if(!piwik.currentDateString) {
            // eg. Login form
            return;
        }
    
        setCurrentDate(piwik.currentDateString);
    
        var todayDate = new Date;
        var todayMonth = todayDate.getMonth();
        var todayYear = todayDate.getFullYear();
        var todayDay = todayDate.getDate();
    
    mattpiwik's avatar
    mattpiwik a validé
    
    
        var piwikMinDate = new Date(piwik.minDateYear, piwik.minDateMonth - 1, piwik.minDateDay),
            piwikMaxDate = new Date(piwik.maxDateYear, piwik.maxDateMonth - 1, piwik.maxDateDay);
    
        var selectedPeriod = piwik.period;
    
        function isDateInCurrentPeriod(date) {
            // if the selected period isn't the current period, don't highlight any dates
            if (selectedPeriod != piwik.period) {
                return [true, ''];
            }
    
            var valid = false;
    
            var dateMonth = date.getMonth();
            var dateYear = date.getFullYear();
            var dateDay = date.getDate();
    
            // we don't color dates in the future
            if (dateMonth == todayMonth
                && dateYear == todayYear
                && dateDay > todayDay
                ) {
                return [true, ''];
            }
    
            // we don't color dates before the minimum date
            if (dateYear < piwik.minDateYear
                || ( dateYear == piwik.minDateYear
                &&
                (
                    (dateMonth == piwik.minDateMonth - 1
                        && dateDay < piwik.minDateDay)
                        || (dateMonth < piwik.minDateMonth - 1)
                    )
                )
                ) {
                return [true, ''];
            }
    
            // we color all day of the month for the same year for the month period
            if (piwik.period == "month"
                && dateMonth == currentMonth
                && dateYear == currentYear
                ) {
                valid = true;
            }
            // we color all day of the year for the year period
            else if (piwik.period == "year"
                && dateYear == currentYear
                ) {
                valid = true;
            }
            else if (piwik.period == "week"
                && date.getWeek() == currentWeek
                && dateYear == currentYear
                ) {
                valid = true;
            }
            else if (piwik.period == "day"
                && dateDay == currentDay
                && dateMonth == currentMonth
                && dateYear == currentYear
                ) {
                valid = true;
            }
    
            if (valid) {
                return [true, 'ui-datepicker-current-period'];
            }
    
            return [true, ''];
        }
    
        piwik.getBaseDatePickerOptions = function (defaultDate) {
            return {
                showOtherMonths: false,
                dateFormat: 'yy-mm-dd',
                firstDay: 1,
                minDate: piwikMinDate,
                maxDate: piwikMaxDate,
                prevText: "",
                nextText: "",
                currentText: "",
                defaultDate: defaultDate,
                changeMonth: true,
                changeYear: true,
                stepMonths: 1,
                // jquery-ui-i18n 1.7.2 lacks some translations, so we use our own
                dayNamesMin: [
    
                    _pk_translate('Intl_Day_Min_StandAlone_7'),
                    _pk_translate('Intl_Day_Min_StandAlone_1'),
                    _pk_translate('Intl_Day_Min_StandAlone_2'),
                    _pk_translate('Intl_Day_Min_StandAlone_3'),
                    _pk_translate('Intl_Day_Min_StandAlone_4'),
                    _pk_translate('Intl_Day_Min_StandAlone_5'),
                    _pk_translate('Intl_Day_Min_StandAlone_6')],
    
                    _pk_translate('Intl_Day_Short_StandAlone_7'), // start with sunday
                    _pk_translate('Intl_Day_Short_StandAlone_1'),
                    _pk_translate('Intl_Day_Short_StandAlone_2'),
                    _pk_translate('Intl_Day_Short_StandAlone_3'),
                    _pk_translate('Intl_Day_Short_StandAlone_4'),
                    _pk_translate('Intl_Day_Short_StandAlone_5'),
                    _pk_translate('Intl_Day_Short_StandAlone_6')],
    
                    _pk_translate('Intl_Day_Long_StandAlone_7'), // start with sunday
                    _pk_translate('Intl_Day_Long_StandAlone_1'),
                    _pk_translate('Intl_Day_Long_StandAlone_2'),
                    _pk_translate('Intl_Day_Long_StandAlone_3'),
                    _pk_translate('Intl_Day_Long_StandAlone_4'),
                    _pk_translate('Intl_Day_Long_StandAlone_5'),
                    _pk_translate('Intl_Day_Long_StandAlone_6')],
    
                    _pk_translate('Intl_Month_Short_StandAlone_1'),
                    _pk_translate('Intl_Month_Short_StandAlone_2'),
                    _pk_translate('Intl_Month_Short_StandAlone_3'),
                    _pk_translate('Intl_Month_Short_StandAlone_4'),
                    _pk_translate('Intl_Month_Short_StandAlone_5'),
                    _pk_translate('Intl_Month_Short_StandAlone_6'),
                    _pk_translate('Intl_Month_Short_StandAlone_7'),
                    _pk_translate('Intl_Month_Short_StandAlone_8'),
                    _pk_translate('Intl_Month_Short_StandAlone_9'),
                    _pk_translate('Intl_Month_Short_StandAlone_10'),
                    _pk_translate('Intl_Month_Short_StandAlone_11'),
                    _pk_translate('Intl_Month_Short_StandAlone_12')],
    
                    _pk_translate('Intl_Month_Long_StandAlone_1'),
                    _pk_translate('Intl_Month_Long_StandAlone_2'),
                    _pk_translate('Intl_Month_Long_StandAlone_3'),
                    _pk_translate('Intl_Month_Long_StandAlone_4'),
                    _pk_translate('Intl_Month_Long_StandAlone_5'),
                    _pk_translate('Intl_Month_Long_StandAlone_6'),
                    _pk_translate('Intl_Month_Long_StandAlone_7'),
                    _pk_translate('Intl_Month_Long_StandAlone_8'),
                    _pk_translate('Intl_Month_Long_StandAlone_9'),
                    _pk_translate('Intl_Month_Long_StandAlone_10'),
                    _pk_translate('Intl_Month_Long_StandAlone_11'),
                    _pk_translate('Intl_Month_Long_StandAlone_12')]
    
            };
        };
    
        var updateDate;
    
        function getDatePickerOptions() {
            var result = piwik.getBaseDatePickerOptions(currentDate);
            result.beforeShowDay = isDateInCurrentPeriod;
            result.stepMonths = selectedPeriod == 'year' ? 12 : 1;
            result.onSelect = function () { updateDate.apply(this, arguments); };
            return result;
    
    
            var datepickerElem = $('#datepicker').datepicker(getDatePickerOptions()),
    
    sgiehl's avatar
    sgiehl a validé
                periodLabels = $('#periodString').find('.period-type label'),
                periodTooltip = $('#periodString').find('.period-click-tooltip').html();
    
    
            var toggleWhitespaceHighlighting = function (klass, toggleTop, toggleBottom) {
                var viewedYear = $('.ui-datepicker-year', datepickerElem).val(),
                    viewedMonth = +$('.ui-datepicker-month', datepickerElem).val(), // convert to int w/ '+'
                    firstOfViewedMonth = new Date(viewedYear, viewedMonth, 1),
                    lastOfViewedMonth = new Date(viewedYear, viewedMonth + 1, 0);
    
                // only highlight dates between piwik.minDate... & piwik.maxDate...
                // we select the cells to highlight by checking whether the first & last of the
                // currently viewed month are within the min/max dates.
                if (firstOfViewedMonth >= piwikMinDate) {
                    $('tbody>tr:first-child td.ui-datepicker-other-month', datepickerElem).toggleClass(klass, toggleTop);
                }
                if (lastOfViewedMonth < piwikMaxDate) {
                    $('tbody>tr:last-child td.ui-datepicker-other-month', datepickerElem).toggleClass(klass, toggleBottom);
                }
            };
    
            // 'this' is the table cell
            var highlightCurrentPeriod = function () {
                switch (selectedPeriod) {
                    case 'day':
                        // highlight this link
                        $('a', $(this)).addClass('ui-state-hover');
                        break;
                    case 'week':
                        var row = $(this).parent();
    
                        // highlight parent row (the week)
                        $('a', row).addClass('ui-state-hover');
    
                        // toggle whitespace if week goes into previous or next month. we check if week is on
                        // top or bottom row.
                        var toggleTop = row.is(':first-child'),
                            toggleBottom = row.is(':last-child');
                        toggleWhitespaceHighlighting('ui-state-hover', toggleTop, toggleBottom);
                        break;
                    case 'month':
                        // highlight all parent rows (the month)
                        $('a', $(this).parent().parent()).addClass('ui-state-hover');
                        break;
                    case 'year':
                        // highlight table (month + whitespace)
                        $('a', $(this).parent().parent()).addClass('ui-state-hover');
                        toggleWhitespaceHighlighting('ui-state-hover', true, true);
                        break;
                }
            };
    
            var unhighlightAllDates = function () {
                // make sure nothing is highlighted
                $('.ui-state-active,.ui-state-hover', datepickerElem).removeClass('ui-state-active ui-state-hover');
    
                // color whitespace
                if (piwik.period == 'year') {
                    var viewedYear = $('.ui-datepicker-year', datepickerElem).val(),
                        toggle = selectedPeriod == 'year' && currentYear == viewedYear;
                    toggleWhitespaceHighlighting('ui-datepicker-current-period', toggle, toggle);
                }
                else if (piwik.period == 'week') {
                    var toggleTop = $('tr:first-child a', datepickerElem).parent().hasClass('ui-datepicker-current-period'),
                        toggleBottom = $('tr:last-child a', datepickerElem).parent().hasClass('ui-datepicker-current-period');
                    toggleWhitespaceHighlighting('ui-datepicker-current-period', toggleTop, toggleBottom);
                }
            };
    
            updateDate = function (dateText) {
                piwikHelper.showAjaxLoading('ajaxLoadingCalendar');
    
                // select new dates in calendar
                setCurrentDate(dateText);
                piwik.period = selectedPeriod;
    
                // make sure it's called after jquery-ui is done, otherwise everything we do will
                // be undone.
                setTimeout(unhighlightAllDates, 1);
    
                datepickerElem.datepicker('refresh');
    
                // Let broadcast do its job:
                // It will replace date value to both search query and hash and load the new page.
    
    sgiehl's avatar
    sgiehl a validé
                broadcast.propagateNewPage('date=' + dateText + '&period=' + selectedPeriod);
    
            };
    
            var toggleMonthDropdown = function (disable) {
                if (typeof disable === 'undefined') {
                    disable = selectedPeriod == 'year';
                }
    
                // enable/disable month dropdown based on period == year
                $('.ui-datepicker-month', datepickerElem).attr('disabled', disable);
            };
    
            var togglePeriodPickers = function (showSingle) {
    
    Thomas ZILLIOX's avatar
    Thomas ZILLIOX a validé
                $('#periodString').find('.period-date').toggle(showSingle);
                $('#periodString').find('.period-range').toggle(!showSingle);
    
            };
    
            //
            // setup datepicker
            //
    
            unhighlightAllDates();
    
            //
            // hook up event slots
            //
    
            // highlight current period when mouse enters date
            datepickerElem.on('mouseenter', 'tbody td', function () {
                if ($(this).hasClass('ui-state-hover')) // if already highlighted, do nothing
                {
                    return;
                }
    
                // unhighlight if cell is disabled/blank, unless the period is year
                if ($(this).hasClass('ui-state-disabled') && selectedPeriod != 'year') {
                    unhighlightAllDates();
    
                    // if period is week, then highlight the current week
                    if (selectedPeriod == 'week') {
                        highlightCurrentPeriod.call(this);
                    }
                }
                else {
                    highlightCurrentPeriod.call(this);
                }
            });
    
            // make sure cell stays highlighted when mouse leaves cell (overrides jquery-ui behavior)
            datepickerElem.on('mouseleave', 'tbody td', function () {
                $('a', this).addClass('ui-state-hover');
            });
    
            // unhighlight everything when mouse leaves table body (can't do event on tbody, for some reason
            // that fails, so we do two events, one on the table & one on thead)
            datepickerElem.on('mouseleave', 'table', unhighlightAllDates)
                .on('mouseenter', 'thead', unhighlightAllDates);
    
            // make sure whitespace is clickable when the period makes it appropriate
            datepickerElem.on('click', 'tbody td.ui-datepicker-other-month', function () {
                if ($(this).hasClass('ui-state-hover')) {
                    var row = $(this).parent(), tbody = row.parent();
    
                    if (row.is(':first-child')) {
                        // click on first of the month
                        $('a', tbody).first().click();
                    }
                    else {
                        // click on last of month
                        $('a', tbody).last().click();
                    }
                }
            });
    
            var reloading = false;
    
    
            var changePeriodWithPageReload = function (periodInput) {
                var url = periodInput.val(),
                    period = broadcast.getValueFromUrl('period', url);
    
                // if clicking on the selected period, change the period but not the date
                if (period != 'range' && !reloading) {
                    // only reload if current period is different from selected
                    reloading = true;
                    selectedPeriod = period;
                    updateDate(piwik.currentDateString);
                    return true;
                }
    
                return false;
            };
    
            var changePeriodOnClickIfPeriodChanged = function (periodInput) {
    
                if (reloading) // if a click event resulted in reloading, don't reload again
                {
                    return;
                }
    
                var url = periodInput.val(),
                    period = broadcast.getValueFromUrl('period', url);
    
                // if clicking on the selected period, change the period but not the date
                if (selectedPeriod == period && selectedPeriod != 'range') {
                    // only reload if current period is different from selected
    
                    if (piwik.period != selectedPeriod) {
                        return changePeriodWithPageReload(periodInput);
    
            $("#otherPeriods").find("label,input").on('dblclick', function (e) {
    
                var id = $(e.target).attr('for');
    
                changePeriodOnClickIfPeriodChanged($('#' + id));
    
            $("#otherPeriods").find("label,input").on('dblclick', function (e) {
                var id = $(e.target).attr('for');
    
                changePeriodOnClickIfPeriodChanged($('#' + id));
    
            });
    
            // Apply date range button will reload the page with the selected range
            $('#calendarApply')
                .on('click', function () {
                    var $selectedPeriod = $('#periodMore [name=period]:checked');
    
                    if (!$selectedPeriod.is('#period_id_range')) {
    
                        changePeriodWithPageReload($selectedPeriod);
    
                        return true;
                    }
    
                    var dateFrom = $('#inputCalendarFrom').val(),
                        dateTo = $('#inputCalendarTo').val(),
                        oDateFrom = $.datepicker.parseDate('yy-mm-dd', dateFrom),
                        oDateTo = $.datepicker.parseDate('yy-mm-dd', dateTo);
    
                    if (!isValidDate(oDateFrom)
                        || !isValidDate(oDateTo)
                        || oDateFrom > oDateTo) {
                        $('#alert').find('h2').text(_pk_translate('General_InvalidDateRange'));
                        piwikHelper.modalConfirm('#alert', {});
                        return false;
                    }
                    piwikHelper.showAjaxLoading('ajaxLoadingCalendar');
                    broadcast.propagateNewPage('period=range&date=' + dateFrom + ',' + dateTo);
                })
                .show();
    
    
    
    
            // when non-range period is clicked, change the period & refresh the date picker
    
    Thomas ZILLIOX's avatar
    Thomas ZILLIOX a validé
            $("#otherPeriods").find("input").on('click', function (e) {
    
                var request_URL = $(e.target).val(),
                    period = broadcast.getValueFromUrl('period', request_URL),
                    lastPeriod = selectedPeriod;
    
    
                if (changePeriodOnClickIfPeriodChanged($(e.target))) {
    
                    return true;
                }
    
                // switch the selected period
                selectedPeriod = period;
    
                // remove tooltips from the period inputs
                periodLabels.each(function () { $(this).attr('title', '').removeClass('selected-period-label'); });
    
                // range periods are handled in an event handler below
                if (period == 'range') {
                    return true;
                }
    
                // set the tooltip of the current period
                if (period != piwik.period) // don't add tooltip for current period
                {
                    $(this).parent().find('label[for=period_id_' + period + ']')
                        .attr('title', periodTooltip).addClass('selected-period-label');
                }
    
                // toggle the right selector controls (show period selector datepicker & hide 'apply range' button)
                togglePeriodPickers(true);
    
                // set months step to 12 for year period (or set back to 1 if leaving year period)
                if (selectedPeriod == 'year' || lastPeriod == 'year') {
                    // setting stepMonths will change the month in view back to the selected date. to avoid
                    // we set the selected date to the month in view.
                    var currentMonth = $('.ui-datepicker-month', datepickerElem).val(),
                        currentYear = $('.ui-datepicker-year', datepickerElem).val();
    
                    datepickerElem
                        .datepicker('option', 'stepMonths', selectedPeriod == 'year' ? 12 : 1)
                        .datepicker('setDate', new Date(currentYear, currentMonth));
                }
    
                datepickerElem.datepicker('refresh'); // must be last datepicker call, otherwise cells get highlighted
    
                unhighlightAllDates();
                toggleMonthDropdown();
    
                return true;
            });
    
            // clicking left/right re-enables the month dropdown, so we disable it again
            $(datepickerElem).on('click', '.ui-datepicker-next,.ui-datepicker-prev', function () {
                unhighlightAllDates(); // make sure today's date isn't highlighted & toggle extra year highlighting
                toggleMonthDropdown(selectedPeriod == 'year');
            });
    
            function onDateRangeSelect(dateText, inst) {
                var toOrFrom = inst.id == 'calendarFrom' ? 'From' : 'To';
                $('#inputCalendar' + toOrFrom).val(dateText);
            }
    
            // this will trigger to change only the period value on search query and hash string.
            $("#period_id_range").on('click', function (e) {
                togglePeriodPickers(false);
    
                var options = getDatePickerOptions();
    
                // Custom Date range callback
                options.onSelect = onDateRangeSelect;
                // Do not highlight the period
                options.beforeShowDay = '';
                // Create both calendars
                options.defaultDate = piwik.startDateString;
                $('#calendarFrom').datepicker(options).datepicker("setDate", $.datepicker.parseDate('yy-mm-dd', piwik.startDateString));
    
                // Technically we should trigger the onSelect event on the calendar, but I couldn't find how to do that
                // So calling the onSelect bind function manually...
                //$('#calendarFrom').trigger('dateSelected'); // or onSelect
                onDateRangeSelect(piwik.startDateString, { "id": "calendarFrom" });
    
                // Same code for the other calendar
                options.defaultDate = piwik.endDateString;
                $('#calendarTo').datepicker(options).datepicker("setDate", $.datepicker.parseDate('yy-mm-dd', piwik.endDateString));
                onDateRangeSelect(piwik.endDateString, { "id": "calendarTo" });
    
                // If not called, the first date appears light brown instead of dark brown
                $('.ui-state-hover').removeClass('ui-state-hover');
    
                // Bind the input fields to update the calendar's date when date is manually changed
                $('#inputCalendarFrom, #inputCalendarTo')
                    .keyup(function (e) {
                        var fromOrTo = this.id == 'inputCalendarFrom' ? 'From' : 'To';
                        var dateInput = $(this).val();
                        try {
                            var newDate = $.datepicker.parseDate('yy-mm-dd', dateInput);
                        } catch (e) {
                            return;
                        }
                        $("#calendar" + fromOrTo).datepicker("setDate", newDate);
                        if (e.keyCode == 13) {
    
                            $('#calendarApply').click();
    
                        }
                    });
                return true;
            });
            function isValidDate(d) {
                if (Object.prototype.toString.call(d) !== "[object Date]")
                    return false;
                return !isNaN(d.getTime());
            }
    
    
            if (piwik.period == 'range') {