123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
// ==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)