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);
}());