MediaWiki:Edit.js

Материал из Традиция: Право
Перейти к: навигация, поиск
/*
 *   Инструменты редактирования. Версия 0.91
 *   Александр Машин.
 *   Отдельные изменения и исправления — Mithgol the Webmaster.
 *   Для обновления перезагрузить http://pravo.traditio.ru/w/index.php?title=MediaWiki:Edit.js&action=raw&ctype=text/javascript.
 * 
 */

// Значки развёртывания и свёртывания субменю:
var extender = '<img src="http://traditio-ru.org/images/c/cf/Etool_extender.png" width="5" height="16" alt="&rarr;" />';
var collapser = '<img src="http://traditio-ru.org/images/d/d4/Etool_collapser.png" width="5" height="16" alt="&darr;" />';
// Для отложенного разбора:
var lastPostponed = 0;
var immediate_limit = $.browser.msie    ? 16
                    : $.browser.mozilla ? 32
                    :                     64;
// Счётчик инструментов:
var tool_no = 0;
// Признак того, что кнопка мыши нажата:
var mouse_is_down = false;
// id счётчика времени, включившегося при наведении мыши на инструмент:
var delay_id;
// Задержка показа подменю при наведении указателя мыши, мс:
var popup_delay = 500;
// Кэш для хранения обёрток, заполнителей и подменю, загрузка которых отложена:
var cache = {};

/*  Заготовки для меню.
 *  Объявления — глобальные.
 *  Создаются функцией createStubs().
*/
var $li_stub, $button_stub, $a_stub, $full_stub, $ul0_stub, $ul1_stub, $li0_stub,
    $li1_stub, $postponed_stub;

function createStubs(){
    /*  употребляются в eButton():  */
    // Пункт меню:
    $li_stub = $('<li></li>');

    // Кнопка:
    $button_stub = $('<button type="button"></button>').mouseup(function(){
        // Срабатывание назначенной кнопке функции:
        insertTag ($(this).attr ('forbox')
            , cache [makeCacheKey (this.title) + '_wrapper']
            , cache [makeCacheKey (this.title) + '_filler']
            , $(this).attr ('process_all')
        );
        $(this).makeLeader();
    }).mouseover(function(){
        // Вывод вставляемого кнопкой вики-кода в строку состояния:
        var wrapper = cache [makeCacheKey (this.title) + '_wrapper'];
        if (wrapper && !$.isFunction (wrapper)) {
            window.status = this.title;
            if ( this.title != $.trim( stripHTML(wrapper) ).replace (/_/g, ' ') ){
                window.status += ': ' + wrapper;
            }
        }
        return false;
    }).mouseleave(function(){
        // Очистка строки состояния:
        window.status = '';
    });
    // + для IE, который не понимает :hover в CSS:
    if ($.browser.msie) {
        $button_stub.hover (
            function () {$(this).addClass    ('hover');}
          , function () {$(this).removeClass ('hover');}
        );
    }

    // Ссылка:
    $a_stub = $('<a target="_blank"></a>');
    // + для IE, который не понимает :hover в CSS:
    if ($.browser.msie) {
        $a_stub.hover (
            function(){ $(this).addClass   ('hover'); }
          , function(){ $(this).removeClass('hover'); }
        );
    }

    // Текст к кнопке:
    $full_stub = $('<span></span>').addClass('full');

    /*  употребляются в eMenu():  */
    // Заготовка меню верхнего уровня:
    $ul0_stub = $('<ul></ul>').addClass('eMenu');
    // Подменю:
    $ul1_stub = $ul0_stub.clone().mouseleave(function(){
        // Свёртывание при съезде мыши:
        $('.eMenu .eMenu').not('.fixed').slideUp('fast');
        // Сброс счётчика времени для показа подменю по наведению и задержке мыши:
        clearInterval(delay_id);
    });
    // + для IE, который не может нормально установить ширину абсолютно позиционированных блоков:
    if ($.browser.msie) {
        // Установить ширину подменю:
        $ul1_stub.width('35em');
    }

    // Заготовка кнопки верхнего меню:
    $li0_stub = $('<li></li>').append( // Последний инструмент:
        $('<button></button>').text ('?').addClass ('last')
    ).append( // Кнопка развёртывания:
        $('<button type="button"></button>').html(extender).addClass('extender').mousedown(
            function(){
                fixedToggle($(this).parent()); // -- развёртывание.
                return false;
            }
        )
    ).mousedown(function(){
        // Показ подменю при нажатии кнопки мыши:
        var $this = $(this);
        var $toolbar = $this.parents ('.eMenu');
        if ($toolbar.find('.eMenu.fixed').length == 0){
            $this.find ('.eMenu').loadAndShow ('instant');
            mouse_is_down = true;
        }
        // Сброс счётчика времени для показа подменю по наведению и задержке мыши:
        clearInterval (delay_id);
    }).mouseover(function(){
        // Сброс счётчика времени для показа подменю по наведению и задержке мыши:
        clearInterval (delay_id);

        var $this = $(this);
        var $toolbar = $this.parents ('.eMenu');
        if ($toolbar.find('.eMenu.fixed').length == 0) {
            // Показ подменю при наезде, при условии, что:
            if (mouse_is_down) { // кнопка мыши нажата:                   
                $this.find('.eMenu').loadAndShow('instant');
            } else {
                // или мышь задерживается на popupdelay мс (по умолчанию, 0,5 с):
                delay_id = setTimeout(function(){
                    $this.find('.eMenu').loadAndShow('fast');
                }, popup_delay);
            }
        }
    }).mouseup(function(){
        // Снятие признака нажатия кнопки мыши:
        mouse_is_down = false;
        // Сброс счётчика времени для показа подменю по наведению и задержке мыши:
        clearInterval (delay_id);
    }).mouseleave(function(){
        // Сброс счётчика времени для показа подменю по наведению и задержке мыши:
        clearInterval (delay_id);
        // Свёртывание при съезде мыши:
        $('.eMenu .eMenu').not ('.fixed').slideUp ('fast');
    });
    // + для IE: разрыв над подменю, чтобы оно показывалось ниже, а не справа:
    if ($.browser.msie) {
        $li0_stub.append( '<br />' );
    }

    // Заготовка кнопки подменю:
    $li1_stub = $('<li></li>');

    // Заготовка отметки отложенной загрузки:
    /*
    $postponed_stub = eButton({
       button: '<img src="http://traditio-ru.org/images/Etool_AJAX-loader-T16.gif" width="16" height="16" alt="loading…" />',
       title: 'Загрузка…'
    });
    */
}
    
// Вертикальный разделитель и перевод строки для субменю:
var separator = {html: '<li><img src="http://traditio-ru.org/images/7/77/Etool_vrule.png" width="3" style="height: 2.5ex" alt="|" /></li>'};
var inline_separator = ' <<_•_>> ';
var br = {html: '<br clear="all" />'};

// Строка шаблонов лицензий для страницы загрузки изображений:
var licenses = '';
if (wgTitle == 'Upload') {
    $('#wpLicense option').each (function () {
        if (this.disabled) {
            // Группа лицензий:
            licenses += 'br <<' + $(this).text ().replace (/\s/g, '_').replace (/[[\]]/g, '') + '>> ';
        } else {
            // Лицензия:
            licenses += $(this).val () ? '{{' + $.trim ($(this).val ().split ('|', 2) [0]) + '}} ' : '';
        }
    });
}

// Настройка панелей инструментов над и под текстовыми окнами.
//     Вложенные массивы обозначают подменю.
//     Объекты описывают кнопки, метки, ссылки или произвольный HTML.
//     Строки -- ряды простых инструментов, разделённых пробелом.
// Верхняя панель:
var tools_above = [
[
    {title: 'Обработка выделенного текста', nl: true}
  , {wrapper: wikifyText, button: '<img src="http://traditio-ru.org/images/1/1f/Etool_wikify.png" width="20" height="16" alt="W"/>', title: 'Викификация', all: true}
  , {wrapper: function (s) {return s.toLowerCase ();}, title: 'Нижний регистр', button: 'аб', all: true}, br
    // Инструмент поиска и замены:
  , {html: '<hr />'}
  , {wrapper: function (s) {
                  return s.replace ($('#tregex').val () == 'on'
                          ? new RegExp ($('#tsearch').val ()
                                      , ($('#tglobal').val () == 'on' ? 'g' : '')
                                      + ($('#tmulti').val ()  == 'on' ? 'm' : '')
                                      + ($('#ticase').val ()  == 'on' ? 'i' : ''))
                          : $('#tsearch').val ()
                      , $('#treplace').val ());
              },
     button: '<img src="http://traditio-ru.org/images/b/b8/Etool_replace.png" alt="&rarr;" />',
     title: 'Поиск и замена',
     all: true, nl: true}
  , {html: '<span>(</span><input type="checkbox" id="tregex" /><label for="tregex">как <a href="http://traditio-ru.org/wiki/Регулярные_выражения" target="_blank" title="страница о регулярных выражениях (в новой вкладке)">regex</a></label>): '
         + '/<input id="tsearch" size="30" title="Что заменить">/<input id="treplace" size="30" title="Чем заменить">/'
         + '<input type="checkbox" id="tglobal" checked title="Заменить всё" /><label for="tglobal" title="Заменить всё">g</label>'              
         + '<input type="checkbox" id="tmulti" title="Много строк" /><label for="multi" title="Много строк">m</label>'
         + '<input type="checkbox" id="ticase" checked title="Игнорировать регистр" /><label for="ticase" title="Игнорировать регистр">i</label>/',
     nl: true}
] , separator, [
    {title: 'Пунктуация', nl: true}
  , {wrapper: '+—', button: '—', title: 'Тире'}  
  , {wrapper: '+–', button: '–', title: 'Минус'}
  , {wrapper: '+…', button: '…', title: 'Многоточие'}  
  , {wrapper: '&nbsp;', button: '∙', title: 'Неразрывный пробел'}, br
  , {wrapper: '«+»', button: '«<span class="plus_sign">a</span>»', title: 'Кавычки', filler: 'Текст в кавычках'}  
  , {wrapper: '„+“', button: '„<span class="plus_sign">a</span>“', title: 'Вложенные кавычки', filler: 'Текст в кавычках второго уровня'}, br
  , {wrapper: '“+”', button: '“<span class="plus_sign">a</span>”', title: 'Английские кавычки', filler: 'Текст в кавычках внутри английского текста'}
  , {wrapper: '»+«', button: '»<span class="plus_sign">a</span>«', title: 'Немецкие кавычки', filler: 'Текст в кавычках внутри немецкого текста'}, br
  , '§+ №+ ~ ¡+ ¿+ +† +‡ {{•}}_ ¶ #+ &+'
  , {wrapper: function (s) {return s + '|';}, button: '|', title: 'Вертикальная черта'}  
  , ' {{!}} ` \''
  , {title: 'Диакритика', nl: true}
  , {wrapper: '+́', button: '<b><span style="color:black">a</span>́</b>', title: 'Знак ударения', filler: 'Подударная гласная'}, br
  , {wrapper: '+́', button: '<b><span class="plus_sign">a</span>́</b>', title: 'Акут', filler: 'Буква под акутом'}
  , {wrapper: '+̀', button: '<b><span class="plus_sign">a</span>̀</b>', title: 'Гравис', filler: 'Буква под грависом'}
  , {wrapper: '+̂', button: '<b><span class="plus_sign">a</span>̂</b>', title: 'Циркумфлекс', filler: 'Буква под циркумфлексом'}  
  , {wrapper: '+̈', button: '<b><span class="plus_sign">a</span>̈</b>', title: 'Диарезис', filler: 'Буква под диарезисом'}  
  , {wrapper: '+̃', button: '<b><span class="plus_sign">a</span>̃</b>', title: 'Тильда', filler: 'Буква под тильдой'}
  , {wrapper: '+̌', button: '<b><span class="plus_sign">e</span>̌</b>', title: 'Гачек', filler: 'Буква под гачеком'}, br
  , {wrapper: '+̆', button: '<b><span class="plus_sign">a</span>̆</b>', title: 'Кратка', filler: 'Краткая буква'}
  , {wrapper: '+̄', button: '<b><span class="plus_sign">a</span>̄</b>', title: 'Макрон', filler: 'Долгая буква'}
  , {url: mw.util.wikiGetlink ('Традиция:Типографика'), button: '<img src="http://traditio-ru.org/images/d/d5/Etool_help.png" height="16" width="16" alt="?">', title: 'Типографика', nl: true}
], [
    {title: 'Шрифт', nl: true}
  , {wrapper: "''+''", button: '<img src="http://traditio-ru.org/images/e/e8/Etool_italic.png" width="14" height="16" alt="К" />', title: '<em>Курсив</em>'}
  , {wrapper: "'''+'''", button: '<img src="http://traditio-ru.org/images/1/15/Etool_bold.png" width="20" height="16" alt="Ж" />', title: '<strong>Полужирный шрифт</strong>'}, br
  , {wrapper: '<sup>+</sup>', button: '<img src="http://traditio-ru.org/images/9/9b/Etool_font_superscript.png" height="16" width="16" alt="sup">', title: 'Верхний индекс'}
  , {wrapper: '<sub>+</sub>', button: '<img src="http://traditio-ru.org/images/6/68/Etool_font_subscript.png" height="16" width="16" alt="sub">', title: 'Нижний индекс'}  
  , {wrapper: '<s>+</s>', button: '<strike style="color:blue"><span style="color:black">&nbsp;a&nbsp;</span></strike>', title: 'Зачеркнуть', filler: 'Зачёркнутый текст'}  , br
  , {wrapper: '<code>+</code>', button: 'К', title: '<code>Код</code>'}
  , {wrapper: '<kbd>+</kbd>', button: '<img src="http://traditio-ru.org/images/c/ce/Etool_keyboard.png" height="16" width="16" alt="kbd">', title: '<kbd>Ввод пользователя</kbd>'}
  , {wrapper: '<abbr title="(полностью)‎">+</abbr>', button: 'А', title: 'Сокращение'}  
  , {wrapper: '<acronym title="(полностью)‎">+</acronym>', button: 'Y', title: 'Акроним'}
], [
    {title: 'Заголовки', nl: true}
  , {wrapper: '\n== + ==\n', button: '<h2 style="font-size: 130%; margin: 0">З2</h2>', title: '<h2>Заголовок 2</h2>', nl: true}
  , {wrapper: '\n=== + ===\n', button: '<h3 style="font-size: 120%; margin: 0">З3</h3>', title: '<h3 style="margin-left: 16px;">Заголовок 3</h3>', nl: true}
  , {wrapper: '\n==== + ====\n', button: '<h4 style="font-size: 100%; margin: 0">З4</h4>', title: '<h4 style="margin-left: 32px;">Заголовок 4</h4>', nl: true}
  , {wrapper: '\n===== + =====\n', button: '<h5 style="font-size: 90%; margin: 0">З5</h5>', title: '<h5 style="margin-left: 48px;">Заголовок 5</h5>', nl: true}
  , {wrapper: '\n====== + ======\n', button: '<h6 style="font-size: 80%; margin: 0">З6</h6>', title: '<h6 style="margin-left: 64px;">Заголовок 6</h6>', nl: true}  
  , {title: 'Содержание', nl: true}
  , {wrapper: '+\n{{TOC}}\n', button: '<img src="http://traditio-ru.org/images/8/85/Etool_toc.png" height="16" width="16" alt="&Xi;">', title: 'Содержание здесь'}, br
  , {wrapper: '+\n{{TOCRight}}\n', button: '<img src="http://traditio-ru.org/images/f/fd/Etool_toc_right.png" height="16" width="16" alt="&Xi;&rarr;">', title: 'Содержание справа'}, br
  , {wrapper: '+\n__NOTOC__\n', button: '<img src="http://traditio-ru.org/images/0/00/Etool_no_toc.png" height="16" width="16" alt="&Xi;&rarr;">', title: 'Подавить содержание'}
], [
    {title: 'Абзац', nl: true}
  , {wrapper: '\n\n+', button: '<img src="http://traditio-ru.org/images/e/e9/Etool_red_line.png" width="16" height="16" alt="&crarr;" />', title: 'Новый абзац'}, br
  , {wrapper: makeUL, button: '<img src="http://traditio-ru.org/images/0/0d/Etool_text_list_bullets.png" width="16" height="16" alt="*" />', title: 'Маркированный список', filler: '\nодин пункт,\nдругой пункт,\n…,\nпоследний пункт'}
  , {wrapper: makeOL, button: '<img src="http://traditio-ru.org/images/3/36/Etool_text_list_numbers.png" width="16" height="16" alt="#" />', title: 'Нумерованный список', filler: '\nпервый пункт,\nвторой пункт,\n…,\nпоследний пункт'}
  , {wrapper: makeGlossary, button: '<img src="http://traditio-ru.org/images/4/42/Etool_glossary.png" width="16" height="16" alt="= ==" />', title: 'Глоссарий', filler: '\nпервый термин:определение,\nвторой термин:определение,\n…,\nпоследний термин:определение'}, br
  , {wrapper: '\n{{цитата|+|источник}}', button: '<img src="http://traditio-ru.org/images/4/43/Etool_text_indent.png" width="16" height="16" alt="&rarr;text" />', title: 'Цитата', filler: 'Цитируемый текст'}
  , {wrapper: makeTable
   , button: '<img src="http://traditio-ru.org/images/b/ba/Etool_table.png" width="16" height="16" alt="table" />'
   , title: 'Таблица'
   , filler: '\nзаголовок\n(1, nl:1)\n(2,1)'}
  , {url: mw.util.wikiGetlink ('Традиция:Как делать таблицы'), button: '<img src="http://traditio-ru.org/images/d/d5/Etool_help.png" height="16" width="16" alt="?">', title: 'Таблицы'}, br
  , {wrapper: '<poem>+</poem>\n', button:  '<img src="http://traditio-ru.org/images/3/3b/Etool_poem.png" width="16" height="16" alt="Стихи" />', title: 'Стихи'}
  , {wrapper: '<source language=(язык)">+</source>\n', button: '<img src="http://traditio-ru.org/images/a/ad/Etool_source_code.png" width="16" height="16" alt="&lt;&gt;" />', title: '<code>Исходный код</code>'}
  , {wrapper: '<pre>+</pre>\n', button: '<img src="http://traditio-ru.org/images/2/2e/Etool_pre.png" width="16" height="16" alt="$&gt;_" />', title: '<code>Преформатированный текст</code>'}, br
  , {wrapper: '<nowiki>+</nowiki>', button: '<img src="http://traditio-ru.org/images/c/cb/Etool_nowiki.png" width="16" height="16" alt="&lt;/&gt;" />', title: 'Невикифицированный текст', filler: 'Сырой викитест'}
  , {wrapper: '\n<!--\n+\n--' + '>\n', button: '<img src="http://traditio-ru.org/images/5/5f/Etool_comment.png" height="16" width="16" alt="books">', title: 'Комментарий HTML', filler: 'Комментарий HTML (не обрабатывается парсером)'}, br
  , {wrapper: '<br />', button: '<img src="http://traditio-ru.org/images/e/e3/Etool_br.png" width="11" height="16" alt="&crarr;" />', title: 'Перевод строки'}  
  , {url: mw.util.wikiGetlink ('Традиция:Вики-разметка'), button: '<img src="http://traditio-ru.org/images/d/d5/Etool_help.png" height="16" width="16" alt="?">', title: 'Вики-разметка', nl: true}    
], [
    {title: 'Ссылки', nl: true}
  , {wrapper: '[[+]]', button: '<img src="http://traditio-ru.org/images/4/41/Etool_link.png" height="16" width="16" alt="[[]]">', title: 'Вставить викиссылку', filler: 'Статья «Традиции»'}, br
  , {wrapper: '[+ (описание ссылки)]', button: '<img src="http://traditio-ru.org/images/3/3b/Etool_world_link.png" height="16" width="16" alt="&rarr;www">', title: 'Внешняя ссылка', filler: '(url)'}
  , {wrapper: '<span class="plainlinks">[+ (описание ссылки)]</span>', button: '<img src="http://traditio-ru.org/images/e/e6/Etool_www_page.png" height="16" width="16" alt="&rarr;www">', title: 'Внешняя ссылка без значка', filler: '(url)'}
  , {title: 'Сноски', nl: true}
  , {wrapper: '<ref>+</ref>', button: '<img src="http://traditio-ru.org/images/0/02/Etool_bookmark.png" width="16" height="16" alt="Сноска" />', title: 'Сноска', filler: 'Текст сноски'}
  , {wrapper: '{{тчк}}<ref>+</ref>', button: '<span style="margin-right: -0.21em">.</span><sup class="reference">[1]</sup>', title: 'Точка и сноска', filler: 'Текст сноски'}
  , {wrapper: '{{,}}<ref>+</ref>', button: '<span style="margin-right: -0.21em">,</span><sup class="reference">[1]</sup>', title: 'Запятая и сноска', filler: 'Текст сноски'}
  , {title: 'Источники', nl: true}
  , {wrapper: '{{статья|автор=|заглавие=|оригинал=|ссылка=+|издание=|тип=|место={{М.}}|год=[[]]|том=|номер=|страницы=}}', button: '<img src="http://traditio-ru.org/images/d/d6/Etool_newspaper_link.png" height="16" width="16" alt="&rarr;[P]">', title: 'Статья', filler: '(url)'}
  , {wrapper: '{{книга|автор=|часть=|заглавие=|оригинал=|язык_оригинала=|язык_оригинала_сокращённо=|переводчик=|ссылка=+|издание=|место={{М.}}|издательство=|год=[[]]|страницы=|isbn=}}', button: '<img src="http://traditio-ru.org/images/c/cd/Etool_book_link.png" height="16" width="16" alt="&rarr;[B]">', title: 'Книга', filler: '(url)'}
  , {wrapper: '{{cite_news|first=|last=|authorlink=|author=|coauthors=|title=|url=+|format=|work=|publisher=|location=|id=|pages=|page=|date=|accessdate=|language=|quote=|archiveurl=|archivedate=}}', button: '<img src="http://traditio-ru.org/images/d/d6/Etool_newspaper_link.png" height="16" width="16" alt="&rarr;[P]">', title: 'Новость', filler: '(url)'}
  , {wrapper: '{{cite_web|first=|last=|authorlink=|author=|coauthors=|title=|url=+|format=|work=|publisher=|location=|id=|pages=|page=|date=|accessdate=|language=|quote=|archiveurl=|archivedate=}}', button: '<img src="http://traditio-ru.org/images/5/58/Etool_page_link.png" width="16" height="16" alt="&rarr;text" />', title: 'WWW', filler: '(url)'}
  , {title: 'Блоги и форумы', nl: true}
  , {wrapper: '{{Lj user|+}}', button: '<img src="http://traditio-ru.org/images/c/cd/Etool_user.png" width="16" height="16" alt="ЖЖuser" />', title: 'Пользователь ЖЖ', filler: '(ник)'}
  , {wrapper: '{{Lj comm|+}}', button: '<img src="http://traditio-ru.org/images/4/4b/Etool_group_link.png" height="16" width="16" alt="ЖЖС">', title: 'Сообщество ЖЖ', filler: '(ник)'}
  , {wrapper: '{{Lj post|ник=+|№=|название=|автор=|дата=}}', button: '<img src="http://traditio-ru.org/images/d/d6/Etool_livejournal.png" height="16" width="16" alt="ЖЖ">', title: 'Запись ЖЖ', filler: '(ник автора)'}, br
  , {wrapper: '{{Ljr user|+}}', button: '<img src="http://traditio-ru.org/images/d/d4/Etool_user_red.png" width="16" height="16" alt="ЖЖР user" />', title: 'Пользователь ЖЖР', filler: '(ник)'}
  , {wrapper: '{{Ljr comm|+}}', button: '<img src="http://traditio-ru.org/images/4/4b/Etool_group_link.png" height="16" width="16" alt="ЖЖРС">', title: 'Сообщество ЖЖР', filler: '(ник)'}, br
  , {wrapper: '{{ФИГШ:пост|№_поста|+}}', button: 'Пост ФИГШ', title: null, filler: '(название)'}
  , {wrapper: '{{ФИГШ:тема|№_темы|+}}', button: 'Тема ФИГШ', title: null, filler: '(название)'}
  , {title: 'См. также в', nl: true}  
  , {wrapper: '{{См. также в|tsdne=+}}\n', button: 'ТСДНЭ', title: null, filler: '(название)'}
  , {wrapper: '{{См. также в|nmp=+}}\n', button: 'НМП', title: null, filler: '(название)'}
  , {title: 'Запросы источников', nl: true}
  , '{{Источник}} {{Кто?}} {{Когда?}}'
  , {title: 'Разделы сносок и источников', nl: true}
  , {wrapper: '\n== Ссылки ==\n* ', button: '<img src="http://traditio-ru.org/images/9/91/Etool_books.png" height="16" width="16" alt="books">', title: 'Ссылки'}
  , {wrapper: '{{автобиблиография}}', button: 'Автобиблиография', title: 'Автоматическая библиография'}
  , {wrapper: '\n== Примечания ==\n{{примечания}}\n', button: '<img src="http://traditio-ru.org/images/3/38/Etool_column_one.png" height="16" width="16" alt="books">', title: 'Примечания'}
  , {wrapper: '\n== Примечания ==\n{{примечания|2}}\n', button: '<img src="http://traditio-ru.org/images/7/7d/Etool_column_two.png" height="16" width="16" alt="books">', title: 'Примечания в 2 столбца'}  
  , {title: 'Цитирование', nl: true}
  , {wrapper: '\n{{цитата|+|источник}}', button: '<img src="http://traditio-ru.org/images/0/05/Etool_document_quote.png" height="16" width="16" alt="books">', title: 'Цитата', filler: 'Цитируемый текст'}, br
  , {wrapper: '«+»', button: '«<span class="plus_sign">a</span>»', title: 'Кавычки', filler: 'Текст в кавычках'}  
  , {wrapper: '„+“', button: '„<span class="plus_sign">a</span>“', title: 'Вложенные кавычки', filler: 'Текст в кавычках второго уровня'}, br
  , {wrapper: '“+”', button: '“<span class="plus_sign">a</span>”', title: 'Английские кавычки', filler: 'Текст в кавычках внутри английского текста'}
  , {wrapper: '»+«', button: '»<span class="plus_sign">a</span>«', title: 'Немецкие кавычки', filler: 'Текст в кавычках внутри немецкого текста'}, br
  , {wrapper: '{{current}}', button: '<img src="http://traditio-ru.org/images/0/02/Current_event_marker.png" alt="!" height="16" width="21" />', title: 'Текущие события'}
  , {url: mw.util.wikiGetlink ('Справка:Примечания и сноски'), button: '<img src="http://traditio-ru.org/images/d/d5/Etool_help.png" height="16" width="16" alt="?">', title: 'Примечания и сноски', nl: true}
], separator, [
    {button: '<img src="http://traditio-ru.org/images/c/c7/Etool_image.png" width="16" height="16" alt="Файл" />', title: 'Изображения', nl: true}
  , {wrapper: '[[Файл:+|thumb|(размер)px|(описание)]]', button: '<img src="http://traditio-ru.org/images/d/d7/Etool_image_right.png" width="16" height="16" alt="-[]-" />', title: 'Изображение справа', filler: 'Имя файла'}
  , {wrapper: '[[Файл:+|thumb|center|(размер)px|(описание)]]', button: '<img src="http://traditio-ru.org/images/8/88/Etool_image_center.png" width="16" height="16" alt="-[]-" />', title: 'Изображение в центре', filler: 'Имя файла'}
  , {wrapper: '[[Файл:+|(размер)px]]', button: '<img src="http://traditio-ru.org/images/a/aa/Etool_inline_image.png" height="16" width="17" alt="=[]=">', title: 'Внутристрочное изображение', filler: 'Имя файла'}, br
  , {wrapper: '{{Строчный блок|[[Файл:+|thumb|center|(размер)px|(описание)]]}}', button: '<img src="http://traditio-ru.org/images/8/83/Etool_inline_block_image.png" height="16" width="17" alt="[][][]">', title: 'Изображение в строчном блоке', filler: 'Имя файла'}, br
  , {wrapper: '\n<gallery>+</gallery>\n', button: '<img src="http://traditio-ru.org/images/d/d6/Etool_images.png" height="16" width="16" alt="[][][]">', title: 'Галерея', filler: 'Список файлов'}
  , {wrapper: '{{изображения}}', button: '<img src="http://traditio-ru.org/images/d/d6/Etool_images.png" height="16" width="16" alt="↓[][][]">', title: 'Автоматическая галерея'}
  , {url: mw.util.wikiGetlink ('Справка:Изображения'), button: '<img src="http://traditio-ru.org/images/d/d5/Etool_help.png" height="16" width="16" alt="?">', title: 'Изображения', nl: true}
], separator, [
    {button: '', title: 'Вики', nl: true}
  , {wrapper: '#перенаправление [[+]]', button: '<img src="http://traditio-ru.org/images/4/40/Etool_document_redirect.png" height="16" width="16" alt="&crarr;">', title: 'Перенаправление', filler: 'На какую статью перенаправить'}, br
  , {wrapper: '{{другие значения|+}}', button: 'Др. зн.', title: 'Есть другие значения'}
  , {wrapper: '{{неоднозначность}}', button: '<img src="http://traditio-ru.org/images/thumb/5/5f/Disambig_gray.svg/16px-Disambig_gray.svg.png" height="16" width="16" alt="‎E">', title: 'Неоднозначность'}, br,
  , {wrapper: '{{main|+}}', button: '<img src="http://traditio-ru.org/images/3/32/Icons-mini-icon_2main.png" height="16" width="16" alt="‎&rarr;">', title: 'Основная статья'},
  , {wrapper: '{{обзор|+}}', button: '<img src="http://traditio-ru.org/images/a/a9/Icons-mini-icon_2brief.png" height="16" width="16" alt="‎&uarr;">', title: 'Обзор'}, br
  , {wrapper: '{{+}}', button: '<img src="http://traditio-ru.org/images/2/21/Etool_template.png" height="16" width="41" alt="{{*}}">', title: 'Вызвать шаблон', filler: 'Шаблон'}
  , {wrapper: '{{!}}', title: '| для передачи в шаблон', filler: '-'}, br    
  , {wrapper: '\n[[Категория:+]]', button: '<img src="http://traditio-ru.org/images/3/32/Etool_bookshelf.png" width="16" height="16" alt="Добавить категорию" />', title: 'Добавить категорию', filler: 'Категория'}, br
  , {wrapper: '\n{{DISPLAYTITLE:+}}', button: '<img src="http://traditio-ru.org/images/7/78/Etool_displaytitle.png" height="16" width="16" alt="&lt;&gt;">', title: 'Отображаемое название'}
  , {wrapper: '\n{{DEFAULTSORT:+}}', button: '<img src="http://traditio-ru.org/images/a/a2/Etool_page_key.png" height="16" width="16" alt="&uarr;&darr;">', title: 'Ключ сортировки'}, br
  , {button: '', title: 'Заготовки и черновики', nl: true}
  , {wrapper: '{{заготовка}}', button: '<img src="http://traditio-ru.org/images/thumb/9/9d/Blank_template.gif/16px-Blank_template.gif" height="16" width="16" alt="&lt;!&gt;">', title: 'Заготовка'}
  , {wrapper: '{{черновик}}', button: '<img src="http://traditio-ru.org/images/7/73/Etool_construction.png" height="16" width="16" alt="&lt;!&gt;">', title: 'Черновик'}  
  , {wrapper: '{{сборник ссылок}}', button: '<img src="http://traditio-ru.org/images/thumb/Asymmetrical_symbol_of_Chaos.ant.svg/16px-Asymmetrical_symbol_of_Chaos.ant.svg.png" height="16" width="16" alt="&lt;!&gt;">', title: 'Сборник ссылок'}  
  , {wrapper: '{{Написал|+}}', button: '<img src="http://traditio-ru.org/images/3/3d/Etool_document_signature.png" height="16" width="16" alt="~">', title: 'Написал', filler: '(автор)'}
],
wgNamespaceNumber == 10 || wgNamespaceNumber == 156 ? [
    {title: 'Шаблоны', nl: true}
  , '{{{+}}} {{!}}', br
  , {wrapper: '<includeonly>+</includeonly>', button: '&lt;includeonly&gt;'}
  , {wrapper: '<noinclude>+</noinclude>', button: '&lt;noinclude&gt;'}, br
  , '\n[[Категория:Традиция:Шаблоны|+]] {{doc}}', br
  , '{{PAGENAME}} {{FULLPAGENAME}} {{#if:|+|}} {{#ifeq:||+|}} {{#switch:|1=+|2=|default=}}', br
  , '{{#vardefine:a=+}} {{#var:+}} {{#forargs:префикс|параметр|значение|+}}'
  , {url: mw.util.wikiGetlink ('Традиция:Шаблоны'), button: '<img src="http://traditio-ru.org/images/d/d5/Etool_help.png" height="16" width="16" alt="?">', title: 'Шаблоны', nl: true}
] : null
, wgNamespaceNumber == 14 ? [
    {title: 'Категория', nl: true}
  , '{{Категория|+|форма}}  {{catmain|+}}'
] : null
, wgNamespaceNumber == 152 ? [
    {title: 'SMW', nl: true}
  , '{{Свойство|+|тип|опис|общ}}  [[Имеет_тип:+]]  {{Отношение|+|опис|общ}}'
] : null
, wgNamespaceNumber == 6 || wgTitle == 'Upload' ? [
    {button: '<img src="http://traditio-ru.org/images/a/a3/Etool_image_desc.png" height="16" width="16" alt="Ξ">'
   , title: 'Описание', wrapper: '{{Изображение'
      + '\n| Название       = {{PAGENAME}}'
      + '\n| Объект         ='
      + '\n| Описание       ='
      + '\n| Автор          ='
      + '\n| Время создания ='
      + '\n| Источник       ='
      + '\n| Лицензия       ='
      + '\n}}'
    }
  , {title: 'Лицензии', nl: true}
  , licenses
] : null, [
    {url: mw.util.wikiGetlink ('Справка:Справка'), button: '<img src="http://traditio-ru.org/images/d/d5/Etool_help.png" height="16" width="16" alt="?">', title: 'Содержание', nl: true}
  , {url: mw.util.wikiGetlink ('Традиция:Правила и указания'), button: '<img src="http://traditio-ru.org/images/d/d5/Etool_help.png" height="16" width="16" alt="?">', title: 'Правила и указания'}, br
  , {url: mw.util.wikiGetlink ('Традиция:Вики-разметка'), button: '<img src="http://traditio-ru.org/images/d/d5/Etool_help.png" height="16" width="16" alt="?">', title: 'Вики-разметка'}, br
  , {url: mw.util.wikiGetlink ('Традиция:Типографика'), button: '<img src="http://traditio-ru.org/images/d/d5/Etool_help.png" height="16" width="16" alt="?">', title: 'Типографика'}, br
  , {url: mw.util.wikiGetlink ('Традиция:Шаблоны'), button: '<img src="http://traditio-ru.org/images/d/d5/Etool_help.png" height="16" width="16" alt="?">', title: 'Шаблоны'}, br
  , {url: mw.util.wikiGetlink ('Традиция:Как делать таблицы'), button: '<img src="http://traditio-ru.org/images/d/d5/Etool_help.png" height="16" width="16" alt="?">', title: 'Таблицы'}, br
  , {url: mw.util.wikiGetlink ('Справка:Примечания и сноски'), button: '<img src="http://traditio-ru.org/images/d/d5/Etool_help.png" height="16" width="16" alt="?">', title: 'Примечания и сноски'}, br
  , {url: mw.util.wikiGetlink ('Справка:Изображения'), button: '<img src="http://traditio-ru.org/images/d/d5/Etool_help.png" height="16" width="16" alt="?">', title: 'Изображения'}, br
  , {url: mw.util.wikiGetlink ('Справка:Графы'), button: '<img src="http://traditio-ru.org/images/d/d5/Etool_help.png" height="16" width="16" alt="?">', title: 'Графы'}, br
  , {url: mw.util.wikiGetlink ('Справка:Тексты'), button: '<img src="http://traditio-ru.org/images/d/d5/Etool_help.png" height="16" width="16" alt="?">', title: 'Тексты'}
]
];
// Нижняя панель:
var tools_below = [
[
    {button: 'Яя', title: 'Кириллица', nl: true, leader: true}
  , '<<Основные:>> А а Б б В в Г г Д д Е е Ё ё Ж ж З з И и Й й К к Л л М м Н н О о П п Р р С с Т т У у Ф ф Х х Ц ц Ч ч Ш ш Щ щ Ъ ъ Ы ы Ь ь Э э Ю ю Я я br '
  + '<<Старорусские:>> Ѳ ѳ  І і  Ѣ ѣ  Ѵ ѵ <<Древнерусские:>> Ѕ ѕ  Ѥ ѥ  Ѯ ѯ  Ѹ ѹ  Ѱ ѱ  Ѡ ѡ  Ѻ ѻ  Ѽ ѽ  Ѿ ѿ  Ѧ ѧ  Ѩ ѩ  Ѫ ѫ  Ѭ ѭ  Ѷ ѷ  ҂  а҃  б҄  а҅  а҆  ́а  {{подст:у́}} br '
  + '<<Другие_славянские:>> Ґ ґ Ѓ ѓ Ђ ђ Є є І і Ї ї Й й Ј ј Ќ ќ Љ љ Њ њ Ћ ћ Ў ў Џ џ br '
  + '<<Неславянские:>> Ә ә Ө ө Ғ ғ Җ җ Қ қ Ҝ ҝ Ң ң Ү ү Ұ ұ Ҳ ҳ Ҹ ҹ Һ һ  Ҕ ҕ Ӣ ӣ Ӯ ӯ Ҙ ҙ  Ҡ ҡ Ҥ ҥ Ҫ ҫ Ӑ ӑ  Ӓ ӓ Ӕ ӕ Ӗ ӗ Ӱ ӱ  Ӳ ӳ Ӹ ӹ Ӏ br '
  + 'Ҟ ҟ Ҧ ҧ Ҩ ҩ Ҭ ҭ  Ҵ ҵ Ҷ ҷ Ҽ ҽ Ҿ ҿ  Ӂ ӂ Ӄ ӄ Ӈ ӈ Ӌ ӌ  Ӛ ӛ Ӝ ӝ Ӟ ӟ Ӡ ӡ  Ӥ ӥ Ӧ ӧ Ӫ ӫ Ӵ ӵ '
], [
    {button: 'Ωω', title: 'Греческие', nl: true, leader: true}
  , '<<Основные:>> Α α Β β Γ γ Δ δ Ε ε Ζ ζ Η η Θ θ Ι ι Κ κ Λ λ Μ μ Ν ν Ξ ξ Ο ο Π π Ρ ρ Σ σ ς Τ τ Υ υ Φ φ Χ χ Ψ ψ Ω ω br '
  + '<<Шаблоны:>> {{lang-el|+}}  {{lang-el2|+}} {{Polytonic|+}} br '
  + '<<С_тонами:>> Ά ά Έ έ Ή ή Ί ί Ό ό Ύ ύ Ώ ώ  ᾼ ᾳ ᾴ Ὰ ὰ ᾲ ᾶ ᾷ Ἀ ἀ ᾈ ᾀ Ἁ ἁ ᾉ ᾁ Ἄ ἄ ᾌ ᾄ Ἂ ἂ ᾊ ᾂ Ἆ ἆ ᾎ ᾆ Ἅ ἅ ᾍ ᾅ Ἃ ἃ ᾋ ᾃ Ἇ ἇ ᾏ ᾇ br '
  + 'Ὲ ὲ Ἐ ἐ Ἑ ἑ Ἔ ἔ Ἒ ἒ Ἕ ἕ Ἓ ἓ ῌ ῃ ῄ Ὴ ὴ ῂ ῆ ῇ Ἠ ἠ ᾘ ᾐ Ἡ ἡ ᾙ ᾑ Ἤ ἤ ᾜ ᾔ Ἢ ἢ ᾚ ᾒ Ἦ ἦ ᾞ ᾖ Ἥ ἥ ᾝ ᾕ Ἣ ἣ ᾛ ᾓ Ἧ ἧ ᾟ ᾗ br '
  + 'Ὶ ὶ ῖ Ἰ ἰ Ἱ ἱ Ἴ ἴ Ἲ ἲ Ἶ ἶ Ἵ ἵ Ἳ ἳ Ἷ ἷ Ὸ ὸ Ὀ ὀ Ὁ ὁ Ὄ ὄ Ὂ ὂ Ὅ ὅ Ὃ ὃ ῤ Ῥ ῥ Ὺ ὺ ῦ ὐ Ὑ ὑ ὔ ὒ ὖ Ὕ ὕ Ὓ ὓ Ὗ ὗ br '
  + 'ῼ ῳ ῴ Ὼ ὼ ῲ ῶ ῷ Ὠ ὠ ᾨ ᾠ Ὡ ὡ ᾩ ᾡ Ὤ ὤ ᾬ ᾤ Ὢ ὢ ᾪ ᾢ Ὦ ὦ ᾮ ᾦ Ὥ ὥ ᾭ ᾥ Ὣ ὣ ᾫ ᾣ Ὧ ὧ ᾯ ᾧ br '
  + '<<Архаичные:>> Ϝ ϝ  Ϙ ϙ  Ϛ ϛ  Ϻ ϻ  Ϡ ϡ <<Варианты:>>  ϐ ϑ ϳ ϰ ϱ ϲ ϕ ϖ <<Коптские:>> Ϣ ϣ Ϥ  Ϧ ϧ  Ϩ ϩ  Ϫ ϫ  Ϭ ϭ  Ϯ ϯ br '
  + '<<Пунктуация:>> ʹ ͵ ͺ ;'  
], [
    {button: 'Zz', title: 'Латинские', nl: true, leader: true}
  , '<<Основные:>> A a B b C c D d E e F f G g H h I i J j K k L l M m N n O o P p R r S s T t U u V v W w X x Y y Z z br '
  + '<<Шаблоны:>> {{Unicode|+}} br '
  + '<<Дополнительные:>> A a Á á À à Â â Ä ä Ǎ ǎ Ă ă Ā ā Ã ã Å å Ą ą Æ æ Ǣ ǣ  B b  C c Ć ć Ċ ċ Ĉ ĉ Č č Ç ç  D d Ď ď Đ đ Ḍ ḍ Ð ð br '
  + 'E e É é È è Ė ė Ê ê Ë ë Ě ě Ĕ ĕ Ē ē Ẽ ẽ Ę ę Ə ə  F f  G g Ġ ġ Ĝ ĝ Ğ ğ Ģ ģ  H h Ĥ ĥ Ħ ħ Ḥ ḥ  I i İ ı Í í Ì ì Î î Ï ï Ǐ ǐ Ĭ ĭ Ī ī Ĩ ĩ Į į  J j Ĵ ĵ br '
  + 'K k Ķ ķ  L l Ĺ ĺ Ŀ ŀ Ľ ľ Ļ ļ Ł ł Ḷ ḷ Ḹ ḹ  M m Ṃ ṃ  N n Ń ń Ň ň Ñ ñ Ņ ņ Ṇ ṇ  O o Ó ó Ò ò Ô ô Ö ö Ǒ ǒ Ŏ ŏ Ō ō Õ õ Ǫ ǫ Ő ő Ø ø Œ œ br '
  + 'P p  Q q  R r Ŕ ŕ Ř ř Ŗ ŗ Ṛ ṛ Ṝ ṝ  S s Ś ś Ŝ ŝ Š š Ş ş Ṣ ṣ ß  T t Ť ť Ţ ţ Ṭ ṭ Þ þ  U u Ú ú Ù ù Û û Ü ü Ǔ ǔ Ŭ ŭ Ū ū Ũ ũ Ů ů Ų ų Ű ű Ǘ ǘ Ǜ ǜ Ǚ ǚ Ǖ ǖ br '
  + 'V v  W w Ŵ ŵ  X x  Y y Ý ý Ŷ ŷ Ÿ ÿ Ỹ ỹ Ȳ ȳ  Z z Ź ź Ż ż Ž ž  ß Ð ð Þ þ Ə ə'
], [
    {button: 'א', title: 'Еврейские', nl: true, leader: true}
  , '<<Шаблоны:>> {{lang-he|+}} {{lang-he2|+}} br '
  + '<<Основные:>> א ב ג ד ה ו ז ח ט י ך כ ל ם מ ן נ ס ע ף פ ץ צ ק ר ש ת br '
  + '<<Дополнительные:>>  ׳ ״  װ ױ ײ '
], [
    {button: 'ار', title: 'Арабские', nl: true, leader: true}
  , '<<Шаблоны:>> {{lang-ar|+}}  {{lang-ar2|+}} br '
  + '<<Основные:>> ا ب ت ث ج ح خ د ذ ر ز س ش ص ض ط ظ ع غ ف ق ك ل م ن ه و ي br '
  + '<<Дополнительные:>> ﺁ  ﺓ ﻻ ﷲ ء '
  , {wrapper: 'ى', button: 'ى', title: 'алиф максура'}
  , {wrapper: 'ي', button: 'ي', title: 'йе'} , br
  , '<<Пунктуация:>> ، ؛ ؟ br '
  + '<<Цифры:>> ٠ ١ ٢ ٣ ٤ ٥ ٦ ٧ ٨ ٩ ٪ ٫ ٬'  
], [
    {button: '[ɑ]', title: 'IPA для английского языка', nl: true, leader: true}
  , '<<Шаблоны:>> {{IPA-en|+}} {{IPA|/+/}} ‹+› br '
  + 'ˈ ˌ ŋ ɡ tʃ dʒ ʃ ʒ θ ð ʔ  iː ɪ uː ʊ ʌ ɜr eɪ ɛ æ oʊ ɒ ɔː ɔɪ ɔr ɑː ɑr aɪ aʊ  ə ər ɨ ɵ ʉ'
  , {button: '[ʔ]', title: 'IPA для других языков', nl: true}
  , '<<Шаблон:>> {{IPA|+}} br '
  + 'ʈ ɖ ɟ ɡ ɢ ʡ ʔ  ɸ β θ ð ʃ ʒ ɕ ʑ ʂ ʐ ç ʝ ɣ χ ʁ ħ ʕ ʜ ʢ ɦ  ɱ ɳ ɲ ŋ ɴ  ʋ ɹ ɻ ɰ  ʙ ⱱ ʀ ɾ ɽ  ɬ ɮ ɺ ɭ ʎ ʟ  ʍ ɥ ɧ  ʼ ɓ ɗ ʄ ɠ ʛ br '
  + 'ʘ ǀ ǃ ǂ ǁ  ɨ ʉ ɯ ɪ ʏ ʊ ø ɘ ɵ ɤ ə ɛ œ ɜ ɞ ʌ ɔ æ ɐ ɶ ɑ ɒ br '
  + 'ʰ ʱ ʷ ʲ ˠ ˤ ˀ ᵊ k̚ ⁿˡ  ˈ ˌ ː ˑ t̪ d̪ s̺ s̻ θ̼ s̬ n̥ ŋ̊ a̤ a̰  β̞ ˕ r̝ ˔ o˞ ɚ ɝ e̘ e̙ u̟ i̠ ɪ̈ e̽ ɔ̹ ɔ̜ n̩ ə̆ ə̯ ə̃ ȷ̃ ɫ z̴ ə̋ ə́ ə̄ ə̀ ə̏ ə̌ ə̂ ə᷄ ə᷅ ə᷇ ə᷆ ə᷈ ə᷉ t͡ʃ d͡ʒ t͜ɬ ‿ br '
  + '˥ ˦ ˧ ˨ ˩ ꜛ ꜜ | ‖ ↗ ↘  k͈ s͎'
], separator, [
 // Символы:
    {button: '<img src="http://traditio-ru.org/images/3/37/Etool_sum.png" width="16" height="16" alt="&Sigma;" />', title: 'Знаки', nl: true, leader: true}
  , '<<Математические:>> − × ÷ ⋅ ° +² +³ ∗ ∘ ± ∓ ≤ ≥ ≠ ≡ ≅ ≜ ≝ ≐ ≃ ≈ ⊕ ⊗ ∞ ≪ ≫ ∝ √ ∤ ≀ ◅ ▻ ⋉ ⋊ ⋈ ∴ ∵ ∙ ∷ ⋮ ⋯ ⋰ ⋱ br '
  + '¬ ∧ ∨ ⊻ ∀ ∃ ∄ ∅ ∈ ∉ ∋ ⊆ ⊈ ⊊ ⊂ ⊄ ⊇ ⊉ ⊋ ⊃ ⊅ ∪ ∩ ∑ ∏ ∐ ′ ∫ ∬ ∭ ∮ ∇ ∂ ∆ ∅ ℂ ℍ ℕ ℙ ℚ ℝ ℤ ℵ br '
  + '⌊ ⌋ ⌈ ⌉ ⊤ ⊥ ⊢ ⊣ ⊧ □ ∠ ⟨ ⟩ &nbsp; &minus; br '
  + ' ⃛  ⃜ ∁ ‵ ∂ ∞ ∟ ∠ ∡ ∢ ⊾ ⦜ ⊤ * ¹ ² ³ _ | ‖   √ ⊹ ⋔ ⌕ ⎰ ⎱ Ⓢ ╱ ▭ ⧴ ⩮ ⊶ ⊷ ⊸ ⋈ ⌢ ⌣ □ ▪ ♢ ◊ ⧫ br '
  + '<<Дроби:>> ½ ⅓ ⅔ ¼ ¾ ⅛ ⅜ ⅝ ⅞ <<Шахматы:>> ♔ ♕ ♖ ♗ ♘ ♙ ♚ ♛ ♜ ♝ ♞ ♟ br '
  + '<<Масти:>> ♠ ♣ ♥ ♦ ♡ ♢ ♤ ♧ <<Триграммы:>> ☰ ☱ ☲ ☳ ☴ ☵ ☶ ☷ br '
  + '<<Астрономия:>> ☼ ☽ ☾ ☿ ♀ ♁ ♂ ♃ ♄ ♅ ♆ ♇' + inline_separator + '♈ ♉ ♊ ♋ ♌ ♍ ♎ ♏ ♐ ♑ ♒ ♓' + inline_separator + '☉ ☊ ☋ ☌ ☍ br '
  + '<<Символы:>> ® © ™ ♀ ♂ ℅ ℓ ℗ µ Ω ℮ ☠ ☡ ☢ ☣ ☤ ☥ ☦ ☧ ☨ ☩ ☪ ☫ ☬ ☭ ☮ ☯ br '
  + '<<Ноты:>> ♩ ♪ ♫ ♬ ♬ ♭ ♮ ♯ br '
  + '<<Валюты:>> ¤ ₳ ฿ ₵ ¢ ₡ ₢ $ ₫ ₯ € ₠ ₣ ƒ ₴ ₭ ₤ ℳ ₥ ₦ ₧ ₰ £ ៛ ₨ ₪ ৳ ₮ ₩ ¥ br '
  + '<<Стрелки:>> ↺ ↻ ↑ → ← ↓ ↔ ↕ ↖ ↗ ↘ ↙ ↚ ↛ ↜ ↝ ↞↠ ↢ ↣ ↦ ↩  ↪ ↫ ↬ ↭ ↮ ⇍ ⇎ ⇏ ⇐ ⇑ ⇒ ⇓ ⇔ ⇕ ⇚ ⇛ ⇝ ☚ ☛ ☜ ☝ ☞ ☟ ➔ ➘ ➙ ➚ ➛ ➜ ➝ ➟ ➠ ➡ ➢ ➣ ➤ ➥ ➦ ➧ ➨ ➨ ➪ ➫ ➬ ➭ ➮ ➯ ➱ ➲ ➳ ➴ ➵ ➶ ➷ ➸ ➹ ➺ ➻ ➼ ➽ ➾ br '
  + '⇵ ⟵ ⟶ ⟷ ⟸ ⟹ ⟺ ⟼ ⤒ ⤓ ⥎ ⥏ ⥐ ⥑ ⥒ ⥓ ⥔ ⥕ ⥖ ⥗ ⥘ ⥙ ⥚ ⥛ ⥜ ⥝ ⥞ ⥟ ⥠ ⥡ br '
  + '↰ ↱ ↶ ↷ ↼ ↽ ↾ ↿ ⇀ ⇁ ⇂ ⇃ ⇄ ⇅ ⇆ ⇇ ⇈ ⇉ ⇊ ⇋ ⇌ △ ▴ ▵ ▸ ▹ ▽ ▾ ▿ ◂ ◃ br '
  + '⇄ ⇅ ⇆ ⇇ ⇈ ⇉ ⇊ ⇋ ⇌ △ ▴ ▵ ▸ ▹ ▽ ▾ ▿ ◂ ◃'
], // Подписи и обсуждения:
wgNamespaceNumber % 2 == 1 || wgNamespaceNumber == 4 ? [
    {title: 'Подписи', nl: true}
  , {wrapper: '<br />~~~~', button: '<img src="http://traditio-ru.org/images/c/c1/Etool_text_signature.png" width="16" height="16" alt="~~" />', title: 'С новой строки'}, br
  , '<<В_той_же_строке:>> --~~~~  ~~~~   —_~~~~  ~~~', br
  , {wrapper: '{{unsigned|+}}'}
  , {title: 'Голосования и обсуждения', nl: true}
  , {wrapper: '{{За}}', button: '<img src="http://traditio-ru.org/images/thumb/9/94/Symbol_support_vote.svg/15px-Symbol_support_vote.svg.png" alt="+" height="15" width="15" />', title: 'За'}
  , {wrapper: '{{Против}}', button: '<img src="http://traditio-ru.org/images/thumb/7/7f/Symbol_oppose_vote.svg/15px-Symbol_oppose_vote.svg.png" alt="-" height="15" width="15" />', title: 'Против'}
  , {wrapper: '{{Воздерживаюсь}}', button: '<img src="http://traditio-ru.org/images/thumb/5/5f/Symbol_neutral_vote.png/15px-Symbol_neutral_vote.png" alt="~" height="15" width="15" />', title: 'Воздерживаюсь'}, br
  , {wrapper: '{{Оставить}}', button: '<img src="http://traditio-ru.org/images/thumb/5/5a/BallotCheckMark.png/15px-BallotCheckMark.png" alt="Оставить" height="15" width="15" />', title: 'Оставить'}
  , {wrapper: '{{Удалить}}', button: '<img src="http://traditio-ru.org/images/thumb/8/83/BallotX.png/15px-BallotX.png" alt="Удалить" height="15" width="15" />', title: 'Удалить'}, br
  , {wrapper: '{{Перенесено в|+}}', filler: 'Страница, куда перенесён текст'}
  , {wrapper: '{{Перенесено из|+}}', filler: 'Страница, откуда перенесён текст'}
  , {title: 'Новые страницы', nl: true}
  , {title: 'Страница побывала в шаблоне «Новые статьи»', button: '<img src="http://traditio-ru.org/images/thumb/b/b9/Internet-news-reader.svg/16px-Internet-news-reader.svg.png" alt="!" height="16" width="16" />', wrapper: '{{Было_в_новых|URL=+}}'}
] : null
];
/*
 *  Обработчики событий:
 */
// Для упрощения синтаксиса вызова, оформляются в виде метода jQuery:
$.fn.extend ({ 
    // Выбрать ведущую кнопку для подменю:
    setLeader: function ($button) { 
        // Find first active (not submenu) button:
        $button = $button ? $button : this.find ('.leader *, button:not(.label), a:not(.label)').first ();
        this.parent ().children ('.last').replaceWith ($button.clone (true).addClass ('last'));
        return this;
    }
    // Сделать кнопку ведущей в подменю:
  , makeLeader: function () {
        this.parents ('.eMenu ul').setLeader (this);
        return this;
    }
    // Клонировать меню/подменю для указанного текстового поля:
  , cloneForTextbox: function (id) {
        return this.clone (true).find ('button, ul').attr ('forbox', id).end ().attr ('forbox', id);
    }
    // Активировать панели инструментов для текстового поля:
  , activateToolbars: function () {
        // Все панели серым:
        $('.eMenu').removeClass ('active');
        // Относящиеся к окну с фокусом -- не серым:
        $('.eMenu[forbox="' + this.attr ('id') + '"]').addClass ('active');
    }
    // Показать подменю с отложенной загрузкой:
  , loadAndShow: function (speed) {
       clearInterval (delay_id);
       var $ret = this.hasClass ('postponed')
                       // Подменю с отложенной загрузкой. Перезагрузить:
                     ? eMenu (
                           cache [this.attr('id')]
                         , 1, true
                       ).cloneForTextbox (this.attr('forbox')).replaceAll (this)
                       // Подменю полностью загружено:
                     : this;
        return speed == 'instant' ? $ret.show () : $ret.slideDown (speed);
    }
});
// Развёртывание и свёртывание субменю не наездом, а щелчком по треугольнику.
//     Так развёрнутое подменю свёртывается только другим щелчком:
function fixedToggle ($tool) {
    var $toolbar = $tool.parents ('.eMenu');
    // Снять класс fixed со всех развёрнутых подменю данной панели,
    //     всё равно, наездом или щелчком, кроме щёлкнутого:
    $toolbar.find ('li').not ($tool [0]).find ('.eMenu').removeClass ('fixed');
    // Переключить класс fixed щёлкнутого меню:
    $tool.find ('.eMenu').toggleClass ('fixed');
    // Скрыть все подменю данной панели:
    $toolbar.find ('li .eMenu').hide ();    
    // Показать подменю, развёрнутые щелчком (с классом fixed):
    $('.fixed').loadAndShow ();
    // Установить значки на основании класса fixed:
    $('.extender').each (function () {
        $(this).html ($(this).parent ('li').find ('.eMenu.fixed').length ? collapser : extender);
    });
}
/*
 *  Функции-обработчики настроек:
 */
// Экранирование HTML для title, onclick и т.п.:
function escape4htmlEvents (s) {
   return s.replace (/</g, '&lt;').replace (/>/g, '&gt;').replace (/"/g, '&quot;').replace (/\\/g, '\\\\').replace (/'/g, '\\\'');
}
// Удаляет из аргумента теги HTML:
function stripHTML (s) {
    return s ? s.replace (/(<.+?>|\n)/g, '') : null;
}
// Удаление из строки символов, недопустимых в имени переменной Javascript
//     для использования в кэше HTML:
function makeCacheKey (s) {
    return s.replace (/[:'"&+*\-\/|[\]{}(),\s\.#;]/g, 'S').replace (/\?/g, 'qu');
}
// Возвращает имя функции. Нужна только из-за IE:
function functionName (func) {
    var name = func && (typeof (func) == 'function' || typeof (func) == 'object')
             ? func.name
             : null;
    if (!name) {
        var matches = ('' + func).match (/function\s*([\w\$\d_]*)\s*\(/);
        name = matches ? matches [1] : '';
    }
    return name;
}
// Отладочная функция:
function showObj (obj, depth) {
    var out = '';
    if (!depth) {
        depth = 2;
    }
    if (typeof (obj) == 'object' && obj != null && depth > 1) {
        out += 'object (' + obj.constructor.name + ') : [\n';
        $.each (obj, function (key, val) {
            // window.alert (key + ' = ' + val + ' (' + typeof (val) + ')\n');
            out += key + ' = ' + showObj (val, depth - 1) + '\n';
        });
        out += ']';
    } else if (typeof (obj) == 'object' && obj != null && depth <= 1) {
        out = '[object]\n';
    } else if (obj != null) {
        out = typeof (obj) + ': ' + obj.toString ();
    } else {
        out = 'null';
    }
    return out;
}

/*
 *    Точка входа:
 */
// Добавление панелей инструментов над и под каждым текстовым полем после загрузки документа:
$(function () {
    // Компиляция панелей инструментов. Проводится только после загрузки формы редактирования,
    //     чтобы не задерживать её показ:
    // Создание заготовок:
    createStubs ();
    // Обход текстовых полей:
    $('textarea').each (function () {
        // Запись id текстового поля:
        var id = this.id;
        // Добавление панелей:
        $(this).before (       // -- верхняя панель:
            eMenu (tools_above).addClass ('above').cloneForTextbox (id)
        ).after (               // -- нижняя панель:            
            eMenu (tools_below).addClass ('below').cloneForTextbox (id)
        ).focus (function () { // -- событие фокуса: активация своих и деактивация чужих панелей:
            $(this).activateToolbars ();
        });
    });
    // Удаление стандартных инструментов:
    $('#toolbar').remove ();
    mwEditButtons = null;
    // Активация первого текстового поля:
    $('textarea').first ().focus ();
    // window.alert ('Число инструментов -- ' + tool_no);
});
/*
 * Функции, создающие меню из массива:
 */
// Получает в качестве аргумента объект со свойствами
//     wrapper, filler, url, html, button, title:
function eButton (arg) {

    if (!arg) return null;

    // Установить неопределённые свойства в null для упрощения дальнейшего кода:
    var wrapper = typeof arg.wrapper == 'undefined' ? null : arg.wrapper;
    var button  = typeof arg.button  == 'undefined' ? null : arg.button;
    var title   = typeof arg.title   == 'undefined' ? null : arg.title;
    var filler  = typeof arg.filler  == 'undefined' ? null : arg.filler;
    var all     = typeof arg.all     == 'undefined' ? false : arg.all;
    var nl      = typeof arg.nl      == 'undefined' ? null : arg.nl;
    var leader  = typeof arg.leader  == 'undefined' ? null : arg.leader;
    var url     = typeof arg.url     == 'undefined' ? null : arg.url;
    var html    = typeof arg.html    == 'undefined' ? null : arg.html;

    if (!wrapper && !button && !title && !url && !html) return null;

    // Только если явно задано название инструмента, разворачивать его в подменю:
    var expand = arg.title ? true : false;

    tool_no++; // -- счётчик инструментов.
    var $ret = $li_stub.clone ();

    // Вывести инструмент в новой строке?
    if (nl) $ret.addClass ('nl');

    // Сделать его ведущим по умолчанию вне очереди?
    if (leader) $ret.addClass ('leader');

    // Допустить обработку всего поля?
    var wrapper_name = $.isFunction (wrapper)
                     ? functionName (wrapper)
                     : wrapper;
    // TODO: stripHTML () -> mw.html.escape ();
    // Создание отсутствующего заполнителя из заданного названия:
    filler = filler == '-' ? ''
           : filler        ? filler
/*           : title && wrapper && wrapper_name.indexOf ('+') > -1
                           ? stripHTML (title)*/
           :                 '';
    // Всплывающая подсказка для инструмента:
    title = title  ? title // Если надо, создать название из кнопки:
          : button ? escape4htmlEvents (stripHTML (button)) // или даже из обёртки:
          :              $.trim (stripHTML (wrapper_name)).replace (/_/g, ' ');
    // Если надо, создать кнопку из обёртки:
    if (!button && wrapper) {
        var split = wrapper_name.split ('+', 2);
        button = split [0]
               + (split [0] && split [1] ? '<span class="plus_sign">+</span>' : '')
               + (split [1] ? split [1] : '');
    }
    // Кэширование обёртки и заполнителя:
    if (title) {
        var cache_key = makeCacheKey (stripHTML (title));
        cache [cache_key + '_wrapper'] = wrapper;
        cache [cache_key + '_filler']  = filler;
    }
    if (!wrapper && !url && !html && title) {
        // Если обёртки, URL и HTML нет, то создаётся метка: 
        if (nl) $ret.addClass ('header');
        $ret.attr ('title', stripHTML (title)).append (
            // Кнопка без событий, чтобы при протаскивании мыши не началось выделение текста:
            $('<button type="button" class="label"></button>').append (button).append (
                expand ? $('<span></span>').addClass ('full').html (title) : ''
            )
        );
    } else if (url) {
        // Есть URL. Создаётся ссылка: 
        $ret.attr ('title', title ? stripHTML (title) : '').append (
            $a_stub.clone ().attr ('href', url).append (button).append (
                expand ? $full_stub.clone ().html (title) : null
            )
        );
        if (nl) $ret.addClass ('header');
    } else if (html) {
        // Произвольный HTML: 
        if (nl) $ret.addClass ('header');
        $ret = $(html);
    } else {
        // Создаётся настоящая кнопка:
        $ret.append (
            $button_stub.clone (true).attr ('title', stripHTML (title)).attr ('process_all', all).html (button).append (
                // Название инструмента для подменю:
                expand ? $full_stub.clone ().html (title) : null
            )
        );
    }
    return $ret;
}
 
// Создаёт подменю или подменю из массива объектов, описывающих кнопки
//     массивов, описывающих подменю и строк, описывающих ряды кнопок.
//     Если level = 0, нужно меню, иначе -- подменю.
//     Если now = true, отложенная загрузка запрещена.
//     Возвращает объект jQuery:
function eMenu (arg, level, now) {

    if (!level) level = 0;
               
    // Нужно из-за изменения значения this в зависимости от контекста:
    var $li_stub = level == 0 ? $li0_stub : $li1_stub;
    var $ret = level == 0 ? $ul0_stub.clone () : $ul1_stub.clone ();
    
    // Если подменю слишком длинное для немедленного показа, показать отложенно:
    var left = now || level == 0 ? 10000000 : immediate_limit;
    var postponed = false;
    
    // Развёртывание рядов кнопок, заданных с помощью разделённых пробелами строк:
    var parsed = [];

    // Обход всего переданного массива:
    $.each (arg, function () {
        if (this) {
            if (this.split && this.length) {
                // Разделённая пробелами строка. Заменить на массив объектов:
                var estimated_length = this.match (/\S+/ig).length;
                // Массив, полученный разбивкой строки, добавляется к накопленному массиву объектов:
                parsed = $.merge (parsed, $.map (this.split (' ', left), function (s) {
                    // Обёртка подстрок в объекты:
                    return !s         ? null
                          : s == 'br' ? {html   : '<br clear="all" />'} // -- перевод строки.
                          : s.match (/^<<.+>>$/)                        // Метка:
                                      ? {title  : s.replace (/(^<<|>>$)/g, '').replace (/_/g, ' ')}
                          :             {wrapper: s.replace (/_/g, ' ').replace (/-uline-/ig, '_')};
                }));
                // Отдельная оценка необходима, т.к. ограничение в .split () работает неправильно:
                left -= estimated_length;
            } else {
                // Кнопка или подменю. Возвратить как есть:
                parsed.push (this);
                left--;
            }
        }
        // При превышении лимита завершить цикл:
        if (left <= 0) {
            postponed = true;
            return false;
        }
    });
    
    // Обход массива:
    $.each (parsed, function () {
        if (this) {
            if ($.isArray (this)) {
                // Подменю:
                eMenu (this, level + 1, now).appendTo (   // -- создание подменю рекурсивным вызовом.
                    $li_stub.clone (true).appendTo ($ret) // -- создание пункта меню.
                ).setLeader ();                           // -- задание ведущей кнопки.
            } else {
                // Предположительно, объект, описывающий кнопку:
                // Создание пункта меню с кнопкой и добавление к возврату:
                var button = eButton (this);
                if (button) {
                    button.appendTo ($ret);
                }
            }
        }
    });
    // Добавление признаков отложенной загрузки и запись её параметров в кэш:
    if (postponed) {
        // Запись в кэш:
        cache ['postponed_' + lastPostponed] = arg;
        // Класс отложенной записи, id записи в кэше, заглушка:
        $ret.addClass ('postponed').attr ('id', 'postponed_' + lastPostponed++)/*.append (
            $postponed_stub
        )*/;
    }
    
    // Установка класса, заменяющего first-child и last-child, для IE:
    if ($.browser.msie) {
        $ret.children ().first ().addClass ('firstChild');
        $ret.children ().last  ().addClass ('lastChild');
    }
    
    // Возврат:
    return $ret;
}

/*
 *  Функции, обработки текста, вызываемые кнопками: 
 */
// Вставка тега вокруг выделенного текста или вызов функции-обработчика
//     в результате нажатия кнопки
//    (ID окна, обёртка или обработчик, текст-образец (если нет выделения)):
function insertTag (textbox_id, wrapper, filler, all) {
    var callback;
    if ($.isFunction (wrapper)) {
        // Передана функция-обработчик:
        callback = wrapper;
        callback.filler = filler;
    } else {
        // Передана строка-обёртка:
        // Превращение обёртки в открывающий и закрывающий тэги:
        var tag_open, tag_close;
        if (wrapper && wrapper.indexOf ('+') > -1) {
            // Если в обёрке есть плюс, по нему её и разрезать на открывающий и закрывающий теги:
            var tags = wrapper.split (/\+(?!\+)/, 2);
            tag_open  = tags [0];
            tag_close = tags [1];
            callback = function (s) {
                // Окружить старое выделение символами '\x01' и '\x02':
                return tag_open + '\x01' + (s ? s : filler ? filler : '') + '\x02' + tag_close;
            }
        } else {
            // Если в обёртке нет плюса, вставлять её после выделения.
            // Выделить после этого вставленный символ:
            callback = function (s) {
                // Подумать, имеет ли смысл в этом контексте filler:
                return (s ? s : filler ? filler : '') + '\x01' + wrapper + '\x02';
            }
        }
    }
    // ID -> объект DOM:
    var textbox = document.getElementById (textbox_id);
    processSelection (textbox, callback, eval (all));
} // -- конец insertTag ();
// Превратить многострочный текст в маркированный список:
function makeUL (s) {
    return '\n' + (s ? s : makeUL.filler).replace (/^\s*(?:\d*[.)]|-)?\s*(.)/gm, '* $1');
}
// Превратить многострочный текст в нумерованный список:
function makeOL (s) {
    return '\n' + (s ? s : makeOL.filler).replace (/^\s*(?:\d*[.)]|-)?\s*(.)/gm, '# $1');
}
// Превратить многострочный текст в глоссарий:
function makeGlossary (s) {
    return '\n' + (s ? s : makeGlossary.filler).replace (/^\s*(?:\d*[.)]|-)?\s*(.)/gm, '; $1').replace (/[\-—:]/gm, ' : ');
}
// Превратить многострочный текст в строки таблицы (в один столбец):
function makeTable (s) {
    return '\n{|\n' + (s ? s : makeTable.filler).replace (/^./gm, '|-\n| $&') + '\n|}\n';
}
// Функция, викифицирующая выделение:
function wikifySelection (txtarea_id) {
    processSelection (document.getElementById (txtarea_id)
                    , wikifyText
                    , true);
     // Скорее всего, так просто не заработает:
     if (window.insertSummary) {
         insertSummary ('викификация');
     }
}
// Функция, выполняющая поиск и замену в выделении:
function regexSelection (txtarea_id, search, replace) {
    processSelection (document.getElementById (txtarea_id)
                    , function (s) {return s.replace (search, replace);}
                    , true);
}
// Обработать выделение в textbox с помощью funct.
//     Если ничего не выбрано и установлен all, обработать всё:
function processSelection (textbox, funct, all) {
    var inserted;
    var full_text = 'Будет обработан ВЕСЬ редактируемый текст. Продолжить?';
    var win_scroll = document.documentElement.scrollTop;
    textbox.focus ();
    if (typeof (textbox.selectionStart) != 'undefined'
    && (navigator ['productSub'] > 20031000
     || $.browser.safari
     || $.browser.opera
     || $.browser.mozilla)) {
        // Mozilla/Opera/Safari3:
        var textScroll = textbox.scrollTop; // -- сохранить положение промотки.
        // Определить выделение в виде позиций начала и конца:
        var start_pos   = textbox.selectionStart;
        var end_pos     = textbox.selectionEnd;
        if (start_pos == end_pos && all && confirm (full_text)) {
            // Ничего не выделено, но в таком случае позволено обработать весь текст:
            start_pos = 0;
            end_pos = textbox.value.length;
        }
        // Получение и обработка выделения:
        inserted = funct (textbox.value.substring (start_pos, end_pos));
        // Получение старого выделения:
        var sel_offset = inserted.indexOf ('\x01') > -1 ? inserted.indexOf ('\x01') : 0;
        var sel_length = (inserted.indexOf ('\x02') > -1 ? inserted.indexOf ('\x02') : 0) - sel_offset - 1;
        sel_length = sel_length >= 0 ? sel_length : 0;
        // Удаление символов выделения:
        inserted = inserted.replace ('\x01', '').replace ('\x02', '');
        // Перезапись значения поля:
        textbox.value = textbox.value.substring (0, start_pos)
                      + inserted
                      + textbox.value.substring (end_pos);
        // Выделить обработанное. Использовать для выделения нестандартные свойства
        //     selOffset и selLength, если возвращены funct:
        var correction = Math.floor (($.browser.opera && inserted.substr (0, start_pos + sel_offset).match (/\n/g)
                ? inserted.substr (0, start_pos + sel_offset).match (/\n/g).length
                : 0) / 2);
        textbox.selectionStart
          = start_pos
          + sel_offset
          + correction;
        textbox.selectionEnd
          = start_pos + sel_offset
          + sel_length
          - correction;
        // -- всё ещё неверно в Опере.
        textbox.scrollTop = textScroll; // -- восстановить положение промотки.
    } else if (document.selection && document.selection.createRange) {
        // IE:
        // Определить выделение в виде объекта range:
        var range = document.selection.createRange();
        if (range.text.length == 0 && all && confirm (full_text)) {
            // Ничего не выделено, но в таком случае позволено обработать весь текст:
            textbox.value = funct (textbox.value);
        } else {
            // Есть выделение, или обработка всего текста не предусмотрена:
            // Обработать выделение:
            inserted = funct (range.text);
            // Получение старого выделения:
            var sel_offset = inserted.indexOf ('\x01') > -1 ? inserted.indexOf ('\x01') : 0;
            var sel_length = (inserted.indexOf ('\x02') > -1 ? inserted.indexOf ('\x02') : 0) - sel_offset - 1;
            sel_length = sel_length >= 0 ? sel_length : 0;
            // Удаление символов выделения:
            inserted = inserted.replace ('\x01', '').replace ('\x02', '');
            
            // Заменить выделение на обработанное:
            range.text = inserted;
            // Перевыделить вставленное:
            if (range.moveStart) {
                range.moveStart ('character', - inserted.length + sel_offset);
                range.moveEnd   ('character', - inserted.length + sel_offset + sel_length);
            }
            range.select();
        }
    } else { 
        // Другие браузеры. Выделения не получить; обрабатывать всё или ничего:    
        if (all && confirm (full_text)) {
            textbox.value = funct (textbox.value).replace ('\x01', '').replace ('\x02', '');
        }
    }
    document.documentElement.scrollTop = win_scroll; // -- восстановить позицию промотки в IE/Opera.
} // -- конец processSelection ().

/*  Описание изменений
 *  Fixed by Dream, переписано под jQuery А. Машиным:
*/
function insertSummary ($for, text) {
    if ($for.val ().indexOf (text) != -1) return;                       // -- не нужно повторов.
    if ($for.val ().match (/[^,;: \/]$/)) $for.val ($for.val () + ','); // -- добавление запятой в конце.
    if ($for.val ().match (/[^ ]$/))      $for.val ($for.val () + ' '); // -- добавление пробела в конце.
    $for.val ($for.val () + text);                                      // -- добавление текста.
}

$.fn.extend ({
    addSumButton: function ($for, name, text, title) {
        return this.append (
            $('<a></a>').text (name).attr ('title', title).click (function () {
                insertSummary ($for, text);
            })
        );
    }
});

$(function () {
    $('input.mw-summary, input#wpSummary').each (function () {
        var $this = $(this);
        $('<span></span>').attr ('id', 'userSummaryButtonsA').addSumButton (
            $this, 'викиф.', 'викификация', 'Произведена викификация').addSumButton (
            $this, 'оформл.', 'оформление', 'Улучшено оформление').addSumButton (
            $this, 'стиль', 'стилистические правки', 'Переменён стиль изложения').addSumButton (
            $this, 'орфогр.', 'орфография', 'Поправлена орфография').addSumButton (
            $this, 'опеч.', 'зачистка опечаток', 'Исправлена опечатка').addSumButton (
            $this, 'типогр.', 'типографика', 'Поправлена типографика').addSumButton (
            $this, 'пункт.', 'пунктуация', 'Изменена пунктуация').addSumButton (
            $this, 'сноски', '[[Справка:Сноски|сноски]]', 'Оформлены сноски').addSumButton (
            $this, 'кат.', 'категория', 'Исправлена категоризация').addSumButton (
            $this, 'шаб.', 'шаблон', 'Добавлен / изменён шаблон').addSumButton (
            $this, 'к удал.', 'к удалению', 'Страница предложена к удалению').addSumButton (
            $this, 'доп.', 'дополнение', 'Добавлены новые сведения').addSumButton (
            $this, 'иллюстрация', 'иллюстрация', 'Размещена иллюстрация').addSumButton (
            $this, 'обнов.', 'обновление данных', 'Обновлены устаревшие данные').addSumButton (
            $this, 'семант.', 'семантика', 'Добавлены аннотации'
        ).insertAfter ($this).before('<br />');
    });
});

/*
 * Викификатор
 */

// '''ВНИМАНИЕ! Внося изменения в код, не забывайте обновлять справку на странице [[Традиция:Викификатор]]''' 

var wmVersion = '2012-09-16'
var wmCantWork = 'Викификатор не может работать в Вашем браузере\n\nWikificator cannot work in your browser'
var wmTalkPage = 'Викификатор не обрабатывает страницы обсуждения целиком.\n\nВыделите Ваше сообщение — обработано будет только оно'

// Функция викифицирует переданный текст и возвращает викифицированный:
function wikifyText (s) {
    var txt='', hidden = [];

    var u = '\u00A0'; // -- unbreakable space.
    if (wgNamespaceNumber % 2 == 1 || wgNamespaceNumber == 4) { // -- это обсуждение.
        u = ' ';
        // Несколько дат, вероятно, чужие подписи::
        var sigs = s.match (/\d\d:\d\d, \d\d? \S{3,8} 20\d\d \(UTC\)/g);
            if (sigs && sigs.length > 1) {
                alert(wmTalkPage);
                return s;
             }
    }

    // Скрытие преформатированных тегов:
    s = hideTag (s, 'nowiki');
    s = hideTag (s, 'pre');
    s = hideTag (s, 'source');
    s = hideTag (s, 'code');
    s = hideTag (s, 'tt');

    s = hideTag (s, 'math'); // — внутристрочные формулы.
    s = hideTag (s, 'gallery'); // — галереи.
    s = hide (s, /{\{[\s\S]+?}}/g); // — шаблоны.
    s = hide (s, /^ .*/mg); // — преформатированный текст.
    s = hide (s, /(https?|ftp|news|nntp|telnet|irc|gopher):\/\/[^\s\[\]<>"]+ ?/gi); // — гиперссылки.
    s = hide (s, /^#(redirect|перенапр(авление)?)/i); // — перенаправления.

    s = s.replace (/ +(\n|\r)/g, '$1'); // -- пробелы в конце строки.
    s = '\n' + s + '\n';

    var replacements1 = [
        // Русификация пространств имён:
        [/(\[\[:?)(category|категория):( *)/ig, '$1Категория:']
      , [/(\[\[:?)(image|изображение|file):( *)/ig, '$1Файл:']
        // Оформление дат:
      , [/(\(|\s)(\[\[[12]?\d{3}\]\])[\u00A0 ]?(-{1,3}|–|—) ?(\[\[[12]?\d{3}\]\])(\W)/g, '$1$2—$4$5']
      , [/(\[\[[12]?\d{3}\]\]) ?(гг?\.)/g, '$1' + u + '$2']
      , [/(\(|\s)(\[\[[IVX]{1,5}\]\])[\u00A0 ]?(-{1,3}|–|—) ?(\[\[[IVX]{1,5}\]\])(\W)/g, '$1$2—$4$5']
      , [/(\[\[[IVX]{1,5}\]\]) ?(вв?\.)/g, '$1' + u + '$2']
      , [/\[\[(\d+)\]\][\u00A0 ]год/g, '[[$1' + u + 'год]]']
      , [/\[\[((\d+)(?: (?:год )?в [\wa-яёА-ЯЁ ]+\|\2)?)\]\][\u00A0 ](год[а-яё]*)/g, '[[$1' + u + '$3]]']
      , [/\[\[([XVI]+)\]\][\u00A0 ]век/g, '[[$1' + u + 'век]]']
      , [/\[\[(([XVI]+) век\|\2)\]\][\u00A0 ]век/g, '[[$2' + u + 'век]]']
      // Удаление недопустимых символов из викиссылок:
      , [/(\[\[[^|\[\]]*)[\u00AD\u200E\u200F]+([^\[\]]*\]\])/g, '$1$2'] // -- Soft Hyphen & DirMark.
      , [/\[\[ *([a-zA-Zа-яёА-ЯЁ\u00A0-\u00FF %!\"$&'()*,\-.\/0-9:;=?\\@\^_`’~]+) *\| *(\1)([a-zа-яё]*) *\]\]/g, '[[$2]]$3'] // -- ".
      , [/\[\[ *([a-zA-Zа-яёА-ЯЁ\u00A0-\u00FF %!\"$&'()*,\-.\/0-9:;=?\\@\^_`’~]+) *\| *([^|[\]]+) *\]\]([a-zа-яё]+)/g, '[[$1|$2$3]]'] // -- ".
     ];
     s = runReplacements (s, replacements1);
     s = hide (s, /\[\[[^\]|]+/g); // -- скрытие викиссылок.

    // Все теги в <> надо обработать здесь:
    var replacements2 = [
        // HTML -> викитекст:
        [/<<(\S.+\S)>>/g, '"$1"'] // -- угловые кавычки в обычные. Или лучше в «»?
      , [/(sup>|sub>|\s)-(\d)/g, '$1−$2'] // -- minus в индексах.
      , [/(<sup>2<\/sup>|&sup2;)/gi, '²'] // -- символы квадрата
      , [/(<sup>3<\/sup>|&sup3;)/gi, '³'] //    и куба.
      , [/<(b|strong)>(.*)<\/(b|strong)>/gi,"'''$2'''"] // -- вики-полужирный.
      , [/<(i|em)>(.*)<\/(i|em)>/gi,"''$2''"] // -- вики-курсив.
      , [/^<hr ?\/?>/gim, '----'] // -- вики-гор. разделитель.
      , [/<\/?(hr|br)( [^\/>]+?)? ?\/?>/gi, '<$1$2 />'] // оформление hr/br по стандарту XML.
      , [/(\n==\s*Примечания\s*==\n)<references *\/>/,'$1{{примечания}}']

        // .,… до сносок -- сдвиг сносок:
      , [/\s*,\s*((<ref[^<\/>]*?(>[^<]+?<\/ref|\/)>)+)/gi , '{{,}}$1']   // -- запятая до;
      , [/\s*(…)\s*((<ref[^<\/>]*?(>[^<]+?<\/ref|\/)>)+)/gi , '{{,|$1}}$2']   // -- др. знак до;
      , [/\s*\.\s*((<ref[^<\/>]*?(>[^<]+?<\/ref|\/)>)+)/gi, '{{тчк}}$1'] // -- точка до;

        // .,… после сносок -- перенос до и сдвиг сносок:
      , [/\s*((<ref[^<\/>]*?(>[^<]+?<\/ref|\/)>)+)\s*(?:,|\{\{(?:,|зпт)\}\})/gi , '{{,}}$1']   // -- запятая после;
      , [/\s*((?:<ref[^<\/>]*?(?:>[^<]+?<\/ref|\/)>)+)\s*([…])/gi , '{{,|$2}}$1']   // -- др. знак после;
      , [/\s*((<ref[^<\/>]*?(>[^<]+?<\/ref|\/)>)+)\s*(?:\.|\{\{(?:,\|\.|тчк)\}\})/gi, '{{тчк}}$1'] // -- точка после;

        // !? после сносок -- перенос до:
      , [/\s*((?:\<ref[^<\/>]*?(?:\>[^<]+?<\/ref|\/)>)+)([!?;:“])/gi , '$2$1']   // -- !? после;

        // !?;:“» до сносок -- удаление лишних пробелов:
      , [/\s*([!?;:“»])\s+((<ref[^<\/>]*?(>[^<]+?<\/ref|\/)>)+)/gi , '$1$2']   // -- др. знак до;

    ];
    s = runReplacements (s, replacements2);
    s = hide(s, /<[a-z][^>]*?>/gi);

    s = hide(s, /^({\||\|-).*/mg); // // -- таблицы и ряды.
    s = hide(s, /(^\||^!|!!|\|\|) *[a-z]+=[^|]+\|(?!\|)/mgi); // -- стили ячеек.
    s = hide(s, /\| +/g) // -- форматированные ячейки.
    s = hide(s, /IS[BS]N[\s\d\-]{9,18}/g) // -- ISBN/ISSN.

    s = s.replace (/[ \t]+/g, ' '); // -- двойные пробелы.

    var replacements3 = [
        // Заголовки:
        [/^(=+)[ \t\f\v]*(.*?)[ \t\f\v]*=+$/gm, '$1 $2 $1'] // -- окружить пробелами.
      , [/([^\r\n])(\r?\n==.*==\r?\n)/g, '$1\n$2'] // -- пустую строку впереди.
      , [/^== см(\.?|отрите) ?так\s*же ==$/gmi, '== См. также =='] // -- «См. также».
      , [/^== сноски ==$/gmi, '== Примечания ==']
      , [/^== (.+)[.:] ==$/gm, '== $1 =='] // -- точка или двоеточие в конце.

      , [/«|»|“|”|„/g, '"'] // -- временное скрытие нормальных кавычек. Нужно ли?

        // Тире и дефисы:
      , [/–/g, '-']                    // -- &ndash; → -
      , [/&(#151|[nm]dash);/g, '—']     // -- мнемоника тире → —
      , [/(&nbsp;|\s)-{1,3} /g, '$1— '] // -- отбитые - → —
      , [/(\d)-{1,2}(\d)/g, '$1—$2']    // -- -/-- между цифрами → —
      , [/(\s)-(\d)/g, '$1−$2']         // -- отбитый - перед цифрой → −

        // Мнемоники HTML -> символы:
      , [/&#x([0-9a-f]{1,4});/gi, function(n,a){return String.fromCharCode(eval('0x'+a.substr(-4)))}]  //&#x301;
      , [/&copy;/gi,'©']
      , [/&reg;/gi,'®']
      , [/&sect;/gi,'§']
      , [/&euro;/gi,'€']
      , [/&yen;/gi,'¥']
      , [/&pound;/gi,'£']
      , [/&deg;/g,'°']
      , [/\(tm\)|\(тм\)|&trade;/gi,'™']
      , [/\.\.\.|&hellip;/g,'…']
      , [/\+-|&plusmn;/g,'±']
      , [/~=/g,'≈']
      , [/\^2(\D)/g,'²$1']
      , [/\^3(\D)/g,'³$1']
      , [/&((la|ra|bd|ld)quo|quot);/g,'"']
      , [/([\wа-яА-ЯёЁ])'([\wа-яА-ЯёЁ])/g,'$1’$2'] //'
      , [/№№/g,'№']

        // Годы и века
      , [/(\(|\s)([12]?\d{3})[\u00A0 ]?(-{1,3}|—) ?([12]?\d{3})(?![\w-°])/g, '$1$2—$4']
      , [/([12]?\d{3}) ?(гг?\.)/g, '$1' + u + '$2']
      , [/(\(|\s)([IVX]{1,5})[\u00A0 ]?(-{1,3}|—) ?([IVX]{1,5})(?![\w-°])/g, '$1$2—$4']
      , [/([IVX]{1,5}) ?(вв?\.)/g, '$1' + u + '$2']

        // Сокращения:
      , [/(Т|т)\.\s?е\./g, '$1о есть']
      , [/(Т|т)\.\s?к\./g, '$1ак как']
      , [/(В|в)\sт\. ?ч\./g, '$1 том числе']
      , [/и\sт\.\s?д\./g, 'и' + u + 'т\.' + u + 'д\.']
      , [/и\sт\.\s?п\./g, 'и' + u + 'т\.' + u + 'п\.']
      , [/(Т|т)\.\s?н\./g, '$1\.' + u + 'н\.']
      , [/н\.\s?э\./g, 'н\.' + u + 'э\.']
      , [/(Д|д)(о|\.)\sн\.\s?э\./g, '$1о' + u + 'н\.' + u + 'э\.']
      , [/(\d)[\u00A0 ]?(тыс\.|млн|млрд|трлн|(?:м|с|д|к)?м|[км]г)\.?(?=[,;.]| "?[а-яё-])/g, '$1' + u + '$2']
      , [/(\d)[\u00A0 ](тыс)([^\.А-Яа-яЁё])/g, '$1' + u + '$2.$3']
      , [/ISBN:\s?(?=[\d\-]{8,17})/, 'ISBN ']

        // Пробелы:
      , [/^([#*:]+)[ \t\f\v]*([^ \t\f\v*#:;])/gm, '$1 $2'] // -- в списках.
      , [/(\S) (-{1,3}|—) (\S)/g, '$1' + u + '— $3']
      , [/([А-Я]\.) ?([А-Я]\.) ?([А-Я][а-я])/g, '$1' + u + '$2' + u + '$3']
      , [/([А-Я]\.)([А-Я]\.)/g, '$1 $2']
      , [/([а-я]\.)([А-ЯA-Z])/g, '$1 $2'] // -- после точки.
      , [/([)"а-яa-z\]])\s*,([\[("а-яa-z])/g, '$1, $2'] // -- после точки.
      , [/([)"а-яa-z\]])\s([,;])\s([\[("а-яa-z])/g, '$1$2 $3']
      , [/([^%\/\w]\d+?(?:[.,]\d+?)?) ?([%‰])(?!-[А-Яа-яЁё])/g, '$1' + u + '$2'] // -- проценты.
      , [/(\d) ([%‰])(?=-[А-Яа-яЁё])/g, '$1$2'] // -- 5%-й
      , [/([№§])(\s*)(\d)/g, '$1'+u+'$3']
      , [/\( +/g, '(']
      , [/ +\)/g, ')'] // -- убрать пробелы у внутренних сторон скобок.

        // Температура:
      , [/([\s\d=≈≠≤≥<>("'|])([+±−-]?\d+?(?:[.,]\d+?)?)(([ °^*]| [°^*])[CС])(?=[\s"').,;!?|])/gm, '$1$2' + u + '°C']
      , [/([\s\d=≈≠≤≥<>("'|])([+±−-]?\d+?(?:[.,]\d+?)?)(([ °^*]| [°^*])F)(?=[\s"').,;|!?])/gm, '$1$2' + u + '°F']

        // Десятичная точка → запятая:
      , [/(\s\d+)\.(\d+[\u00A0 ]*[%‰°])/gi, '$1,$2']

        // Союзы, предлоги, частицы, единицы измерения:
      , [/\b(а|в|во|да|до|за|и|к|ко|на|о|об|обо|с|со|у)\s/gi, '$1 '] // -- проклитики
      , [/\s(б|бы|же|ли|ль)\b/gi, ' $1'] // -- проклитики
    ];
    s = runReplacements (s, replacements3);
    
    // Восстановление кавычек: "" → «»:
    for (var i=1; i<=2; i++) {
        s = s.replace (/([\s\u00A0·\x02!|#'"\/(;+-])"([^"]*)([^\s"(|])"([^a-zа-яё])/ig, '$1«$2$3»$4'); //"
    }
    while (/«[^»]*«/.test(txt)) {
        s = s.replace (/«([^»]*)«([^»]*)»/g, '«$1„$2“');
    }

    s = s.substr (1, s.length - 2); // -- удаление начального и конечного пробелов.
    if ('0'.replace('0', '$$') == '$') { // -- $ в регэксах, как всегда, IE особенный.
        for (var i = 0; i < hidden.length; i++) {
            hidden [i] = hidden [i].replace (/\$/g, '$$$$');
        }
    }
    // Раскрытие скрытого в hide ():
    while (hidden.length > 0) {
        s = s.replace ('\x01' + hidden.length + '\x02', hidden.pop ());
    }
    return s;
    // Вспомогательные функции:
    // Выполнение массива замен:
    function runReplacements (s, pairs) {
        jQuery.each (pairs, function () { s = s.replace (this [0], this [1]);});
        return s;
    }
    // Скрытие фрагментов путём окружения \x01 и \x02:
    function hide (txt, re) {
        return txt.replace (re, function (s) {return '\x01' + hidden.push (s) + '\x02'});
    }
    function hideTag (txt, tag) {
        return hide (txt, RegExp ('<' + tag + '( [^>]+)?>[\\s\\S]+?<\\/' + tag + '>', 'gi'));
    }
}