MediaWiki:Common.js
Замечание: Возможно, после публикации вам придётся очистить кэш своего браузера, чтобы увидеть изменения.
- Firefox / Safari: Удерживая клавишу Shift, нажмите на панели инструментов Обновить либо нажмите Ctrl+F5 или Ctrl+R (⌘+R на Mac)
- Google Chrome: Нажмите Ctrl+Shift+R (⌘+Shift+R на Mac)
- Edge: Удерживая Ctrl, нажмите Обновить либо нажмите Ctrl+F5
- Opera: Нажмите Ctrl+F5.
/* Размещённый здесь код JavaScript будет загружаться пользователям при обращении к каждой странице */
/* Счётчик тем на вкладке "Обсуждение" */
$( function () {
var namespace = mw.config.get( 'wgNamespaceNumber' );
var pageName = mw.config.get( 'wgPageName' );
// Не работаем на специальных страницах
if ( namespace < 0 ) {
return;
}
// Находим вкладку "Обсуждение"
var talkTab = document.querySelector( '#ca-talk a' );
if ( !talkTab ) {
return;
}
/*
* В MediaWiki пространства имён идут парами:
* 0 -> 1 Основное -> Обсуждение
* 2 -> 3 Участник -> Обсуждение участника
* 4 -> 5 Проект -> Обсуждение проекта
* и т.д.
*
* Если мы уже на странице обсуждения,
* используем её саму.
*/
var talkPage;
if ( namespace % 2 === 1 ) {
// Уже на странице обсуждения
talkPage = pageName;
} else {
// Берём ссылку самой вкладки "Обсуждение".
// Так мы не зависим от языка пространства имён.
var href = talkTab.getAttribute( 'href' );
if ( !href ) {
return;
}
try {
var url = new URL( href, window.location.origin );
talkPage =
url.searchParams.get( 'title' ) ||
decodeURIComponent(
url.pathname.substring(
url.pathname.lastIndexOf( '/' ) + 1
)
);
} catch ( e ) {
return;
}
}
if ( !talkPage ) {
return;
}
var api = new mw.Api();
api.get( {
action: 'parse',
page: talkPage,
prop: 'sections',
formatversion: 2
} ).done( function ( data ) {
if ( !data.parse || !data.parse.sections ) {
return;
}
/*
* Считаем заголовки второго уровня:
*
* == Тема обсуждения ==
*
* Подзаголовки === ... === в счётчик не попадут.
*/
var count = data.parse.sections.filter( function ( section ) {
return Number( section.level ) === 2;
} ).length;
if ( count === 0 ) {
return;
}
var badge = document.createElement( 'span' );
badge.className = 'talk-topic-count';
badge.textContent = count;
badge.title =
count === 1
? '1 тема в обсуждении'
: count + ' тем в обсуждении';
talkTab.appendChild( badge );
} );
} );
(function () {
'use strict';
function clean(text) {
return text.replace(/\s+/g, ' ').trim();
}
function equipmentKey(text) {
var letters = {
P: 'Р',
C: 'С',
Y: 'У',
M: 'М'
};
return clean(text).toUpperCase().replace(/[PCYM]/g, function (c) {
return letters[c];
});
}
function init() {
var table = document.getElementById('soul-characters');
if (!table || table.getAttribute('data-soul-filter-ready')) {
return;
}
var equipmentOrder = ['Р', 'СР', 'ССР', 'УР', 'МР'];
var records = Array.prototype.filter.call(table.rows, function (row) {
return row.cells.length === 4 &&
row.cells[0].tagName === 'TD';
}).map(function (row) {
var equipment = [];
Array.prototype.forEach.call(
row.cells[2].querySelectorAll('td, th'),
function (cell) {
var key = equipmentKey(cell.textContent);
if (
equipmentOrder.indexOf(key) !== -1 &&
equipment.indexOf(key) === -1
) {
equipment.push(key);
}
}
);
return {
row: row,
originalDisplay: row.style.display,
characterClass: clean(
row.cells[3].textContent
).toLowerCase(),
equipment: equipment
};
});
if (!records.length) {
return;
}
table.setAttribute('data-soul-filter-ready', '1');
var panel = document.createElement('div');
panel.className = 'soul-character-filters';
panel.style.cssText =
'display:flex;flex-wrap:wrap;align-items:center;' +
'gap:12px;margin:12px 0;';
panel.setAttribute('role', 'group');
panel.setAttribute('aria-label', 'Фильтры персонажей');
function addSelect(caption, allCaption, options) {
var label = document.createElement('label');
label.textContent = caption + ' ';
var select = document.createElement('select');
select.style.cssText =
'font:inherit;padding:5px;max-width:100%;';
select.add(new Option(allCaption, ''));
options.forEach(function (option) {
select.add(new Option(option.label, option.value));
});
label.appendChild(select);
panel.appendChild(label);
return select;
}
var classSelect = addSelect('Класс:', 'Все классы', [
{ label: 'Магический', value: 'магический' },
{ label: 'Атакующий', value: 'атакующий' },
{ label: 'Защитный', value: 'защитный' }
]);
var presentEquipment = equipmentOrder.filter(function (key) {
return records.some(function (record) {
return record.equipment.indexOf(key) !== -1;
});
});
var equipmentSelect = addSelect(
'Боевое снаряжение:',
'Все снаряжения',
presentEquipment.map(function (key) {
return { label: key, value: key };
})
);
var reset = document.createElement('button');
reset.type = 'button';
reset.textContent = 'Сбросить';
reset.style.cssText =
'font:inherit;padding:5px 10px;cursor:pointer;';
panel.appendChild(reset);
var count = document.createElement('span');
count.setAttribute('role', 'status');
count.setAttribute('aria-live', 'polite');
panel.appendChild(count);
table.parentNode.insertBefore(panel, table);
function applyFilters() {
var visible = 0;
records.forEach(function (record) {
var matchesClass =
!classSelect.value ||
record.characterClass === classSelect.value;
var matchesEquipment =
!equipmentSelect.value ||
record.equipment.indexOf(equipmentSelect.value) !== -1;
var matches = matchesClass && matchesEquipment;
record.row.style.display = matches
? record.originalDisplay
: 'none';
if (matches) {
visible += 1;
}
});
count.textContent =
'Показано: ' + visible + ' из ' + records.length +
(visible ? '' : ' — совпадений нет');
}
classSelect.addEventListener('change', applyFilters);
equipmentSelect.addEventListener('change', applyFilters);
reset.addEventListener('click', function () {
classSelect.value = '';
equipmentSelect.value = '';
applyFilters();
});
applyFilters();
}
mw.hook('wikipage.content').add(init);
}());