Surprise! We've been running on hardware provided by BuyVM for a few months and wanted to show them a little appreciation.
Running a paste site comes with unique challenges, ones that aren't always obvious and hard to control. As such, BuyVM offered us a home where we could worry less about the hosting side of things and focus on maintaining a clean and useful service! Go check them out and show them some love!
Description: Юзерскрипт для показа категорий на RPGverse
Submitted on April 10, 2024 at 09:40 AM
Expires on April 10, 2025 at 09:40 AM (11 months from now)

// ==UserScript==
// @name     Display RPGverse language categories separately
// @version  1
// @grant    none
// @match http://wiki.rpgverse.ru/*
// @match https://wiki.rpgverse.ru/*
// ==/UserScript==


  var LANGUAGE_CATEGORY_NAME_REGEXP = /^Ролевые (материалы|системы) (на .*языке.*|без английской версии)$/;
  var CATEGORY_NAMESPACE_ID = 14;
  var PARENT_DIV_ID = 'rpgverse-lang-catlinks';
  var GENERALIZING_CAT_NAME = 'Ролевые материалы по языку';
  var GENERALIZING_CAT_TITLE = 'По языку';
  var COLON_TEXT = ': ';
  var CATLINKS_ELEMENT_ID = 'catlinks'
  var NORMAL_CAT_LINKS_PARENT_ID = 'mw-normal-catlinks'
  
  /**
   * Превращает полное имя категории («Ролевые материалы на китайском языке»)
   * в краткое («на китайском»).
   * 
   * Теряет различие между ссылками на категории («Ролевые материалы на X языке»
   * и «Ролевые системы на X языке»).
   * 
   * @param {string} fullName Полное имя (без префикса пространства имён)
   * @returns {string} Краткое имя
   */
  function makeShortCategoryText(fullName) {
    return fullName.replace(/^Ролевые (материалы|системы) /, '').replace(/ языке$/, '')
  }

  /**
   * Получает список категорий текущей страницы как массив объектов со
   * свойствами name (имя категории без пространства имён)
   * и shortName (текст вроде «на N языке»)
   *
   * @returns {{name: string; shortName: text}[]}
   */
  function getLanguageCategories() {
    var materialsByLanguage = Array.from(document.querySelectorAll('#catlinks ul li > a')).map(x => x.title.replace(/ \(страница не существует\)$/, '').replace(/^Категория:/, ''))
      .filter(function (catName) {
        return catName.match(LANGUAGE_CATEGORY_NAME_REGEXP)
      });
    var results = [];
    materialsByLanguage.forEach(function (name) {
      results.push({
        name: name,
        shortName: makeShortCategoryText(name)
      });
    })
    return results;
  }
  
  /**
   * @param {string} name Название категории (без префикса пространства имён)
   * @param {string} title Текст ссылки
   * @return {HTMLElement} Элемент <a> со ссылкой на категорию
   */
  function makeCategoryLink(name, title) {
    var articlePath = '/wiki/$1';
    var categoryNamespace = 'Категория';
    var qualifiedName = categoryNamespace + ':' + name;
    
    var className = '';
    if (document.querySelector) {
      // TODO: этот код не будет работать на старых браузерах, там все ссылки будут синие
      // Возможно, стоит либо переписать всё на ES6 (если не нужна), либо на jQuery (если нужна)
      var existingLink = document.querySelector('[title*="' + qualifiedName.replace(/["\\]/g, '\\$&') + '"]');
      if (existingLink && existingLink.title.indexOf(qualifiedName) === 0) {
        className = existingLink.className;
      }
    }
        
    var element = document.createElement('a');
    element.href = articlePath.replace('$1', qualifiedName);
    element.title = qualifiedName;
    element.innerText = title;
    element.className = className;
    return element;
  }
  
  /**
   *
   * @param {{name: string; shortName: text}[]} categories
   * @returns {HTMLElement} Элемент <ul>
   */
  function makeLanguageCategoriesList(categories) {
    var listElement = document.createElement('ul');
    
    categories.forEach(function (category) {
      var itemElement = document.createElement('li');
      itemElement.appendChild(makeCategoryLink(category.name, category.shortName));    
      listElement.appendChild(itemElement);
    });
    return listElement;
  }

  /**
   * @param {{name: string; shortName: text}[]} categories
   * @returns {HTMLElement} Элемент <div>
   */
  function makeLanguageCategoriesDiv(categories) {
    var parentElement = document.createElement('div');
    parentElement.id = PARENT_DIV_ID;
    
    parentElement.appendChild(makeCategoryLink(GENERALIZING_CAT_NAME, GENERALIZING_CAT_TITLE));
    parentElement.appendChild(document.createTextNode(COLON_TEXT));
    parentElement.appendChild(makeLanguageCategoriesList(categories));
    return parentElement;
  }
  
  /**
   * Скрывает языковые категории из основного списка.
   *
   * TODO: может, лучше скрыть категории через встроенный механизм MediaWiki?
   *
   * @param {{name: string; shortName: text}[]} categories
   */
  function hideLanguageCategoriesFromNormalCatLinks(categories) {
    var categoryNamespace = 'Категория';
    var normalCatLinksParent = document.getElementById(NORMAL_CAT_LINKS_PARENT_ID);
    
    // TODO: этот код не будет работать на старых браузерах, нам нужна их поддержка?
    // Возможно, стоит либо переписать всё на ES6 (если не нужна), либо на jQuery (если нужна)
    if (!normalCatLinksParent.querySelector) {
     // degrade gracefully на старых браузерах (кто-то ими ещё пользуется? там полинтернета поломано)
      return
    }
    
    categories.forEach(function (category) {
      var qualifiedName = categoryNamespace + ':' + category.name;
      var existingLink = normalCatLinksParent.querySelector('[title*="' + qualifiedName.replace(/["\\]/g, '\\$&') + '"]');
      if (existingLink && existingLink.title.indexOf(qualifiedName) === 0) {
        existingLink.style.display = 'none';
      }
    });
  }

  /**
   * Размещает список категорий по языку на странице.
   *
   * @param {{name: string; shortName: text}[]} categories
   */
  function placeLinksByLanguageOnPage(categories) {
    var catlinksElement = document.getElementById(CATLINKS_ELEMENT_ID);
    if (!catlinksElement) {
      console.error('Cannot find element with ID ' + CATLINKS_ELEMENT_ID);
      return
    }
    
    if (categories.length < 1) {
      return
    }
    catlinksElement.appendChild(makeLanguageCategoriesDiv(categories))
  }
  
  var categories = getLanguageCategories()
  placeLinksByLanguageOnPage(categories);
  hideLanguageCategoriesFromNormalCatLinks(categories)