Участник:Александр Дмитриев/comments in local time ru test.js

Материал из Википедии — свободной энциклопедии
/*
  COMMENTS IN LOCAL TIME RU
  Основной автор: http://en.wikipedia.org/wiki/User:Gary_King
  Русская локализация: http://ru.wikipedia.org/wiki/Участник:Александр_Дмитриев
  Основано на английской версии, сохранённой 03:14, 17 апреля 2010 (UTC)
  Документация: http://ru.wikipedia.org/wiki/Участник:Александр_Дмитриев/comments_in_local_time_ru
*/

$(function()
{
  var language = 
  {
    // относительные понятия
    'The Day Before Yesterday' : 'позавчера',
    'Yesterday'                : 'вчера',
    'Today'                    : 'сегодня',

    // названия месяцев в обоих направлениях
    'January'   : 'января',
    'February'  : 'февраля',
    'March'     : 'марта',
    'April'     : 'апреля',
    'May'       : 'мая',
    'June'      : 'июня',
    'July'      : 'июля',
    'August'    : 'августа',
    'September' : 'сентября',
    'October'   : 'октября',
    'November'  : 'ноября',
    'December'  : 'декабря',

    'Январь'   : 'January',
    'Февраль'  : 'February',
    'Март'     : 'March',
    'Апрель'   : 'April',
    'Май'      : 'May',
    'Июнь'     : 'June',
    'Июль'     : 'July',
    'Август'   : 'August',
    'Сентябрь' : 'September',
    'Октябрь'  : 'October',
    'Ноябрь'   : 'November',
    'Декабрь'  : 'December',

    'Янв' : 'January',
    'Фев' : 'February',
    'Мар' : 'March',
    'Апр' : 'April',
    'Май' : 'May',
    'Июн' : 'June',
    'Июл' : 'July',
    'Авг' : 'August',
    'Сен' : 'September',
    'Окт' : 'October',
    'Ноя' : 'November',
    'Дек' : 'December',

    'янв' : 'January',
    'фев' : 'February',
    'мар' : 'March',
    'апр' : 'April',
    'май' : 'May',
    'июн' : 'June',
    'июл' : 'July',
    'авг' : 'August',
    'сен' : 'September',
    'окт' : 'October',
    'ноя' : 'November',
    'дек' : 'December',

    'января'   : 'January',
    'февраля'  : 'February',
    'марта'    : 'March',
    'апреля'   : 'April',
    'мая'      : 'May',
    'июня'     : 'June',
    'июля'     : 'July',
    'августа'  : 'August',
    'сентября' : 'September',
    'октября'  : 'October',
    'ноября'   : 'November',
    'декабря'  : 'December',

    // фразы, использующиеся при описании разницы
    'ago'      : '%period% назад',
    'from now' : 'через %period%',

    // единицы времени, использующиеся при описании разницы
    'year'    : 'год',
    'years1'  : 'года',
    'years2'  : 'лет',
    'month'   : 'месяц',
    'months1' : 'месяца',
    'months2' : 'месяцев',
    'day'     : 'день',
    'days1'   : 'дня',
    'days2'   : 'дней'
  };

  // настройки по умолчаннию
  if (typeof(LocalComments) == 'undefined')
    LocalComments = {};
  if (typeof(LocalComments.timeFirst) == 'undefined')
    LocalComments.timeFirst = true;
  if (typeof(LocalComments.dateFormat) == 'undefined')
    LocalComments.dateFormat = 'd m y';
  if (typeof(LocalComments.dateDifference) == 'undefined')
    LocalComments.dateDifference = false;

  if (mw.config.get('wgCanonicalNamespace') == '' || mw.config.get('wgCanonicalNamespace') == 'MediaWiki'
      || mw.config.get('wgCanonicalNamespace') == 'Special')
    return;
  var disabled_urls = new Array('action=history'), unique_url = false,
      wikiPreview = new Array('action=edit', 'action=submit');
  for (var i = 0; i < disabled_urls.length; i++)
  {
    if (document.location.href.indexOf(disabled_urls[i]) != -1)
      return;
  }
  for (var i = 0; i < wikiPreview.length; i++)
  {
    if (document.location.href.indexOf(wikiPreview[i]) != -1)
      unique_url = 'wikiPreview';
  }
  var element_id = unique_url ? unique_url : 'bodyContent';
  replace_text(document.getElementById(element_id), /(\d\d):(\d\d), (\d{1,2}) ([А-я]+) (\d{4}) \(UTC\)/g, adjust_time);

  function add_leading_zero(number)
  {
    if (number < 10)
      number = '0' + number;
    return number;
  }

  function adjust_time(original_timestamp, old_hour, old_minute, old_day, old_month, old_year, offset)
  {
    console.log("CILTRU: Entering adjust_time() function...");
    console.log("CILTRU: Arguments:");
    console.log("CILTRU:     original_timestamp", original_timestamp);
    console.log("CILTRU:     old_hour", old_hour, "old_minute", old_minute);
    console.log("CILTRU:     old_day", old_day, "old_month", old_month, "old_year", old_year);
    var today = new Date();

    // установить time равным старой дате
    var time = new Date();
    console.log("CILTRU: Assigning time", time.toString());
    console.log("CILTRU: Computing convert_month_to_number(old_month)", convert_month_to_number(old_month));
    time.setUTCFullYear(old_year, convert_month_to_number(old_month), old_day);
    console.log("CILTRU: Calling time.setUTCFullYear(). time", time.toString());
    time.setUTCHours(old_hour);
    console.log("CILTRU: Calling time.setUTCHours(). time", time.toString());
    time.setUTCMinutes(old_minute);
    console.log("CILTRU: Calling time.setUTCMinutes(). time", time.toString());

    // выяснить разницу с UTC
    console.log("CILTRU: Computing time.getTimezoneOffset()", time.getTimezoneOffset());
    var utc_offset = -1 * time.getTimezoneOffset() / 60;
    console.log("CILTRU: Assigning utc_offset", utc_offset);
    if (utc_offset >= 0)
    {
      utc_offset = '+' + utc_offset;
      console.log("CILTRU: utc_offset >= 0, so assigning utc_offset", utc_offset);
    }
    else
    {
      utc_offset = '−' + Math.abs(utc_offset);
      console.log("CILTRU: utc_offset < 0, so assigning utc_offset", utc_offset);
    }

    // расчёт элементов новой даты
    var year = time.getFullYear(), month = time.getMonth() + 1;
    var day = time.getDate();
    console.log("CILTRU: Assigning year", year, "month", month, "day", day);
    var hour = parseInt(time.getHours()), minute = time.getMinutes();
    console.log("CILTRU: Assigning hour", hour, "minute", minute);

    if (LocalComments.dateDifference)
    {
      // расчёт разницы c сегодняшним днём
      today = new Date(today.getYear(), today.getMonth(), today.getDate());
      time = new Date(time.getYear(), time.getMonth(), time.getDate());
      var difference, difference_phrase = '';
      if (today.valueOf() >= time.valueOf())
      {
        difference = new Date(today.valueOf() - time.valueOf());
        difference_phrase = language['ago'];
      }
      else
      {
        difference = new Date(time.valueOf() - today.valueOf());
        difference_phrase = language['from now'];
      }
      var descriptive_difference = '';
      if (difference.getYear() - 70 > 0)
        descriptive_difference = (difference.getYear() - 70) + ' ' + pluralize(difference.getYear() - 70,
            language['year'], language['years1'], language['years2']);
      else if (difference.getMonth() > 0)
        descriptive_difference = difference.getMonth() + ' ' + pluralize(difference.getMonth(),
            language['month'], language['months1'], language['months2']);
      else if (difference.getDate() - 1 > 2)
        descriptive_difference = (difference.getDate() - 1) + ' ' + pluralize(difference.getDate() - 1,
            language['day'], language['days1'], language['days2']);
      if (difference.getYear() - 70 > 0 || difference.getMonth() > 0 || difference.getDate() - 1 > 2)
        descriptive_difference = difference_phrase.replace("%period%", descriptive_difference);
      else if (difference.getDate() - 1 == 0)
        descriptive_difference = language['Today'];
      else if (difference.getDate() - 1 == 1)
        descriptive_difference = language['Yesterday'];
      else if (difference.getDate() - 1 == 2)
        descriptive_difference = language['The Day Before Yesterday'];
      descriptive_difference = ' (' + descriptive_difference + ')';
    }
    else
      descriptive_difference = '';
    console.log("CILTRU: Assigning descriptive_difference", descriptive_difference);

    // форматировать дату в соответствии с настройками пользователя
    var formatted_date = '', month_name = convert_number_to_month(time.getMonth());
    console.log("CILTRU: Assigning month_name", month_name);
    switch (LocalComments.dateFormat.toLowerCase())
    {
      case 'd.m.y':
        formatted_date = add_leading_zero(day) + '.' + add_leading_zero(month) + '.' + year;
        console.log("CILTRU: dateFormat == d.m.y, so assigning formatted_date", formatted_date);
        break;
      case 'd-m-y':
        formatted_date = add_leading_zero(day) + '-' + add_leading_zero(month) + '-' + year;
        console.log("CILTRU: dateFormat == d-m-y, so assigning formatted_date", formatted_date);
        break;
      default:
        formatted_date = day + ' ' + month_name + ' ' + year;
        console.log("CILTRU: dateFormat == d m y, so assigning formatted_date", formatted_date);
    }

    var date = formatted_date + descriptive_difference;
    console.log("CILTRU: Assigning date", date);

    var time = add_leading_zero(hour) + ':' + add_leading_zero(minute);
    console.log("CILTRU: Assigning time", time);

    if (LocalComments.timeFirst)
    {
      var return_date = time + ', ' + date + ' (UTC' + utc_offset + ')';
      console.log("CILTRU: timeFirst, so assigning return_date", return_date);
    }
    else
    {
      var return_date = date + ', ' + time + ' (UTC' + utc_offset + ')';
      console.log("CILTRU: !timeFirst, so assigning return_date", return_date);
    }

    console.log("CILTRU: Exiting adjust_time() function...");
    return return_date;
  }

  function convert_month_to_number(month)
  {
    var output = new Date(language[month] + ' 1, 2001');
    return output.getMonth();
  }

  function convert_number_to_month(number)
  {
    var month = new Array(language['January'], language['February'], language['March'],
        language['April'], language['May'], language['June'],
        language['July'], language['August'], language['September'],
        language['October'], language['November'], language['December']);
    return month[number];
  }

  function pluralize(count, term, plural1, plural2)
  {
    if (count == 1)
      return term;
    else if (count >= 2 && count <= 4)
      return plural1;
    else if (count >= 5 && count <= 20)
      return plural2;
    else if (count % 10 == 1)
      return term;
    else if (count % 10 >= 2 && count % 10 <= 4)
      return plural1;
    else
      return plural2;
  }

  function replace_text(node, search, replace)
  {
    if (node != null && node.nodeType == 3)
    {
      var value = node.nodeValue;
      var matches = value.match(search);
      if (matches != null)
      {
        var node_parent_node = node.parentNode;
        var old_node = node;
        for (match = 0; match < matches.length; match++)
        {
          // Построение <span class="localcomments" style="font-size: 95%; white-space: nowrap;"
          // title="MATCHES[MATCH]">MATCHES[MATCH]</span>
          var position;
          if (after_match != null && length != null)
            position = after_match.search(search) + before_match.length + length;
          else
            position = value.search(search);
          var length = matches[match].toString().length;
          var before_match = value.substring(0, position);
          var after_match = value.substring(position + length);
          var span = document.createElement('span');      
          span.setAttribute('class', 'localcomments');
          span.style.fontSize = '95%';
          span.style.whiteSpace = 'nowrap';
          span.setAttribute('title', matches[match]);
          span.appendChild(document.createTextNode(matches[match].toString().replace(search, replace)));
          var new_node = document.createDocumentFragment();
          new_node.appendChild(document.createTextNode(before_match));
          new_node.appendChild(span);
          new_node.appendChild(document.createTextNode(after_match));
          node_parent_node.replaceChild(new_node, old_node);
          break;
        }
      }
    }
    else if (node != null)
    {
      var children = [], child = node.firstChild;
      while (child)
      {
        children[children.length] = child;
        child = child.nextSibling;
      }
      for (var child = 0; child < children.length; child++)
        replace_text(children[child], search, replace);
    }
  }
});