User:Kxx/comments in local time.js

/*    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);})();