User:Kxx/comments in local time.js

From Wikipedia, the free encyclopedia
Note: After saving, you have to bypass your browser's cache to see the changes. Google Chrome, Firefox, Microsoft Edge and Safari: Hold down the ⇧ Shift key and click the Reload toolbar button. For details and instructions about other browsers, see Wikipedia:Bypass your cache.
/*
    COMMENTS IN LOCAL TIME
    Description: Changes [[Coordinated Universal Time|UTC]]-based times and dates, such as those used in signatures, to be relative to local time.
    Documentation: [[Wikipedia:Comments in Local Time]]
    Source: [[User:Gary King/comments in local time.js]]  
*/

(function(undefined) {
    var window = this, document = window.document;
    switch (window.mw.config.get('wgCanonicalNamespace')) {
    case '':
    case 'MediaWiki':
    case 'Special':
        return;
    }
    if (window.mw.config.get('wgAction') === 'history')
        return;
    var addLeadingZero = function(number) {
            return number < 10 ? '0' + number : number;
        },
        convertMonthToNumber = {
            January: 0, Jan: 0,
            February: 1, Feb: 1,
            March: 2, Mar: 2,
            April: 3, Apr: 3,
            May: 4,
            June: 5, Jun: 5,
            July: 6, Jul: 6,
            August: 7, Aug: 7,
            September: 8, Sep: 8,
            October: 9, Oct: 9,
            November: 10, Nov: 10,
            December: 11, Dec: 11
        },
        convertNumberToMonth = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
        dayNames = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
        Date = window.Date,
        Math = window.Math,
        parseInt = window.parseInt,
        pluralize = function(term, count) {
            return count === 1 ? term : term + 's';
        },
        search = /(\d\d):(\d\d), (\d{1,2}) ([A-Z][a-z]+) (\d{4}) \(UTC\)/g,
        today = new Date(new Date().toDateString()),
        adjustTime = function(matches) {
            // set the date entered
            var time = new Date(Date.UTC(parseInt(matches[5]), convertMonthToNumber[matches[4]], parseInt(matches[3]), parseInt(matches[1]), parseInt(matches[2])));

            // determine the time offset
            var utcOffset = today.getTimezoneOffset() / -60;
            utcOffset = utcOffset >= 0 ? '+' + utcOffset : '−' + -utcOffset;

            // set the date bits to output
            var year = time.getFullYear();
            var month = time.getMonth();
            var day = time.getDate();
            var hour = time.getHours();
            var minute = time.getMinutes();

            // output am or pm depending on the date
            var ampm = hour <= 11 ? ' am' : ' pm';
            if (hour > 12)
                hour -= 12;
            else if (hour === 0)
                hour = 12;

            // return 'today', 'yesterday' or 'tomorrow' if that is the case
            var oldDate = new Date(year, month, day), date;
            switch (Math.round((oldDate.getTime() - today.getTime()) / 8.64e7)) {
            case -1:
                date = 'yesterday';
                break;
            case 0:
                date = 'today';
                break;
            case 1:
                date = 'tomorrow';
                break;
            default:
                var newDate = new Date(today);

                // calculate time difference from today
                var daysDiff = Math.round((newDate.getTime() - oldDate.getTime()) / 8.64e7);

                var differenceWord, last = '';
                if (daysDiff >= 0) {
                    differenceWord = 'ago';
                    if (daysDiff <= 7)
                        last = 'last ';
                } else {
                    differenceWord = 'from now';
                    if (daysDiff > -7)
                        last = 'this ';
                    var tmpDate = newDate;
                    newDate = oldDate;
                    oldDate = tmpDate;
                }

                var newYear = newDate.getFullYear(), newMonth = newDate.getMonth(), newDay = newDate.getDate();
                var oldTime = oldDate.getTime(), oldYear = oldDate.getFullYear(), oldMonth = oldDate.getMonth();
                var yearsAgo = newYear - oldYear;
                if (new Date(oldYear, newMonth, newDay).getTime() < oldTime)
                    --yearsAgo;
                var monthsAgo = ((newYear - yearsAgo) * 12 + newMonth) - (oldYear * 12 + oldMonth);
                if (new Date(newYear - yearsAgo, newMonth - monthsAgo, newDay).getTime() < oldTime)
                    --monthsAgo;
                var daysAgo = Math.round((new Date(newYear - yearsAgo, newMonth - monthsAgo, newDay).getTime() - oldTime) / 8.64e7);

                var descriptiveParts = [];
                if (yearsAgo > 0)
                    descriptiveParts.push(yearsAgo + ' ' + pluralize('year', yearsAgo));
                if (monthsAgo > 0)
                    descriptiveParts.push(monthsAgo + ' ' + pluralize('month', monthsAgo));
                if (daysAgo > 0)
                    descriptiveParts.push(daysAgo + ' ' + pluralize('day', daysAgo));

                var descriptiveDifference = ' (' + descriptiveParts.join(', ') + ' ' + differenceWord + ')';
                var formattedDate = convertNumberToMonth[month] + ' ' + day + ', ' + year;
                var formattedDayOfTheWeek = ', ' + last + dayNames[time.getDay()];
                date = formattedDate + formattedDayOfTheWeek + descriptiveDifference;
            }

            var finalTime = hour + ':' + addLeadingZero(minute) + ampm;
            var returnDate = finalTime + ', ' + date + ' (UTC' + utcOffset + ')';

            return returnDate;
        },
        replaceText = function(root) {
            var stack = [root], textNodes = [];
            do {
                for (var child = stack.pop().firstChild; child; child = child.nextSibling)
                    if (child.nodeType === 1)
                        stack.push(child);
                    else if (child.nodeType === 3)
                        textNodes.push(child);
            } while (stack.length !== 0);

            for (var i = 0, length = textNodes.length; i < length; ++i) {
                var node = textNodes[i], value = node.textContent;

                var match = search.exec(value);
                if (!match)
                    continue;

                var fragment = document.createDocumentFragment(), lastIndex = 0;

                do {
                    fragment.appendChild(document.createTextNode(value.substring(lastIndex, match.index)));
                    lastIndex = search.lastIndex;
                    var span = document.createElement('span');
                    span.className = 'localcomments';
                    span.title = match[0];
                    span.textContent = adjustTime(match);
                    fragment.appendChild(span);
                    match = search.exec(value);
                } while (match);

                fragment.appendChild(document.createTextNode(value.substr(lastIndex)));

                node.parentNode.replaceChild(fragment, node);
            }
        };

    var topContainer = document.getElementById('wikiPreview');
    if (!topContainer && window.mw.config.get('wgAction') === 'view')
        topContainer = document.getElementById('mw-content-text') || document.getElementById('bodyContent');

    if (topContainer)
        replaceText(topContainer);
})();