MediaWiki:Common.js

Материал из Циклопедии
Перейти к навигации Перейти к поиску

Замечание: Возможно, после публикации вам придётся очистить кэш своего браузера, чтобы увидеть изменения.

  • Firefox / Safari: Удерживая клавишу Shift, нажмите на панели инструментов Обновить либо нажмите Ctrl+F5 или Ctrl+R (⌘+R на Mac)
  • Google Chrome: Нажмите Ctrl+Shift+R (⌘+Shift+R на Mac)
  • Internet Explorer / Edge: Удерживая Ctrl, нажмите Обновить либо нажмите Ctrl+F5
  • Opera: Нажмите Ctrl+F5.
/**
 * Улучшенная версия пользовательских скриптов для Cyclowiki
 */

(function() {
    "use strict";

    // ====================== Утилиты ============================
    
    /**
     * Выполняет callback как можно раньше, с проверкой наличия элемента
     */
    window.runAsEarlyAsPossible = function(callback, $testElement, func) {
        func = func || $;
        $testElement = $testElement || $('#footer');
        
        if ($testElement.length) {
            callback();
        } else {
            func(callback);
        }
    };

    /**
     * Функция импорта скриптов
     */
    window.importScript = function(page) {
        mw.loader.using('mediawiki.util').done(function() {
            mw.loader.load(
                '//cyclowiki.org/w/index.php?title=' + 
                mw.util.wikiUrlencode(page) + 
                '&action=raw&ctype=text/javascript'
            );
        });
    };

    // ==================== Инициализация js правки нуль-раздела ==
  
    importScript("MediaWiki:Edittop.js");
    
    
    // ==================== Обработка категорий для статей Вахи ===
    
    $(function() {
        try {
            var textarea = $('#wpTextbox1');
            var textareaValue = textarea.val();
            var categories = mw.config.get('wgCategories') || [];
            
            // Проверка наличия Wh-категорий или шаблонов
            var hasWhCategory = $.inArray("Wharticle", categories) !== -1 ||
                               $.inArray("Whcat", categories) !== -1 ||
                               $.inArray("Whtalk", categories) !== -1;
            
            var hasWhTemplate = textareaValue !== undefined && (
                textareaValue.indexOf('{{wharticle}}') !== -1 ||
                textareaValue.indexOf('{{whcat}}') !== -1 ||
                textareaValue.indexOf('{{whtalk') !== -1
            );
            
            if (hasWhCategory || hasWhTemplate) {
                $('head').append(
                    '<link rel="stylesheet" href="/w/index.php?title=MediaWiki:Wh.css&action=raw&ctype=text/css" type="text/css" />'
                );
            }
        } catch (e) {
            console.warn('Ошибка при обработке Wh-категорий:', e);
        }
    });

    // ==================== Викификатор ===========================
    
    var currentAction = mw.config.get('wgAction');
    
    if ($.inArray(currentAction, ['edit', 'submit']) !== -1) {
        // Загрузка Викификатора с ru.wikipedia.org
        mw.loader.load(
            '//ru.wikipedia.org/w/index.php?title=MediaWiki:Gadget-wikificator.js&action=raw&ctype=text/javascript'
        );
        
        // Настройка кнопки в панели инструментов
        var customizeToolbar = function() {
            try {
                $('#wpTextbox1').wikiEditor('addToToolbar', {
                    section: 'advanced',
                    group: 'format',
                    tools: {
                        wikify: {
                            label: 'Викификатор',
                            type: 'button',
                            icon: '//upload.wikimedia.org/wikipedia/commons/0/06/Wikify-toolbutton.png',
                            action: {
                                type: 'callback',
                                execute: function() {
                                    if (typeof Wikify === 'function') {
                                        Wikify();
                                    }
                                }
                            }
                        }
                    }
                });
            } catch (e) {
                console.warn('Ошибка при настройке панели инструментов:', e);
            }
        };
        
        // Активация кнопки, если включена бета-панель
        mw.loader.using('user.options', function() {
            try {
                if (mw.user.options.get('usebetatoolbar')) {
                    mw.loader.using('ext.wikiEditor.toolbar', function() {
                        $(document).ready(customizeToolbar);
                    });
                }
            } catch (e) {
                console.warn('Ошибка при проверке настроек панели:', e);
            }
        });
    }

    // ==================== Скрипт сообщения об ошибках ============
    
    importScript("MediaWiki:Wikibugs.js");

    // ==================== withJS параметр ========================
    
    (function() {
        try {
            var withJS = document.URL.match(/[&?]withjs=((mediawiki:)?([^&#]+))/i);
            if (withJS && withJS[3] && window.importScript) {
                var pageName = withJS[3];
                // Проверка на безопасные символы
                if (/^[a-zA-Z0-9_\.\-]+$/.test(pageName)) {
                    importScript('MediaWiki:' + pageName);
                }
            }
        } catch (e) {
            console.warn('Ошибка при обработке withJS:', e);
        }
    })();

    // ==================== Сворачиваемые таблицы и блоки ==========
    
    var NavigationBar = {
        hide: '[скрыть]',
        show: '[показать]',
        showDefault: 2
    };

    /**
     * Проверка наличия класса у элемента
     */
    function hasClass(element, className) {
        if (!element || !element.className) return false;
        if (element.classList) {
            return element.classList.contains(className);
        }
        return (' ' + element.className + ' ').indexOf(' ' + className + ' ') !== -1;
    }

    /**
     * Сворачивание таблиц
     */
    function collapsibleTables() {
        try {
            var Table, HRow, HCell, btn, a, tblIdx = 0, colTables = [];
            var allTables = document.getElementsByTagName('table');
            
            for (var i = 0; i < allTables.length; i++) {
                Table = allTables[i];
                if (!hasClass(Table, 'collapsible')) continue;
                if (!(HRow = Table.rows[0])) continue;
                if (!(HCell = HRow.getElementsByTagName('th')[0])) continue;
                
                Table.id = 'collapsibleTable' + tblIdx;
                btn = document.createElement('span');
                btn.style.cssText = 'float:right; font-weight:normal; font-size:smaller';
                
                a = document.createElement('a');
                a.id = 'collapseButton' + tblIdx;
                a.href = '#';
                a.setAttribute('data-table-idx', tblIdx);
                a.onclick = (function(index) {
                    return function(e) {
                        if (e) e.preventDefault();
                        collapseTable(index);
                        return false;
                    };
                })(tblIdx);
                
                a.style.color = HCell.style.color || 'inherit';
                a.appendChild(document.createTextNode(NavigationBar.hide));
                btn.appendChild(a);
                HCell.insertBefore(btn, HCell.firstChild);
                colTables[tblIdx] = Table;
                tblIdx++;
            }
            
            for (var j = 0; j < tblIdx; j++) {
                if ((tblIdx > NavigationBar.showDefault && hasClass(colTables[j], 'autocollapse')) ||
                    hasClass(colTables[j], 'collapsed')) {
                    collapseTable(j);
                }
            }
        } catch (e) {
            console.warn('Ошибка в collapsibleTables:', e);
        }
    }

    /**
     * Свернуть/развернуть таблицу
     */
    function collapseTable(idx) {
        try {
            var Table = document.getElementById('collapsibleTable' + idx);
            var btn = document.getElementById('collapseButton' + idx);
            if (!Table || !btn) return false;
            
            var Rows = Table.rows;
            var isShown = (btn.firstChild && btn.firstChild.data === NavigationBar.hide);
            
            if (btn.firstChild) {
                btn.firstChild.data = isShown ? NavigationBar.show : NavigationBar.hide;
            }
            
            var disp = isShown ? 'none' : (Rows[0] ? Rows[0].style.display : '');
            for (var i = 1; i < Rows.length; i++) {
                if (Rows[i]) Rows[i].style.display = disp;
            }
            return true;
        } catch (e) {
            console.warn('Ошибка в collapseTable:', e);
            return false;
        }
    }

    /**
     * Сворачивание div-блоков
     */
    function collapsibleDivs() {
        try {
            var navIdx = 0, colNavs = [], NavFrame;
            var content = document.getElementById('content') || document.body;
            var divs = content.getElementsByTagName('div');
            
            for (var i = 0; i < divs.length; i++) {
                NavFrame = divs[i];
                if (!hasClass(NavFrame, 'NavFrame')) continue;
                
                NavFrame.id = 'NavFrame' + navIdx;
                
                var a = document.createElement('a');
                a.className = 'NavToggle';
                a.id = 'NavToggle' + navIdx;
                a.href = '#';
                a.setAttribute('data-div-idx', navIdx);
                a.onclick = (function(index) {
                    return function(e) {
                        if (e) e.preventDefault();
                        collapseDiv(index);
                        return false;
                    };
                })(navIdx);
                a.appendChild(document.createTextNode(NavigationBar.hide));
                
                for (var j = 0; j < NavFrame.childNodes.length; j++) {
                    if (hasClass(NavFrame.childNodes[j], 'NavHead')) {
                        NavFrame.childNodes[j].appendChild(a);
                        break;
                    }
                }
                
                colNavs[navIdx] = NavFrame;
                navIdx++;
            }
            
            for (var k = 0; k < navIdx; k++) {
                if ((navIdx > NavigationBar.showDefault && !hasClass(colNavs[k], 'expanded')) ||
                    hasClass(colNavs[k], 'collapsed')) {
                    collapseDiv(k);
                }
            }
        } catch (e) {
            console.warn('Ошибка в collapsibleDivs:', e);
        }
    }

    /**
     * Свернуть/развернуть div
     */
    function collapseDiv(idx) {
        try {
            var div = document.getElementById('NavFrame' + idx);
            var btn = document.getElementById('NavToggle' + idx);
            if (!div || !btn) return false;
            
            var isShown = (btn.firstChild && btn.firstChild.data === NavigationBar.hide);
            
            if (btn.firstChild) {
                btn.firstChild.data = isShown ? NavigationBar.show : NavigationBar.hide;
            }
            
            var disp = isShown ? 'none' : 'block';
            for (var child = div.firstChild; child !== null; child = child.nextSibling) {
                if (hasClass(child, 'NavPic') || hasClass(child, 'NavContent')) {
                    child.style.display = disp;
                }
            }
            return true;
        } catch (e) {
            console.warn('Ошибка в collapseDiv:', e);
            return false;
        }
    }

    /**
     * Обработка координат
     */
    function handleCoordinates() {
        try {
            var wgAction = mw.config.get('wgAction');
            if (wgAction !== 'view' || !$('.coordinates').length) return;
            
            var c = $('.coordinates')[0];
            $('.coordinates').remove();
            
            if ($('#siteSub').length) {
                $('#siteSub').before(c);
            } else {
                $('#content').prepend(c);
            }
            
            $('.coordinates')
                .css({
                    'position': 'relative',
                    'right': '0',
                    'top': '0',
                    'margin-top': '-7px',
                    'margin-left': '2.8em'
                })
                .addClass('plainlinks');
        } catch (e) {
            console.warn('Ошибка при обработке координат:', e);
        }
    }

    // Запуск функций при загрузке страницы
    $(handleCoordinates);

    // ==================== Инициализация сворачивания ============
    
    function initializeAll() {
        collapsibleTables();
        collapsibleDivs();
    }

    // Универсальная функция добавления обработчика загрузки
    function addLoadEvent(func) {
        if (typeof func !== 'function') return;
        if (window.addEventListener) {
            window.addEventListener("load", func, false);
        } else if (window.attachEvent) {
            window.attachEvent("onload", func);
        }
    }

    addLoadEvent(initializeAll);

    // ==================== Плагин addtocopy =====================
    
    /**
     * jQuery плагин addtocopy
     * @author Falchenko Maxim aka be3
     * @version 1.2
     */
    jQuery.fn.addtocopy = function(usercopytxt) {
        var options = {
            htmlcopytxt: '<br>More: <a href="' + window.location.href + '">' + window.location.href + '</a><br>',
            minlen: 25,
            addcopyfirst: false
        };
        
        $.extend(options, usercopytxt);
        
        var copy_sp = document.createElement('span');
        copy_sp.id = 'ctrlcopy';
        copy_sp.innerHTML = options.htmlcopytxt;
        
        return this.each(function() {
            $(this).mousedown(function() {
                $('#ctrlcopy').remove();
            });
            
            $(this).mouseup(function() {
                if (window.getSelection) { // Современные браузеры
                    var slcted = window.getSelection();
                    var seltxt = slcted.toString();
                    
                    if (!seltxt || seltxt.length < options.minlen) return;
                    
                    var nslct = slcted.getRangeAt(0);
                    seltxt = nslct.cloneRange();
                    seltxt.collapse(options.addcopyfirst);
                    seltxt.insertNode(copy_sp);
                    
                    if (!options.addcopyfirst) {
                        nslct.setEndAfter(copy_sp);
                    }
                    
                    slcted.removeAllRanges();
                    slcted.addRange(nslct);
                    
                } else if (document.selection) { // Старые версии IE
                    var slcted = document.selection;
                    var nslct = slcted.createRange();
                    var seltxt = nslct.text;
                    
                    if (!seltxt || seltxt.length < options.minlen) return;
                    
                    seltxt = nslct.duplicate();
                    seltxt.collapse(options.addcopyfirst);
                    seltxt.pasteHTML(copy_sp.outerHTML);
                    
                    if (!options.addcopyfirst) {
                        nslct.setEndPoint("EndToEnd", seltxt);
                        nslct.select();
                    }
                }
            });
        });
    };

    // Активация addtocopy для анонимов в основном пространстве
    try {
        var wgUserName = mw.config.get('wgUserName');
        var wgNamespaceNumber = mw.config.get('wgNamespaceNumber');
        
        if (wgUserName === null && wgNamespaceNumber === 0) {
            $(document).addtocopy({
                htmlcopytxt: '<br>Подробнее: <a href="' + window.location.href + '">' + window.location.href + '</a>'
            });
        }
    } catch (e) {
        console.warn('Ошибка при активации addtocopy:', e);
    }

})();