Jump to content

User:ZBroz/Tbot.js

From Wiktionary, the free dictionary

Note: You may have to bypass your browser’s cache to see the changes. In addition, after saving a sitewide CSS file such as MediaWiki:Common.css, it will take 5-10 minutes before the changes take effect, even if you clear your cache.

  • Mozilla / Firefox / Safari: hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (Command-R on a Macintosh);
  • Konqueror and Chrome: click Reload or press F5;
  • Opera: clear the cache in Tools → Preferences;
  • Internet Explorer: hold Ctrl while clicking Refresh, or press Ctrl-F5.


// <pre><nowiki>
var Tbot;
Tbot = Tbot || {};

/*</pre>
==Change redlinks to greenlinks==
<pre>*/

Tbot.greenifyTranslinks = function (langcode)
{
  if(mw.config.get('wgAction') !== 'view')
    return;
  if(! document.querySelector)
    return;
  if(! document.querySelector
         ('table.translations span:lang(' + langcode + ') > a.new'))
    return;
  var headers = document.querySelectorAll('h3, h4, h5');
  for(var i = 0; i < headers.length; ++i)
  {
    if($(headers[i].querySelector('.mw-headline')).text() !== 'Translations')
      continue;
    var posHeader = getPosForTransSect(i);
    if(! posHeader)
      continue;
    for( var elem = headers[i].nextElementSibling;
         elem && elem.tagName.search(/^[hH]\d$/) === -1;
         elem = elem.nextElementSibling )
    {
      var linksToGreenify =
        elem.querySelectorAll('span:lang(' + langcode + ') > a.new');
      if(linksToGreenify.length === 0)
        continue;
      var gloss = getGlossForTransTable(elem);
      for(var j = 0; j < linksToGreenify.length; ++j)
      {
        var link = linksToGreenify[j];

        var tbotData =
        {
          lang:  langcode,
          pos:   posHeader.toLowerCase(),
          head:  $(link).text().trim().replace(/ +/g, ' '),
          xlit:  getXlitForLink(link),
          g:     getGenderForLink(link),
          trans: mw.config.get('wgTitle'),
          gloss: gloss
        };
        if(mw.util.wikiUrlencode(tbotData.head)
             === link.getAttribute('href').match(/\?(?:.*?&)?title=([^&]+)/)[1])
          delete tbotData.head;
        removeEmptyProps(tbotData);

        var href = link.getAttribute('href');
        href = href.split('#')[0]; // shouldn't be needed
        if(href.indexOf('?') === -1) // shouldn't happen
          href += '?';
        href += '&tbotData=' + encodeURIComponent(JSON.stringify(tbotData));

        link.setAttribute('href', href);
        link.style.color = 'rgb(34, 204, 0)';
      }
    }
  }

  function getPosForTransSect(i) // headers[i] is the trans-sect-header
  {
    // We start at headers[i-1], and scroll back until we find a header at
    // a higher level than headers[i]. For example, if ====Translations====
    // is at L4, then the closest-previous L3 header is the POS header.

    for(var j = i - 1; j >= 0; --j)
      if(headers[j].tagName < headers[i].tagName)
      {
        var ret = $(headers[j].querySelector('.mw-headline')).text();
        ret = ret.replace(/\s+\d+$/, ''); // e.g. 'Noun 1' -> 'Noun'
        return ret;
      }
    return null; // shouldn't happen
  }

  function getGlossForTransTable(navFrame)
  {
    var ret = $(navFrame.querySelector('.NavHead')).text();
    ret = ret.trim().replace(/^\[.*?\]\s*/, '').replace(/^\u00B1\s*/, '');
    return ret;
  }

  function getXlitForLink(link)
  {
    for(var node = link.parentNode.nextSibling; node; node = node.nextSibling)
    {
      if(node.nodeType === Node.ELEMENT_NODE
          && node.tagName.toUpperCase() === 'A') // hit {{t}} or [[ ]]
        break;
      if(node.nodeType === Node.ELEMENT_NODE
          && node.lang === langcode) // hit {{t-SOP}} or {{l}}
        break;
      if(node.nodeType !== Node.TEXT_NODE)
        continue;
      var match = node.data.match(/^ \((.*)\),? ?$/);
      if(match)
        return match[1];
    }
    return '';
  }

  function getGenderForLink(link) // e.g. '' or 'm' or 'c1' or 'm|f'
  {
    var ret = '';
    for( var elem = link.parentNode.nextElementSibling;
         elem;
         elem = elem.nextElementSibling )
      if(elem.tagName.toUpperCase() === 'A') // hit {{t}} or [[ ]]
        return '';
      else if(elem.lang === langcode) // hit {{t-SOP}} or {{l}}
        return '';
      else if(elem.className === 'gender')
        return decodeGenderSpan(elem);
    return '';
  }

  function decodeGenderSpan(span)
  {
    var child = span.firstChild;
    if(child.nodeValue && child.nodeValue.trim() === 'class') {
      child = child.nextSibling;
      var ret = '';
      while(child) {
        if(child.nodeType === Node.ELEMENT_NODE) {
          ret += '|c' + child.innerHTML.trim();
        }
        child = child.nextSibling;
      }
      return ret.replace(/^[|]/, '');
    } else {
      var abbrToCode = { pl: 'p',  anim: 'an',
                         du: 'd',  inan: 'in',
                         sg: 's',  pers: 'pr' };
      var ret = '';
      while(child) {
        if(child.nodeType === Node.ELEMENT_NODE) {
          var abbr = child.innerHTML.trim();
          ret += '-' + (abbrToCode[abbr] || abbr);
        } else if(child.nodeType === Node.TEXT_NODE) {
          if(child.nodeValue.trim() === ',')
            ret += '|';
        }
        child = child.nextSibling;
      }
      return ret.replace(/(^|[|])-/g, '$1');
    }
  }

  function removeEmptyProps(obj)
  {
    var propsToRemove = [];
    for(var key in obj)
      if(obj[key] === undefined || obj[key] === null || obj[key] === '')
        propsToRemove.push(key);
    for(var i = 0; i < propsToRemove.length; ++i)
      delete obj[propsToRemove[i]];
  }
};

/*</pre>
==Populate edit-window at target of a greenlink==
<pre>*/

Tbot.getHeadLine = Tbot.getHeadLine || {};

if(! Tbot.getHeadLine.run)
  Tbot.getHeadLine.run = function(tbotData)
  {
    var f;

    // Has a special case has been set up for this lang & POS?
    f = f || Tbot.getHeadLine[tbotData.lang+'~'+tbotData.pos];

    // . . . how about a special case for this lang, regardless of POS?
    f = f || Tbot.getHeadLine[tbotData.lang+'~'];

    // . . . or for this POS, regardless of lang?
    f = f || Tbot.getHeadLine['~'+tbotData.pos];

    // No? O.K., then just use the default:
    f = f || Tbot.getHeadLine.default;

    return f(tbotData);
  };

// a suitable default, using the {{head}} template
if(! Tbot.getHeadLine.default)
  Tbot.getHeadLine.default = function (tbotData)
  {
    var ret = '{{head|' + tbotData.lang;
    if(tbotData.pos.indexOf('=') > -1)
      ret += '||1=' + tbotData.pos;
    else
      ret += '|' + tbotData.pos;
    if(tbotData.head)
      ret += '|head=' + tbotData.head;
    if(tbotData.xlit)
      ret += '|tr=' + tbotData.xlit;
    if(tbotData.g)
      ret += '|g=' + tbotData.g.split('|')[0];
    if(tbotData.g && tbotData.g.indexOf('|') > -1)
      ret += '|g2=' + tbotData.g.split('|')[1];
    ret += '}}';
    return ret;
  };

// An augmented default: use {{head}} initially, but also launch an
// AJAX request to see if there exists a more-specific template and,
// if so, to replace {{head}} with a stab in the dark at how to use
// that template.
Tbot.getHeadLine['attempt-{{xx-pos}}'] = function (tbotData)
{
  var lang = tbotData.lang;
  var pos = tbotData.pos;

  jQuery.getJSON
  (
    '/w/api.php?format=jsonfm&action=query&titles='
      + 'Template:' + lang + '-' + pos,
    function (data)
    {
      data = data && data.query && data.query.pages;
      if(! data)
        return;
      var regex = new RegExp('[{][{]head[|]' + lang + '[|]' + pos + '(?=[|}]');
      var wpTextbox1 = document.getElementById('wpTextbox1');
      if(! wpTextbox1 || ! regex.test(wpTextbox1.value))
        return;
      for(var pageid in data)
        if(pageid.charAt(0) !== '-')
        {
          wpTextbox1.value =
            wpTextbox1.value.replace
              (regex, '{{' + data[pageid].title.substr(9));
          return;
        }
    }
  );

  return Tbot.getHeadLine['{{head}}'](tbotData);
};

Tbot.getHeadLine['ru~adjective'] =
Tbot.getHeadLine['ru~adverb'] =
Tbot.getHeadLine['ru~noun'] =
Tbot.getHeadLine['ru~proper noun'] =
Tbot.getHeadLine['ru~verb'] = function (tbotData)
{
  var ret = '{{ru-';
  if(tbotData.pos === 'adjective' || tbotData.pos === 'adverb')
    ret += tbotData.pos.substr(0, 3); // 'adj' or 'adv'
  else
    ret += tbotData.pos; // 'noun', 'proper noun', 'verb'
  if(tbotData.head)
    ret += '|head=' + tbotData.head;
  if(tbotData.xlit)
    ret += '|tr=' + tbotData.xlit;
  if(tbotData.g)
    if(tbotData.pos === 'verb')
      // not actually a gender: it's 'impf' or 'pf':
      ret += '|' + tbotData.g.split('|')[0];
    else if(tbotData.pos === 'noun' || tbotData.pos === 'proper noun')
      ret += '|g=' + tbotData.g.replace(/[|]/g, '');
  ret += '}}';
  return ret;
};

Tbot.getHeadLine['cs~adjective'] =
Tbot.getHeadLine['cs~adverb'] =
Tbot.getHeadLine['cs~noun'] =
Tbot.getHeadLine['cs~proper noun'] =
Tbot.getHeadLine['cs~verb'] = function (tbotData)
{
  var ret = '{{cs-';
  if(tbotData.pos === 'adjective' || tbotData.pos === 'adverb')
    ret += tbotData.pos.substr(0, 3); // 'adj' or 'adv'
  else
    ret += tbotData.pos; // 'noun', 'proper noun', 'verb'
  if(tbotData.head)
    ret += '|head=' + tbotData.head;
  if(tbotData.g)
    if(tbotData.pos === 'noun' || tbotData.pos === 'proper noun')
      ret += '|g=' + tbotData.g.replace(/[|]/g, '');
  ret += '}}';
  return ret;
};
 
Tbot.getHeadLine['tpi~verb'] = function (tbotData)
{
  if(mw.config.get('wgPageName').search(/im$/) > -1)
    return '{{tpi-verb|t}}';
  else
    return '{{tpi-verb|i}}';
};

Tbot.getHeadLine['tpi~verb'] = function (tbotData)
{
  if(mw.config.get('wgPageName').search(/im$/) > -1)
    return '{{tpi-verb|t}}';
  else
    return '{{tpi-verb|i}}';
};

Tbot.getHeadLine['yi~adjective'] =
Tbot.getHeadLine['yi~adverb'] =
Tbot.getHeadLine['yi~noun'] =
Tbot.getHeadLine['yi~phrase'] =
Tbot.getHeadLine['yi~proper noun'] =
Tbot.getHeadLine['yi~verb'] = function (tbotData)
{
  var ret = '{{yi-';
  if(tbotData.pos === 'adjective' || tbotData.pos === 'adverb')
    ret += tbotData.pos.substr(0, 3); // 'adj' or 'adv'
  else
    ret += tbotData.pos; // 'noun', 'phrase', etc.
  if(tbotData.head)
    ret += '|head=' + tbotData.head;
  if(tbotData.xlit)
    ret += '|tr=' + tbotData.xlit;
  if(tbotData.pos === 'noun' && tbotData.g)
    ret += '|g=' + tbotData.g.replace(/[|]/, '');
  if(tbotData.pos === 'noun' && tbotData.g === 'f'
      && mw.config.get('wgPageName').search(/\u05E2$/) > -1)
    ret += '|pl=s';
  ret += '}}';
  return ret;
};

Tbot.getInflSect = function (tbotData)
{
  // allow special-casing of specific languages and POSes:
  if(Tbot.getInflSect[tbotData.lang + '~' + tbotData.pos])
    return Tbot.getInflSect[tbotData.lang+'~'+tbotData.pos](tbotData);

  return '';
};

Tbot.getInflSect['yi~adjective'] = function (tbotData)
{
  var template = '{{yi-adj-';
  var curr = mw.config.get('wgTitle');
  if(curr.search(/[\u05DA\u05DD\u05DF\u05E3\u05E5]$/) > -1) // final letter
  {
    if(curr.charAt(curr.length - 1) === '\u05DD') // final mem
      template += 'm';
    else if(curr.charAt(curr.length - 1) === '\u05DF') // final nun
      template += 'n';
    else // final khaf, final fei, or final tsadi
      template += 'final';
    template += '|' + curr.substr(0, curr.length - 1)
                    + String.fromCharCode(curr.charCodeAt(curr.length - 1) + 1);
  }
  else if(curr.search(/\u05D5\u05BC?$|\u05D9\u05B4?$|\u05D0[\u05B7\u05B8]$|\u05E2$/) > -1)
    template += 'vowel';
  else
    template += '1';
  if(tbotData.xlit)
    template += '|' + tbotData.xlit;
  template += '}}';
  return '\n====Declension====\n' + template + '\n';
};

// DP custom BEGIN
Tbot.getLanguageHeading = function (langCode) {
  // Hardcode some languages for a nicer wiki markup before substitution
  if (langCode=="cs")
    return '==Czech==\n\n';
  else
    return '=={{subst:#invoke:language utilities|lookup_language|' + langCode + '|names}}==\n\n';
};

Tbot.getExternalLinks = function (langCode) {
  if (langCode=="cs")
    return "\n===External links===\n* {{R:PSJC}}\n* {{R:SSJC}}";
  else
    return "";
};
// DP custom END

$(function ()
{
  if(mw.config.get('wgNamespaceNumber') !== 0)
    return;
  if(mw.config.get('wgAction') !== 'edit')
    return;
  if(! document.getElementById('ca-nstab-main'))
    return;
  if(document.getElementById('ca-nstab-main').className !== 'selected new')
    return;
  var tbotData = document.location.href.match(/&tbotData=([^&]+)/);
  if(! tbotData)
    return;
  tbotData = JSON.parse(decodeURIComponent(tbotData[1]));
  if(tbotData.pos)
    tbotData.posHeader =
      tbotData.pos.charAt(0).toUpperCase() + tbotData.pos.substr(1);
  var wikitext = '';
  if(! tbotData.lang || tbotData.lang.search(/^[a-z-]+$/) === -1)
    return;
  //wikitext += '=={{subst:#invoke:language utilities|lookup_language|' + tbotData.lang + '|names}}==\n\n';
  wikitext += Tbot.getLanguageHeading(tbotData.lang);
  if(! tbotData.posHeader)
    return;
  if(tbotData.posHeader.search(/^=|=$/) > -1)
    wikitext += '=== ' + tbotData.posHeader + ' ===\n';
  else
    wikitext += '===' + tbotData.posHeader + '===\n';
  wikitext += Tbot.getHeadLine.run(tbotData) + '\n\n';
  if(! tbotData.trans)
    return;
  wikitext += '# [[' + tbotData.trans + ']]';
  if(tbotData.gloss)
    wikitext += ' {{gloss|' + tbotData.gloss + '}}';
  wikitext += '\n';
  wikitext += Tbot.getInflSect(tbotData);
  wikitext += Tbot.getExternalLinks(tbotData.lang);
  document.getElementById('wpTextbox1').value = wikitext;
});
// </nowiki></pre>