Меню

Главная
Случайная статья
Настройки
MediaWiki:Gadget-qualityArticles.js: различия между версиями
Материал из https://ru.wikipedia.org

/*
Скрипт автоматизирует ряд действия для проекта Добротные статьи:
1. Добавляет ссылку "Номинировать в ДС" в группе "Инструменты" слева для номинации статей на ВП:КДС.
   См. addButtonsNominate
2. На страницы номинаций КДС добавляет кнопки За, Против и Комментарий,
   а для избрирающих - кнопки для избрания статей. См. addButtonsDiscussion
3. Список избирающих задается ниже в isOfficer
4. На страницу ВП:КДС добавляет кнопку для архивирования завершенных обсуждений. См. addButtonsArchive
5. На страницы добротных статей добавляет кнопку "Категории ДС" для изменения категорий. См. addButtonsChangeCategories
*/
var ruWikiQualityArticles = {

        htmlInProgress: '<img alt="" src="//upload.wikimedia.org/wikipedia/commons/thumb/6/6a/Pictogram_voting_wait.svg/17px-Pictogram_voting_wait.svg.png" srcset="//upload.wikimedia.org/wikipedia/commons/thumb/6/6a/Pictogram_voting_wait.svg/26px-Pictogram_voting_wait.svg.png 1.5x, //upload.wikimedia.org/wikipedia/commons/thumb/6/6a/Pictogram_voting_wait.svg/34px-Pictogram_voting_wait.svg.png 2x" data-file-width="250" data-file-height="250" height="17" width="17">',
        htmlSuccess: '<img alt="" src="//upload.wikimedia.org/wikipedia/commons/thumb/f/fb/Yes_check.svg/15px-Yes_check.svg.png" srcset="//upload.wikimedia.org/wikipedia/commons/thumb/f/fb/Yes_check.svg/23px-Yes_check.svg.png 1.5x, //upload.wikimedia.org/wikipedia/commons/thumb/f/fb/Yes_check.svg/30px-Yes_check.svg.png 2x" data-file-width="600" data-file-height="600" height="15" width="15">',
        htmlFailure: '<img alt="" src="//upload.wikimedia.org/wikipedia/commons/thumb/b/ba/Red_x.svg/16px-Red_x.svg.png" srcset="//upload.wikimedia.org/wikipedia/commons/thumb/b/ba/Red_x.svg/24px-Red_x.svg.png 1.5x, //upload.wikimedia.org/wikipedia/commons/thumb/b/ba/Red_x.svg/32px-Red_x.svg.png 2x" data-file-width="600" data-file-height="600" height="16" width="16">',
        htmlNotNeeded: '<img alt="(=)" src="//upload.wikimedia.org/wikipedia/commons/thumb/2/25/Pictogram_voting_neutral.svg/15px-Pictogram_voting_neutral.svg.png" srcset="//upload.wikimedia.org/wikipedia/commons/thumb/2/25/Pictogram_voting_neutral.svg/23px-Pictogram_voting_neutral.svg.png 1.5x, //upload.wikimedia.org/wikipedia/commons/thumb/2/25/Pictogram_voting_neutral.svg/30px-Pictogram_voting_neutral.svg.png 2x" data-file-width="250" data-file-height="250" height="15" width="15">',

        summarySuffix: ' с помощью гаджета QA (v. ' + mw.loader.moduleRegistry['ext.gadget.qualityArticles'].version + ')',

        pageIdCandidates: 5020826, // Википедия:Кандидаты в добротные статьи/Список
        pageIdCategories: 5027966, // Википедия:Добротные статьи/Категории
        pagePrefixList: 'Википедия:Добротные статьи/Список/',

        categories: null,
        'rq': null,

    isOfficer: function () {
        var userName = mw.config.get('wgUserName');
                return false // список избирающих проекта Добротные статьи (в алфавитном порядке)
                                || userName  == 'AnimusVox' // 
                                || userName  == 'Avner' //
                                || userName  == 'Bapak Alex' // 
                                || userName  == 'Christian Valentine' // 
                                || userName  == 'Dmartyn80' //
                                || userName  == 'DZ' //
                                || userName  == 'El Presedente' //
                                || userName  == 'EvaInCat' //
                                || userName  == 'Fastboy' // 
                                || userName  == 'Horim' // 
                                || userName  == 'Kosta1974' //
                                || userName  == 'Melissanda' // 
                                || userName  == 'Pessimist2006' // 
                                || userName  == 'Sir Shurf' //
                                || userName  == 'Triumphato' // 
                                || userName  == 'Vlsergey'//
                                || userName  == 'Vladimir Solovjev' // 
                                || userName  == 'Vicpeters' // 
                                || userName  == 'Voyagerim' // 
                                || userName  == 'Wanwa' // 
                                || userName  == 'WindWarrior' // 
                                || userName  == 'Yuri Rubtcov' // 
                                || userName  == 'Есстествоиспытатель' //
                                || userName  == 'Иван Богданов' //
                                || userName  == 'Люба КБ' //
                                || userName  == 'Полиционер' //
                                || userName  == 'Роман Курносенко' //
                                || userName  == 'Томасина' //
                                || userName  == 'Юлия 70';
        },
    
    getFirstObjectValue: function( obj ) {
                "use strict";
                return obj[Object.keys( obj )[0]];
        },

        queryWikidataToken: function( tokenType ) {
                if ( $.isEmpty( tokenType ) ) {
                        tokenType = 'csrf';
                }

                var d = $.Deferred();

                $.ajax( {
                        type: 'GET',
                        url: mw.config.get( 'wgServer' ) + mw.config.get( 'wgScriptPath' ) + '/api.php' //
                                        + '?format=json' // 
                                        + '&action=query' //
                                        + '&meta=tokens' //
                                        + '&type=' + encodeURIComponent( tokenType ),
                        error: function( jqXHR, textStatus, errorThrown ) {
                                d.reject( textStatus );
                        },
                        success: function( result ) {
                                if ( result.error ) {
                                        d.reject( result.error.info );
                                        return;
                                }

                                var token = ruWikiQualityArticles.getFirstObjectValue( result.query.tokens );
                                if ( typeof token === 'undefined' ) {
                                        d.reject( 'no token in response' );
                                        return;
                                }

                                d.resolve( token );
                        },
                } );

                return d;
        },

        addButtonsDiscussion: function() {
                var isOfficer = ruWikiQualityArticles.isOfficer();
                var commonTitlePrefix = 'Кандидаты в добротные статьи/';
                var commonTitlePrefixLength = commonTitlePrefix.length;

                // check if this is nominations page
                if ( $( ".ruWikiQualityArticlesNavigation" ).size() != 1 )
                        return;

                $( "div#mw-content-text" ).after(
                                '' + '<div id="ruWikiAddOpinionForm" title="Добавление оценки для статьи"><form><fieldset>'
                                                + '<p id="ruWikiAddOpinionFormTitle"></p>' 
                                                + '<textarea name="opiniontext" id="ruWikiAddOpinionFormOpinionText" style="height: 150px;" class="text ui-widget-content ui-corner-all"></textarea>'
                                                + '<p class="validateTips" style="color:gray">Поле комментария обязательно к заполнению</p>'
                                                + '<p class="ruWikiAddOpinionFormDesc" style="color:gray"></p>' 
                                                + '<input type="hidden" name="type" id="ruWikiAddOpinionFormOpinionType" value="">'
                                                + '<input type="hidden" name="section" id="ruWikiAddOpinionFormOpinionSectionIndex" value="">'
                                                + '<input type="hidden" name="section" id="ruWikiAddOpinionFormOpinionSectionTitle" value="">' + '</fieldset>' + '</form>' + '</div>' );
                $( "div#ruWikiAddOpinionForm" ).hide();

                $( "div#mw-content-text > h2" ).each( function( index ) {
                        var jThis = $( this );

                        var hasSubsection = false;
                        var curr = jThis.next();
                        while ( curr.size() === 1 ) {
                                if ( curr[0].nodeName === "H3" || curr[0].nodeName === "H4" ) {
                                        hasSubsection = true;
                                        break;
                                }
                                if ( curr[0].nodeName === "H2" ) {
                                        break;
                                }
                                curr = curr.next();
                        }
                        if ( hasSubsection ) {
                                return;
                        }

                        var sectionTitle = jThis.find( "span.mw-headline" ).text();
                        var sectionIndexStr;
                        jThis.find( "span.mw-editsection a" ).each( function( i, a ) {
                                var jA = $( a );
                                var editUrl = jA.attr( 'href' );
                                if ( editUrl.indexOf( '&action=edit&' ) !== -1 ) {
                                        sectionIndexStr = editUrl.substring( editUrl.indexOf( '&section=' ) + '&section='.length );
                                }
                        } );
                        if ( typeof sectionIndexStr === 'undefined' ) {
                                mw.log( 'Unable to detect section index for headline «' + sectionTitle + '»' );
                                return;
                        }

                        jThis.css( 'clear', 'both' );

                        var div = $( document.createElement( 'div' ) ).css( {
                                float: 'right'
                        } );
                        $( document.createElement( 'div' ) ) //
                        .addClass( 'ruWikiQualityButton' ).addClass( 'ruWikiQualityButtonOpinion' ) //
                        .data( 'opinion-type', 'За' ).data( 'section-index', sectionIndexStr ).data( 'section-title', sectionTitle )//
                        .text( 'За' ).appendTo( div );
                        $( document.createElement( 'div' ) ) //
                        .addClass( 'ruWikiQualityButton' ).addClass( 'ruWikiQualityButtonOpinion' ) //
                        .data( 'opinion-type', 'Против' ).data( 'section-index', sectionIndexStr ).data( 'section-title', sectionTitle )//
                        .text( 'Против' ).appendTo( div );
                        $( document.createElement( 'div' ) ) //
                        .addClass( 'ruWikiQualityButton' ).addClass( 'ruWikiQualityButtonOpinion' ) //
                        .data( 'opinion-type', 'Комментарий' ).data( 'section-index', sectionIndexStr ).data( 'section-title', sectionTitle )//
                        .text( 'Комментарий' ).appendTo( div );

                        if ( isOfficer ) {
                                $( document.createElement( 'br' ) ).appendTo( div );
                                $( document.createElement( 'div' ) ) //
                                .addClass( 'ruWikiQualityButton' ).addClass( 'ruWikiQualityButtonSummary' ) //
                                .data( 'summary-type', 'yes' ).data( 'section-index', sectionIndexStr ).data( 'section-title', sectionTitle )//
                                .text( 'Избрать' ).appendTo( div );
                                $( document.createElement( 'div' ) ) //
                                .addClass( 'ruWikiQualityButton' ).addClass( 'ruWikiQualityButtonSummary' ) //
                                .data( 'summary-type', 'togood' ).data( 'section-index', sectionIndexStr ).data( 'section-title', sectionTitle )//
                                .text( 'Избрать + в ХС' ).appendTo( div );
                                $( document.createElement( 'br' ) ).appendTo( div );
                                $( document.createElement( 'div' ) ) //
                                .addClass( 'ruWikiQualityButton' ).addClass( 'ruWikiQualityButtonSummary' ) //
                                .data( 'summary-type', 'no' ).data( 'section-index', sectionIndexStr ).data( 'section-title', sectionTitle )//
                                .text( 'Отказать' ).appendTo( div );
                                $( document.createElement( 'div' ) ) //
                                .addClass( 'ruWikiQualityButton' ).addClass( 'ruWikiQualityButtonSummary' ) //
                                .data( 'summary-type', 'toobig' ).data( 'section-index', sectionIndexStr ).data( 'section-title', sectionTitle )//
                .text( 'Отказать + в ХС/ИС' ).appendTo( div );
                        }

                        jThis.after( div );
                } );

                $( "div.ruWikiQualityButton" ).button();
                $( "div.ruWikiQualityButtonOpinion" ).click( function( event ) {
                        var opinionType = $( this ).data( 'opinion-type' );
                        var sectionIndex = $( this ).data( 'section-index' );
                        var sectionTitle = $( this ).data( 'section-title' );

                        var opinionFormDiv = $( "div#ruWikiAddOpinionForm" );
                        var opinionFormDivDesc = opinionFormDiv.find( 'p.ruWikiAddOpinionFormDesc' );
                        var opinionTextField = opinionFormDiv.find( '#ruWikiAddOpinionFormOpinionText' );
                        var opinionTypeField = opinionFormDiv.find( '#ruWikiAddOpinionFormOpinionType' );
                        var opinionSectionIndexField = opinionFormDiv.find( '#ruWikiAddOpinionFormOpinionSectionIndex' );
                        var opinionSectionTitleField = opinionFormDiv.find( '#ruWikiAddOpinionFormOpinionSectionTitle' );
                        var allFields = $( [] ).add( opinionTextField ).add( opinionTypeField ).add( opinionSectionIndexField ).add( opinionSectionTitleField );
                        var tips = opinionFormDiv.find( 'p.validateTips' );
            var addOpinionFormTitle = 'Комментарий для статьи «' + sectionTitle + '»:';

            if (opinionType == 'За') {
                addOpinionFormTitle = 'Комментарий к оценке <img src="https://upload.wikimedia.org/wikipedia/commons/thumb/c/c2/Pictogram_voting_support.svg/15px-Pictogram_voting_support.svg.png"/>'
                  + '<b>За</b> для статьи «' + sectionTitle + '»:';
            } else if (opinionType == 'Против') {
                addOpinionFormTitle = 'Комментарий к оценке <img src="https://upload.wikimedia.org/wikipedia/commons/thumb/e/e9/Pictogram_voting_oppose.svg/15px-Pictogram_voting_oppose.svg.png"/>'
                  + '<b>Против</b> для статьи «' + sectionTitle + '»:';
            } 
            $ ("#ruWikiAddOpinionFormTitle").html(addOpinionFormTitle);
            opinionFormDivDesc.text( 'Шаблон {{' + opinionType + '}} и подпись участника (' + '~' + '~' + '~' + '~' + ') будут добавлены автоматически ' );
                        opinionTypeField.val( opinionType );
                        opinionSectionIndexField.val( sectionIndex );
                        opinionSectionTitleField.val( sectionTitle );

                        opinionFormDiv.dialog( {
                                autoOpen: false,
                                height: 'auto',
                                width: 600,
                                modal: true,
                                buttons: {
                                        "Добавить оценку": function() {
                                                var bValid = true;
                                                allFields.removeClass( "ui-state-error" );
                                                bValid = bValid && ruWikiQualityArticles.checkNotEmpty( opinionTextField );

                                                if ( bValid ) {
                                                        $( this ).dialog( "close" );

                                                        var type = opinionTypeField.val();
                                                        var sectionIndex = opinionSectionIndexField.val();
                                                        var sectionTitle = opinionSectionTitleField.val();
                                                        var newText = '\r\n* {{' + type + '}} ' + opinionTextField.val() + ' — ~' + '~' + '~' + '~';

                                                        mw.notify( 'Идёт получение токена редактирования...' );
                                                        var d = ruWikiQualityArticles.queryWikidataToken();
                                                        d.fail( function( textStatus ) {
                                                                alert( 'Редактирование невозможно: ' + textStatus );
                                                                return;
                                                        } );
                                                        d.done( function( editToken ) {
                                                                mw.notify( 'Сохранение нового текста статьи...' );
                                                                $.ajax( {
                                                                        type: 'POST',
                                                                        url: mw.config.get('wgServer') + mw.config.get('wgScriptPath') + '/api.php?format=json&action=edit&pageid=' + mw.config.get('wgArticleId') + '&section=' + sectionIndex,
                                                                        data: {
                                                                                summary: '/* ' + sectionTitle + ' */ «' + type + '» ' + ruWikiQualityArticles.summarySuffix,
                                                                                appendtext: newText,
                                                                                token: editToken,
                                                                        },
                                                                        error: function( jqXHR, textStatus, errorThrown ) {
                                                                                alert( "Не удалось сохранить страницу: " + textStatus );
                                                                                return;
                                                                        },
                                                                        success: function( result ) {
                                                                                mw.notify( 'Изменения сохранены. Перезагрузите страницу для отображения изменений' );
                                                                                return;
                                                                        },
                                                                } );
                                                        } );
                                                }
                                        },
                                        "Отменить": function() {
                                                $( this ).dialog( "close" );
                                        }
                                },
                                close: function() {
                                }
                        } );

                        opinionFormDiv.dialog( "open" );
                } );

                $( "div#mw-content-text" )
                                .after(
                                                ''
                                                                + '<div id="ruWikiSummaryForm" title="Подведение итога по статье">'
                                                                + '<form>'
                                                                + '<fieldset>'
                                                                + '<label for="opiniontext" id="ruWikiSummaryFormSummaryTitle">Комментарий:</label> <br />'
                                                                + '<textarea name="opiniontext" id="ruWikiSummaryFormSummaryText" style="height: 120px;" class="text ui-widget-content ui-corner-all"></textarea>'
                                                                + '<p class="validateTips" style="color:gray">Поле комментария обязательно к заполнению</p>'
                                                                + '<p class="ruWikiSummaryFormDesc" style="color:gray"></p>'
                                                                + '<span class="ruWikiSummaryCategorySpan">'
                                                                + '<p id="ruWikiSummaryFormTitle"><br/>А также укажите подходящую категорию из <a href="https://ru.wikipedia.org/wiki/Википедия:Добротные_статьи/Категории">общего списка</a> для размещения статьи на <a href="https://ru.wikipedia.org/wiki/Википедия:ДС">главной странице ВП:ДС</a>:</p>' 
                                                                + '<table border="0"><tr><td><label for="category1">Основная категория:</label></td><td><input type="text" name="category1" class="ruWikiQACategoryTextField" id="ruWikiSummaryFormCategory1" value="" placeholder="Введите первые буквы категории" size="50"></td></tr>'
                                                                + '<tr><td><label for="category2">Доп. категория:</label></td><td><input type="text" name="category2" class="ruWikiQACategoryTextField" id="ruWikiSummaryFormCategory2" value="" size="50"></td></tr>'
                                                                + '<tr><td><label for="category3">Доп. категория 2:</label></td><td><input type="text" name="category3" class="ruWikiQACategoryTextField" id="ruWikiSummaryFormCategory3" value="" size="50"></td></tr></table>'
                                                                + '</span>' 
                                                                + '<input type="hidden" name="type" id="ruWikiSummaryFormSummaryType" value="">'
                                                                + '<input type="hidden" name="section" id="ruWikiSummaryFormSectionIndex" value="">'
                                                                + '<input type="hidden" name="section" id="ruWikiSummaryFormSectionTitle" value="">' + '</fieldset>' + '</form>' + '</div>' );
                $( "div#ruWikiSummaryForm" ).hide();
                
                $( "div#mw-content-text" ).after(
                                '' + '<div id="ruWikiSummaryProgressForm" title="Избрание статьи">' + '<ul>' + '<li><span></span> Получение токена редактирования</li>'
                                                + '<li><span></span> Сохранение итога</li>' + '<li><span></span> Получение таблицы кандидатов</li>'
                                                + '<li><span></span> Сохранение таблицы кандидатов</li>' + '<li><span></span> Получение текста статьи</li>'
                                                + '<li><span></span> Удаление шаблона «Кандидат в добротные статьи»</li>' + '<li><span></span> Сохранение текста статьи</li>'
                                                + '<li><span></span> Получение токена редактирования страницы обсуждения</li>' + '<li><span></span> Сохранение страницы обсуждения</li>'
                                                + '<li><span></span> Получение токена списка основной категории</li>' + '<li><span></span> Пополнение списка основной категории</li>'
                                                + '<li><span></span> Получение токена списка доп. категории</li>' + '<li><span></span> Пополнение списка доп. категории</li>'
                                                + '<li><span></span> Получение токена списка доп. второй категории</li>' + '<li><span></span> Пополнение списка доп. второй категории</li>' + '</div>' );

                var summaryProgressDiv = $( "div#ruWikiSummaryProgressForm" );
                summaryProgressDiv.hide();
                var progressItems = summaryProgressDiv.find( 'li span' );

                $( "div.ruWikiQualityButtonSummary" ).click(
                                function( event ) {
                                        var summaryType = $( this ).data( 'summary-type' );
                                        var sectionIndex = $( this ).data( 'section-index' );
                                        var sectionTitle = $( this ).data( 'section-title' );

                                        var summaryFormDiv = $( "div#ruWikiSummaryForm" );
                                        summaryFormDiv.hide();
                                        var summaryFormDivDesc = summaryFormDiv.find( 'p.ruWikiSummaryFormDesc' );
                                        var summaryCategory1Field = summaryFormDiv.find( '#ruWikiSummaryFormCategory1' );
                                        var summaryCategory2Field = summaryFormDiv.find( '#ruWikiSummaryFormCategory2' );
                                        var summaryCategory3Field = summaryFormDiv.find( '#ruWikiSummaryFormCategory3' );
                                        var summaryTextField = summaryFormDiv.find( '#ruWikiSummaryFormSummaryText' );
                                        var summaryTypeField = summaryFormDiv.find( '#ruWikiSummaryFormSummaryType' );
                                        var summarySectionIndexField = summaryFormDiv.find( '#ruWikiSummaryFormSectionIndex' );
                                        var summarySectionTitleField = summaryFormDiv.find( '#ruWikiSummaryFormSectionTitle' );
                                        var allFields = $( [] ).add( summaryTextField ).add( summaryTypeField ).add( summarySectionIndexField ).add( summarySectionTitleField );
                                        var tips = summaryFormDiv.find( 'p.validateTips' );

                                        var summaryText;
                                        var newStatus;

                    if ( summaryType == "yes" || summaryType == "togood") {
                        summaryFormTitle = 'Комментарий при ' + ruWikiQualityArticles.htmlSuccess + ' <b>избрании статьи</b>:';
                        $ ("#ruWikiSummaryFormSummaryTitle").html(summaryFormTitle);
                        $ ("#ruWikiSummaryFormSummaryText").attr('placeholder', 'Требованиям [[ВП:ТДС]] соответствует.');
                    }
                        
                    if ( summaryType == "yes" ) {
                                                summaryFormDivDesc.text( 'Шаблон {{Сделано|Статья избрана}} и подпись участника (' + '~' + '~' + '~' + '~' + ') будут добавлены автоматически ' );
                                                summaryText = 'Статья «[[' + sectionTitle + ']]» избрана' + ruWikiQualityArticles.summarySuffix;
                                                newStatus = 'accepted';
                                                $( "span.ruWikiSummaryCategorySpan" ).show();
                                        }
                                        if ( summaryType == "togood" ) {
                                                summaryFormDivDesc.text( 'Шаблон {{Сделано|Статья избрана и рекомендована в хорошие}} и подпись участника (' + '~' + '~' + '~' + '~'
                                                                + ') будут добавлены автоматически ' );
                                                summaryText = 'Статья «[[' + sectionTitle + ']]» избрана и рекомендована в хорошие' + ruWikiQualityArticles.summarySuffix;
                                                newStatus = 'accepted';
                                                $( "span.ruWikiSummaryCategorySpan" ).show();
                                        }
                                        if ( summaryType == "no" ) {
                        summaryFormTitle = 'Комментарий при ' + ruWikiQualityArticles.htmlFailure + ' <b>отказе в статусе</b>:';
                        $ ("#ruWikiSummaryFormSummaryTitle").html(summaryFormTitle);
                        $ ("#ruWikiSummaryFormSummaryText").attr('placeholder', 'Подробная причина отказа со ссылками на требования ВП:ТДС');
                                                summaryFormDivDesc.text( 'Шаблон {{Не сделано|Статья не избрана}} и подпись участника (' + '~' + '~' + '~' + '~' + ') будут добавлены автоматически ' );
                                                summaryText = 'Статья «[[' + sectionTitle + ']]» НЕ избрана' + ruWikiQualityArticles.summarySuffix;
                                                newStatus = 'declined';
                                                $( "span.ruWikiSummaryCategorySpan" ).hide();
                                        }
                                        if ( summaryType == "toobig" ) {
                        summaryFormTitle = 'Комментарий при ' + ruWikiQualityArticles.htmlFailure + ' <b>отказе в статусе</b> из-за большого размера:';
                        $ ("#ruWikiSummaryFormSummaryTitle").html(summaryFormTitle);
                                                summaryFormDivDesc.text( 'Шаблон {{Не сделано|Статья не избрана}} и подпись участника (' + '~' + '~' + '~' + '~' + ') будут добавлены автоматически ' );
                        $ ("#ruWikiSummaryFormSummaryText").attr('placeholder', 'Подробная причина отказа со ссылками на требования ВП:ТДС');
                                                summaryText = 'Статья «[[' + sectionTitle + ']]» НЕ избрана' + ruWikiQualityArticles.summarySuffix;
                                                newStatus = 'declined';
                                                $( "span.ruWikiSummaryCategorySpan" ).hide();
                                        }
                                        summaryTypeField.val( summaryType );
                                        summarySectionIndexField.val( sectionIndex );
                                        summarySectionTitleField.val( sectionTitle );
                    
                                        summaryFormDiv
                                                        .dialog( {
                                                                autoOpen: false,
                                                                height: 'auto',
                                                                width: 600,
                                                                modal: true,
                                                                buttons: {
                                                                        "Подвести итог": function() {
                                                                                var bValid = true;
                                                                                allFields.removeClass( "ui-state-error" );
                                                                                bValid = bValid && ruWikiQualityArticles.checkNotEmpty( summaryTextField );
                                                                                if ( !bValid ) {
                                                                                        return;
                                                                                }
                                                                                
                                        if ( summaryType == "yes" || summaryType == "togood" ) {
                                            bValid = bValid && ruWikiQualityArticles.checkNotEmpty( summaryCategory1Field );
                                            if ( !bValid ) {
                                                return;
                                            }
                                        }

                                                                                $( this ).dialog( "close" );

                                                                                var newText;
                                                                                if ( summaryType == "yes" ) {
                                                                                        newText = "\r\n=== Итог ===\r\n{{Сделано|Статья избрана}} " + summaryTextField.val() + " — ~" + "~" + "~" + "~\r\n";
                                                                                }
                                                                                if ( summaryType == "no" || summaryType == "toobig") {
                                                                                        newText = "\r\n=== Итог ===\r\n{{Не сделано|Статья не избрана}} " + summaryTextField.val() + " — ~" + "~" + "~" + "~\r\n";
                                                                                }
                                                                                if ( summaryType == "togood" ) {
                                                                                        newText = "\r\n=== Итог ===\r\n{{Сделано|Статья избрана и рекомендована в хорошие}} " + summaryTextField.val() + " — ~" + "~" + "~"
                                                                                                        + "~\r\n";
                                                                                }
                                                                                var categoriesNames = [ summaryCategory1Field.val(), summaryCategory2Field.val(), summaryCategory3Field.val() ];
                                                                                var type = summaryTypeField.val();
                                                                                var sectionIndex = summarySectionIndexField.val();
                                                                                var sectionTitle = summarySectionTitleField.val();

                                                                                var newTemplate = '{{Добротная статья';
                                                                                for ( var i = 0; i < 3; i++ ) {
                                                                                        if ( categoriesNames[i] ) {
                                                                                                newTemplate = newTemplate + '|' + categoriesNames[0];
                                                                                        }
                                                                                }
                                                                                newTemplate = newTemplate + '}}';

                                                                                summaryProgressDiv.dialog( {
                                                                                        autoOpen: false,
                                                                                        height: 'auto',
                                                                                        width: 600,
                                                                                        modal: true,
                                                                                        buttons: {
                                                                                                // TODO: jump to section
                                                                                                "Перезагрузить страницу": function() {
                                                                                                        ruWikiQualityArticles.purge();
                                                                                                        return;
                                                                                                }
                                                                                        }
                                                                                } );
                                                                                summaryProgressDiv.dialog( "open" );

                                                                                var funcEmpty = function() {
                                                                                        alert( 'Empty function call (error)' );
                                                                                };
                                                                                var funcs = new Array( 9 ).map( function( x, i ) {
                                                                                        return funcEmpty;
                                                                                } );

                                                                                // Добавление раздела "Итог" на текущую страницу (в текущую секцию)
                                                                                funcs[0] = function() {
                                                                                        ruWikiQualityArticles.apiQueryAndEdit( {
                                                                                                apiQueryInfoArguments: 'pageids=' + mw.config.get('wgArticleId'),
                                                                                                apiEditArguments: 'pageid=' + mw.config.get('wgArticleId') + '&section=' + sectionIndex,
                                                                                                apiEditData: {
                                                                                                        summary: summaryText,
                                                                                                        appendtext: newText,
                                                                                                },
                                                                                                progressItemSpan1: $( progressItems[0] ),
                                                                                                progressItemSpan2: $( progressItems[1] ),
                                                                                                onComplete: funcs[1],
                                                                                        } );
                                                                                };

                                                                                // Замена "inprogress" на новый статус в списке кандидатов
                                                                                funcs[1] = function() {
                                                                                        ruWikiQualityArticles.apiQueryAndEdit( {
                                                                                                apiQueryLastRevisionContent: true,
                                                                                                apiQueryInfoArguments: 'pageids=' + ruWikiQualityArticles.pageIdCandidates,
                                                                                                apiEditArguments: 'pageid=' + ruWikiQualityArticles.pageIdCandidates,
                                                                                                apiEditData: function( pageInfo ) {
                                                                                                        if ( !pageInfo.revisions || !pageInfo.revisions[0] || !pageInfo.revisions[0]['*'] ) {
                                                                                                                alert( 'Невозможно получить текст списка кандидатов' );
                                                                                                                return undefined;
                                                                                                        }
                                                                                                        var content = pageInfo.revisions[0]['*'];
                                                                                                        if ( content.indexOf( '|' + sectionTitle + '|inprogress' ) === -1 ) {
                                                                                                                alert( 'Статья не найдена в списке кандидатов' );
                                                                                                                return undefined;
                                                                                                        }
                                                                                                        content = content.replace( '|' + sectionTitle + '|inprogress', '|' + sectionTitle + '|' + newStatus );
                                                                                                        return {
                                                                                                                summary: summaryText,
                                                                                                                text: content,
                                                                                                        };
                                                                                                },
                                                                                                progressItemSpan1: $( progressItems[2] ),
                                                                                                progressItemSpan2: $( progressItems[3] ),
                                                                                                onComplete: funcs[2],
                                                                                        } );
                                                                                };

                                                                                // Замена шаблона КХС или просто добавление шаблона ДС
                                                                                funcs[2] = function() {
                                                                                        ruWikiQualityArticles.apiQueryAndEdit( {
                                                                                                apiQueryLastRevisionContent: true,
                                                                                                apiQueryInfoArguments: 'titles=' + encodeURIComponent( sectionTitle ),
                                                                                                apiEditArguments: 'title=' + encodeURIComponent( sectionTitle ),
                                                                                                apiEditData: function( pageInfo ) {
                                                                                                        if ( !pageInfo.revisions || !pageInfo.revisions[0] || !pageInfo.revisions[0]['*'] ) {
                                                                                                                alert( 'Невозможно получить текст статьи' );
                                                                                                                return undefined;
                                                                                                        }
                                                                                                        var content = pageInfo.revisions[0]['*'];
                                                                                                        var patt = new RegExp( "\\{\\{Кандидат в добротные статьи\\|([0-9а-я ]*)\\}\\}", "i" );

                                                                                                        var newContent;
                                                                                                        if ( summaryType == "no" || summaryType == "toobig" ) {
                                                                                                                newContent = content.replace( patt, '' );
                                                                                                                if ( content === newContent ) {
                                                                                                                        $( progressItems[5] ).html( ruWikiQualityArticles.htmlFailure );
                                                                                                                } else {
                                                                                                                        $( progressItems[5] ).html( ruWikiQualityArticles.htmlSuccess );
                                                                                                                }
                                                                                                        } else {
                                                                                                                newContent = content.replace( patt, newTemplate );
                                                                                                                if ( content === newContent ) {
                                                                                                                        $( progressItems[5] ).html( ruWikiQualityArticles.htmlFailure );
                                                                                                                        newContent = content + '\n' + newTemplate;
                                                                                                                } else {
                                                                                                                        $( progressItems[5] ).html( ruWikiQualityArticles.htmlSuccess );
                                                                                                                }
                                                                                                        }

                                                                                                        return {
                                                                                                                summary: summaryText,
                                                                                                                text: newContent,
                                                                                                        }
                                                                                                },
                                                                                                progressItemSpan1: $( progressItems[4] ),
                                                                                                progressItemSpan2: $( progressItems[6] ),
                                                                                                onComplete: funcs[3],
                                                                                        } );
                                                                                };

                                                                                // Добавление шаблона {{Сообщение ДС|...}} на страницу обсуждения статьи
                                                                                funcs[3] = function() {
                                                                                        var toAppend;
                                                                                        if ( summaryType == "no" ) {
                                                                                                toAppend = '\r\n{{Сообщение ДС|' + mw.config.get('wgTitle').substring( commonTitlePrefixLength ) 
                                                                + '|{{su' + 'bst:CURRENTDAY}} {{su' + 'bst:CURRENTMONTHNAMEGEN}} {{su' + 'bst:CURRENTYEAR}}|Кандидат}}\r\n';
                                            } else if ( summaryType == "toobig" ) {
                                                                                                toAppend = '\r\n{{Сообщение ДС|' + mw.config.get('wgTitle').substring( commonTitlePrefixLength ) 
                                                                + '|{{su' + 'bst:CURRENTDAY}} {{su' + 'bst:CURRENTMONTHNAMEGEN}} {{su' + 'bst:CURRENTYEAR}}|Кандидат в ХС/ИС}}\r\n';
                                                                                        } else {
                                                                                                toAppend = '\r\n{{Сообщение ДС|' + mw.config.get('wgTitle').substring( commonTitlePrefixLength ) 
                                                                + '|{{su' + 'bst:CURRENTDAY}} {{su' + 'bst:CURRENTMONTHNAMEGEN}} {{su' + 'bst:CURRENTYEAR}}}}\r\n';
                                                                                        }
                                            
                                                                                        ruWikiQualityArticles.apiQueryAndEdit( {
                                                                                                apiQueryInfoArguments: 'titles=' + encodeURIComponent( 'Обсуждение:' + sectionTitle ),
                                                                                                apiEditArguments: 'title=' + encodeURIComponent( 'Обсуждение:' + sectionTitle ) + '&section=0',
                                                                                                apiEditData: {
                                                                                                        summary: summaryText,
                                                                                                        appendtext: toAppend,
                                                                                                },
                                                                                                progressItemSpan1: $( progressItems[7] ),
                                                                                                progressItemSpan2: $( progressItems[8] ),
                                                                                                errorTextInfoObtainFailure: 'Редактирование страницы обсуждения невозможно',
                                                                                                errorTextEditFailure: 'Не удалось сохранить страницу обсуждения',
                                                                                                onComplete: funcs[4],
                                                                                        } );
                                                                                };

                                        // Обновление шаблонов проектов
                                                                                funcs[4] = function() {
                                            if ( summaryType == "no" || summaryType == "toobig") {
                                                funcs[5]();
                                                return;
                                            }    
                                            ruWikiQualityArticles.apiQueryAndEdit( {
                                                apiQueryLastRevisionContent: true,
                                                apiQueryInfoArguments: 'titles=' + encodeURIComponent( 'Обсуждение:' + sectionTitle ),
                                                apiEditArguments: 'title=' + encodeURIComponent( 'Обсуждение:' + sectionTitle ),
                                                apiEditData: function( pageInfo ) {
                                                    if ( !pageInfo.revisions || !pageInfo.revisions[0] || !pageInfo.revisions[0]['*'] ) {
                                                        alert( 'Невозможно получить текст страницы обсуждения статьи' );
                                                        return undefined;
                                                    }
                                                    var content = pageInfo.revisions[0]['*'];
                                                    var firstSectionStart = content.indexOf('==');  
                                                    var newContent;
                                                    if (firstSectionStart >= 0) { // обрабатываем только заголовок страницы обсуждения
                                                        newContent = ruWikiQualityArticles.updateProjectTemplates(content.substring(0, firstSectionStart))
                                                           + content.substring(firstSectionStart, content.length);
                                                    }
                                                    else {
                                                        newContent = ruWikiQualityArticles.updateProjectTemplates(content);
                                                    }
                                                    if ( content === newContent ) {
                                                        return undefined;
                                                    }
                                                    return {
                                                        summary: 'Обновление шаблонов проектов',
                                                        text: newContent,
                                                    };
                                                },
                                                progressItemSpan1: $( progressItems[7] ),
                                                progressItemSpan2: $( progressItems[8] ),
                                                                                                errorTextInfoObtainFailure: 'Редактирование страницы обсуждения невозможно',
                                                                                                errorTextEditFailure: 'Не удалось сохранить страницу обсуждения',
                                                onComplete: funcs[5],
                                            } );
                                                                                };

                                        // Обновление списков категорий 
                                        var addToCategoryIndex = 5;
                                                                                var functionBuilderAdd = function( i ) {
                                                                                        return function() {
                                                                                                if ( summaryType == "no" || summaryType == "toobig" || !categoriesNames[i] ) {
                                                                                                        $( progressItems[9 + 2 * i + 0] ).html( ruWikiQualityArticles.htmlNotNeeded );
                                                                                                        $( progressItems[9 + 2 * i + 1] ).html( ruWikiQualityArticles.htmlNotNeeded );
                                                                                                        funcs[addToCategoryIndex + i + 1]();
                                                                                                        return;
                                                                                                }
                                                                                                ruWikiQualityArticles.addToCategory( {
                                                                                                        title: sectionTitle,
                                                                                                        category: categoriesNames[i],
                                                                                                        progressItemSpan1: $( progressItems[9 + 2 * i + 0] ),
                                                                                                        progressItemSpan2: $( progressItems[9 + 2 * i + 1] ),
                                                                                                        onComplete: funcs[addToCategoryIndex + i + 1],
                                                                                                } );
                                                                                        };
                                                                                }
                                                                                for ( var i = 0; i < 3; i++ ) {
                                                                                        funcs[addToCategoryIndex + i] = functionBuilderAdd( i );
                                                                                }
                                                                                funcs[addToCategoryIndex + 3] = function() {
                                                                                        // no ops
                                                                                };

                                                                                funcs[0]();
                                                                        },
                                                                        "Отменить": function() {
                                                                                $( this ).dialog( "close" );
                                                                        }
                                                                },
                                                                close: function() {
                                                                }
                                                        } );

                                        summaryFormDiv.dialog( "open" );
                    summaryTextField.focus();
                    
                    var summaryTextYes = 'Требованиям [[ВП:ТДС]] соответствует.';
                    var summaryTextTooBig = 'Статья слишком велика для ДС (несоответствие п. 8 [[ВП:ТДС]]). ' 
                                            + 'Рекомендуется доработать её и номинировать в [[ВП:КХС|хорошие]]/[[ВП:КИС|избранные]].';
                    var newSummaryText = $ ("#ruWikiSummaryFormSummaryText").text();
                    if (newSummaryText == '' || newSummaryText == summaryTextYes || newSummaryText == summaryTextTooBig) {
                        if ( summaryType == "yes" || summaryType == "togood") {
                            $ ("#ruWikiSummaryFormSummaryText").text(summaryTextYes);
                        } else if (summaryType == "no") {
                            $ ("#ruWikiSummaryFormSummaryText").text('');
                        } else if (summaryType == "toobig") {
                            $ ("#ruWikiSummaryFormSummaryText").text(summaryTextTooBig);
                        }
                    }
                    
                                        if ( (summaryType == "yes" || summaryType == "togood") && ruWikiQualityArticles.categories == null ) {
                                                ruWikiQualityArticles.loadCategories();
                                        }
                                } );

        },
        loadCategories: function() {
                var progressDialog = $( '<div title="Загрузка списка категорий"><ul><li>' + ruWikiQualityArticles.htmlInProgress + ' Загрузка списка категорий</li></ul></div>' );
                progressDialog.dialog( {
                        autoOpen: false,
                        height: 'auto',
                        width: 'auto',
                        modal: true,
                } );
                progressDialog.dialog( "open" );

                var funcEmpty = function() {
                        alert( 'Empty function call (error)' );
                };
                var funcs = new Array( 3 ).map( function( x, i ) {
                        return funcEmpty;
                } );

                funcs[0] = function() {
                        var uri = mw.config.get('wgServer') + mw.config.get('wgScriptPath') + '/api.php?format=json&action=query&prop=revisions&rvprop=content&pageids=' + ruWikiQualityArticles.pageIdCategories;
                        ruWikiQualityArticles.rq.onreadystatechange = funcs[1];
                        ruWikiQualityArticles.rq.open( "GET", uri, true );
                        ruWikiQualityArticles.rq.send( "" );
                };
                var todayDateStr;
                funcs[1] = function() {
                        if ( this.readyState != 4 )
                                return;
                        if ( this.status != 200 ) {
                                funcs[2]();
                                return;
                        }
                        var responseText = eval( '(' + this.responseText + ')' );
                        var text = ruWikiQualityArticles.getFirstObjectValue( responseText.query.pages ).revisions[0]['*'];
                        if ( !text ) {
                                alert( 'Список категорий не найден' );
                                funcs[2]();
                                return;
                        }
                        var lines = text.split( '\n' );
                        ruWikiQualityArticles.categories = [];

                        for ( var i = 0; i < lines.length; i++ ) {
                                var match1 = /^\*\s+(.*)$/.exec( lines[i] );
                                if ( !match1 ) {
                                        continue;
                                }
                                var categoryNameLevel1 = match1[1];
                                ruWikiQualityArticles.categories.push( {
                                        value: categoryNameLevel1,
                                        label: categoryNameLevel1
                                } );

                                for ( var j = i + 1; lines.length; j++ ) {
                                        var match2 = /^\*\*\s+(.*)$/.exec( lines[j] );
                                        if ( !match2 ) {
                                                i = j - 1;
                                                break;
                                        }
                                        var categoryNameLevel2 = match2[1];
                                        ruWikiQualityArticles.categories.push( {
                                                value: categoryNameLevel2,
                                                label: categoryNameLevel1 + ": " + categoryNameLevel2
                                        } );

                                        for ( var k = j + 1; lines.length; k++ ) {
                                                var match3 = /^\*\*\*\s+(.*)$/.exec( lines[k] );
                                                if ( !match3 ) {
                                                        j = k - 1;
                                                        break;
                                                }
                                                var categoryNameLevel3 = match3[1];
                                                ruWikiQualityArticles.categories.push( {
                                                        value: categoryNameLevel3,
                                                        label: categoryNameLevel1 + ": " + categoryNameLevel2 + ": " + categoryNameLevel3
                                                } );
                                                
                                                for ( var m = k + 1; lines.length; m++ ) {
                            var match4 = /^\*\*\*\*\s+(.*)$/.exec( lines[m] );
                            if ( !match4 ) {
                                k = m - 1;
                                break;
                            }
                            var categoryNameLevel4 = match4[1];
                            ruWikiQualityArticles.categories.push( {
                                value: categoryNameLevel4,
                                label: categoryNameLevel1 + ": " + categoryNameLevel2 + ": " + categoryNameLevel3 + ": " + categoryNameLevel4
                            } );
                        }
                                        }
                                }
                        }

                        ruWikiQualityArticles.categories.sort();
                        $( '.ruWikiQACategoryTextField' ).autocomplete( {
                                source: ruWikiQualityArticles.categories
                        } );

                        funcs[2]();
                };
                funcs[2] = function() {
                        progressDialog.dialog( 'close' );
                };

                funcs[0]();
        },
        addButtonsNominate: function() {
                if (
                // уже ДС
                $( "#qa-message" ).size() !== 0 || $( "#quality-candidate" ).size() !== 0 ||
                // уже ХС
                $( "#ga-message" ).size() !== 0 || $( "#good-candidate" ).size() !== 0 ||
                // уже ИС
                $( "#fa-message" ).size() !== 0 || $( "#featured-candidate" ).size() !== 0 ||
                // Дисамбиги в ДС не выдвигаются
                $( "table#disambig" ).size() !== 0 ||
                // Вообще не статья или режим не просмотра
                mw.config.get('wgNamespaceNumber') !== 0 || mw.config.get('wgAction') !== 'view' ) {
                        return;
                }

                $( "div#mw-content-text" ).after(
            '<div id="ruWikiQualityNominate" title="Выдвижение статьи в добротные">'
            + '<table border="0"><tr><td width="50" align="center">'
            + '<img src="https://upload.wikimedia.org/wikipedia/commons/thumb/6/67/Grey_star_boxed_plus.svg/40px-Grey_star_boxed_plus.svg.png" height="40" width="40"></td><td>'
            + '<p>Перед выдвижением ознакомьтесь с <a href="https://ru.wikipedia.org/wiki/Википедия:ТДС">требованиями к добротным статьям</a></b>.<br/>'
            + 'Пожалуйста, не номинируйте <b>более 3 статей в день</b>. Если номинируете статью впервые, укажите это при номинировании и дождитесь итога по первой номинации, прежде чем действовать дальше.</p>' 
            + '</td></tr></table>'
            + '<form><fieldset>'
            + '<textarea name="opiniontext" id="ruWikiQualityNominateComment" style="height: 150px;" class="text ui-widget-content ui-corner-all"></textarea>'
            + '</fieldset></form>'
            + '<p class="validateTips" style="color:gray">Поле комментария обязательно к заполнению,<br/>ваша подпись будет добавлена автоматически.</p>'
            + '</div>' );            

                var nominateFormDiv = $( "div#ruWikiQualityNominate" );
                nominateFormDiv.hide();
                var nominateCommentField = nominateFormDiv.find( '#ruWikiQualityNominateComment' );
                var allFields = $( [] ).add( nominateCommentField );
                var tips = nominateFormDiv.find( 'p.validateTips' );

                nominateFormDiv.dialog( {
                        autoOpen: false,
                        height: 'auto',
                        width: 600,
                        modal: true,
                        buttons: {
                                "Номинировать": function() {
                                        var bValid = true;
                                        allFields.removeClass( "ui-state-error" );
                                        bValid = bValid && ruWikiQualityArticles.checkNotEmpty( nominateCommentField );

                                        if ( bValid ) {
                                                $( this ).dialog( "close" );
                                                ruWikiQualityArticles.nominateImpl();
                                        }
                                },
                                "Отменить": function() {
                                        $( this ).dialog( "close" );
                                }
                        }
                } );

                $( "div#mw-content-text" ).after('<div id="ruWikiNominateProgressForm" title="Номинирование статьи">' + '<ul>'
                                         + '<li id="ruWikiNominateProgressFormItem1"><span></span> Определение текущей даты по серверу</li>'
                                         + '<li><span></span> Получение токена редактирования</li>' + '<li><span></span> Добавление шаблона «Кандидат в добротные статьи»</li>'
                                         + '<li><span></span> Получение токена редактирования таблицы кандидатов</li>' + '<li><span></span> Добавление строки в таблицу кандидатов</li>'
                                         + '<li><span></span> Получение токена редактирования страницы обсуждения</li>'
                                         + '<li><span></span> Добавление секции на страницу обсуждения</li>' + '</div>' );

                var nominateProgressDiv = $( "div#ruWikiNominateProgressForm" );
                nominateProgressDiv.hide();

                $( "#p-tb div ul" ).append(
                                $( '<li class="plainlinks"></li>' ).append( $( document.createElement( 'a' ) ).text( 'Номинировать в ДС' ).css( 'cursor', 'pointer' ).click( function() {
                                        ruWikiQualityArticles.nominate();
                                } ) ) );
        },
        nominate: function() {
                var nominateFormDiv = $( "div#ruWikiQualityNominate" );
                nominateFormDiv.dialog( "open" );
                var nominateCommentField = nominateFormDiv.find( '#ruWikiQualityNominateComment' );
                nominateCommentField.focus();
        },
        nominateImpl: function() {
                var commonTitlePrefix = 'Википедия:Кандидаты в добротные статьи/';
                var summaryEditCurrentArticle = '[[ВП:КДС|Номинирование статьи в добротные]]' + ruWikiQualityArticles.summarySuffix;
                var summaryEditNotCurrentArticle = 'Номинирование статьи «[[' + mw.config.get('wgTitle') + ']]»' + ruWikiQualityArticles.summarySuffix;

                var nominateFormDiv = $( "div#ruWikiQualityNominate" );
                var nominateCommentField = nominateFormDiv.find( '#ruWikiQualityNominateComment' );

                var nominateProgressDiv = $( "div#ruWikiNominateProgressForm" );
                var nominateProgressItem1Li = nominateProgressDiv.find( 'li#ruWikiNominateProgressFormItem1' );
                var progressItems = nominateProgressDiv.find( 'li span' );

                nominateProgressDiv.dialog( {
                        autoOpen: false,
                        height: 'auto',
                        width: 600,
                        modal: true,
                        buttons: {
                                "Перезагрузить страницу": function() {
                                        ruWikiQualityArticles.purge();
                                        return;
                                }
                        }
                } );
                nominateProgressDiv.dialog( "open" );

                var funcEmpty = function() {
                        alert( 'Empty function call (error)' );
                };
                var funcs = new Array( 6 ).map( function( x, i ) {
                        return funcEmpty;
                } );

                funcs[0] = function() {
                        $( progressItems[0] ).html( ruWikiQualityArticles.htmlInProgress );
                        var uri = mw.config.get('wgServer') + mw.config.get('wgScriptPath') + '/api.php?format=json&action=expandtemplates&text=' + encodeURIComponent( '{{CURRENTDAY}} {{CURRENTMONTHNAMEGEN}} {{CURRENTYEAR}}' );
                        ruWikiQualityArticles.rq.onreadystatechange = funcs[1];
                        ruWikiQualityArticles.rq.open( "GET", uri, true );
                        ruWikiQualityArticles.rq.send( "" );
                };
                var todayDateStr;
                funcs[1] = function() {
                        if ( this.readyState != 4 )
                                return;
                        if ( this.status != 200 ) {
                                $( progressItems[0] ).html( ruWikiQualityArticles.htmlFailure );
                                funcs[5]();
                                return;
                        }
                        result = eval( '(' + this.responseText + ')' );
                        todayDateStr = result.expandtemplates['*'];
                        if ( !todayDateStr ) {
                                $( progressItems[0] ).html( ruWikiQualityArticles.htmlFailure );
                                funcs[5]();
                                return;
                        }
                        $( progressItems[0] ).html( ruWikiQualityArticles.htmlSuccess );
                        nominateProgressItem1Li.append( $( "<span> — <b>" + todayDateStr + "</b></span>" ) );
                        funcs[2]();
                };
                // Добавление шаблона {{Кандидат в добротные статьи|...}} на текущую страницу
                funcs[2] = function() {
                        ruWikiQualityArticles.apiQueryAndEdit( {
                                apiQueryInfoArguments: 'pageids=' + mw.config.get('wgArticleId'),
                                apiEditArguments: 'pageid=' + mw.config.get('wgArticleId'),
                                apiEditData: {
                                        summary: summaryEditCurrentArticle,
                                        appendtext: '\r\n{{Кандидат в добротные статьи|' + todayDateStr + '}}\r\n',
                                },
                                progressItemSpan1: $( progressItems[1] ),
                                progressItemSpan2: $( progressItems[2] ),
                                onComplete: funcs[3],
                        } );
                };
                // Добавление строки кандидата на страницу [[Википедия:Кандидаты в добротные статьи/Список]]
                funcs[3] = function() {
                        ruWikiQualityArticles.apiQueryAndEdit( {
                                apiQueryInfoArguments: 'pageids=' + ruWikiQualityArticles.pageIdCandidates,
                                apiEditArguments: 'pageid=' + ruWikiQualityArticles.pageIdCandidates,
                                apiEditData: {
                                        summary: summaryEditNotCurrentArticle,
                                        appendtext: '\r\n' + todayDateStr + '|' + mw.config.get('wgTitle') + '|inprogress',
                                },
                                progressItemSpan1: $( progressItems[3] ),
                                progressItemSpan2: $( progressItems[4] ),
                                errorTextInfoObtainFailure: 'Не удалось получить разрешение на редактирование списка кандидатов',
                                errorTextEditFailure: 'Не удалось обновить список кандидатов',
                                onComplete: funcs[4],
                        } );
                };
                // Добавление обсуждения кандидата на страницу [[Википедия:Кандидаты в добротные статьи/...]], возможно создание новой страницы
                funcs[4] = function() {
                        ruWikiQualityArticles.apiQueryAndEdit( {
                                apiQueryInfoArguments: 'titles=' + encodeURIComponent( commonTitlePrefix + todayDateStr ),
                                apiEditArguments: function( pageInfo ) {
                                        if ( "" === pageInfo.missing ) {
                                                return 'title=' + encodeURIComponent( commonTitlePrefix + todayDateStr ) + '&createonly=1'
                                        } else {
                                                return 'title=' + encodeURIComponent( commonTitlePrefix + todayDateStr ) + '&nocreate=1';
                                        }
                                },
                                apiEditData: function( pageInfo ) {
                                        if ( "" === pageInfo.missing ) {
                                                var newText = "{{Кандидаты в добротные статьи - Навигация}}\r\n\r\n== [[" + mw.config.get('wgTitle') + ']] ==\r\n' + nominateCommentField.val() 
                                + ' — ~' + '~' + '~' + '~\r\n';
                                                return {
                                                        summary: summaryEditNotCurrentArticle,
                                                        text: newText,
                                                };
                                        } else {
                                                var appendText = "\r\n== [[" + mw.config.get('wgTitle') + ']] ==\r\n' + nominateCommentField.val() + ' — ~' + '~' + '~' + '~\r\n';
                                                return {
                                                        summary: summaryEditNotCurrentArticle,
                                                        appendtext: appendText,
                                                };
                                        }
                                },
                                progressItemSpan1: $( progressItems[5] ),
                                progressItemSpan2: $( progressItems[6] ),
                                errorTextInfoObtainFailure: 'Не удалось получить разрешение на редактирование страницы обсуждения кандидатов',
                                errorTextEditFailure: 'Не удалось обновить страницу обсуждения кандидатов',
                                onComplete: funcs[5],
                        } );
                };
                funcs[5] = function() {
                        // finally
                };

                funcs[0]();
        },
        updateTips: function( o, t ) {
                o.addClass( "ui-state-error" );

                tips = $( ".validateTips" );
                tips.text( t ).addClass( "ui-state-highlight" );

                setTimeout( function() {
                        tips.removeClass( "ui-state-highlight", 1500 );
                        o.removeClass( "ui-state-error", 1500 );
                }, 1500 );
        },
        checkNotEmpty: function( o ) {
                if ( o.val().length === 0 ) {
                        ruWikiQualityArticles.updateTips( o, "Поле должно быть заполнено." );
                        return false;
                } else {
                        return true;
                }
        },
        addButtonsArchive: function() {
                $( "div#mw-content-text" ).after(
                                '' + '<div id="ruWikiQAToArchivProgressForm" title="Отправка списка номинаций в архив">' + '<ul>'
                                                + '<li id="ruWikiQAToArchivProgressFormLi1"><span></span> Генерация имени страницы архива</li>'
                                                + '<li><span></span> Получение текущей таблицы кандидатов</li>' + '<li><span></span> Удаление строк из таблицы кандидатов</li>'
                                                + '<li><span></span> Получение информации о служебной странице архива</li>'
                                                + '<li><span></span> Добавление информации на о служебную архива</li>'
                                                + '<li><span></span> Получение информации об отображаемой странице архива</li>'
                                                + '<li><span></span> Создание отображаемой страницы архива, если необходимо</li>' + '</div>' );
                var toArchivProgressForm = $( "div#ruWikiQAToArchivProgressForm" );
                var progressItem1Li = toArchivProgressForm.find( 'li#ruWikiQAToArchivProgressFormLi1' );
                progressItems = toArchivProgressForm.find( 'li span' )
                toArchivProgressForm.dialog( {
                        autoOpen: false,
                        height: 'auto',
                        width: 600,
                        modal: true,
                        buttons: {
                                "Перезагрузить страницу": function() {
                                        ruWikiQualityArticles.purge();
                                        return;
                                }
                        }
                } );

                $( "span.ruWikiQualityCandatatesToArchivButton" ).before( "<br >" ).text( "Отправить в архив" ).button().click( function() {
                        var dateStr = $( this ).data( "date" )
                        toArchivProgressForm.dialog( "open" );

                        var funcEmpty = function() {
                                alert( 'Empty function call (error)' );
                        };
                        var funcs = new Array( 4 ).map( function( x, i ) {
                                return funcEmpty;
                        } );

                        var archiveTitle;
                        var archiveListTitle;
                        var list = '\n';

                        funcs[0] = function() {
                                $( progressItems[0] ).html( ruWikiQualityArticles.htmlInProgress );
                                var tokens = dateStr.split( " " );
                                var month = tokens[1];
                                var monthNumber;
                                switch ( month ) {
                                case 'января':
                                        monthNumber = "01";
                                        break;
                                case 'февраля':
                                        monthNumber = "02";
                                        break;
                                case 'марта':
                                        monthNumber = "03";
                                        break;
                                case 'апреля':
                                        monthNumber = "04";
                                        break;
                                case 'мая':
                                        monthNumber = "05";
                                        break;
                                case 'июня':
                                        monthNumber = "06";
                                        break;
                                case 'июля':
                                        monthNumber = "07";
                                        break;
                                case 'августа':
                                        monthNumber = "08";
                                        break;
                                case 'сентября':
                                        monthNumber = "09";
                                        break;
                                case 'октября':
                                        monthNumber = "10";
                                        break;
                                case 'ноября':
                                        monthNumber = "11";
                                        break;
                                case 'декабря':
                                        monthNumber = "12";
                                        break;
                                default: {
                                        $( progressItems[0] ).html( ruWikiQualityArticles.htmlFailure );
                                        alert( "Неизвестное название месяца: " + month )
                                        return;
                                }
                                }
                                archiveTitle = "ВП:Кандидаты в добротные статьи/Архив/" + tokens[2] + "-" + monthNumber;
                                archiveListTitle = archiveTitle + '/Список';

                                var a1 = $( "<a>" ).attr( "href", mw.config.get('wgServer') + mw.config.get('wgScriptPath') + '/index.php?action=view&title=' + encodeURIComponent( archiveTitle ) )
                                a1.html( '<b style="white-space:nowrap;">' + archiveTitle + '</b>' );
                                progressItem1Li.append( $( '<span>: </span>' ) ).append( a1 );

                                var a2 = $( "<a>" ).attr( "href", mw.config.get('wgServer') + mw.config.get('wgScriptPath') + '/index.php?action=view&title=' + encodeURIComponent( archiveListTitle ) )
                                a2.html( '<b style="white-space:nowrap;">' + archiveListTitle + '</b>' );
                                progressItem1Li.append( $( '<span>; </span>' ) ).append( a2 );

                                $( progressItems[0] ).html( ruWikiQualityArticles.htmlSuccess );

                                ruWikiQualityArticles.apiQueryAndEdit( {
                                        apiQueryLastRevisionContent: true,
                                        apiQueryInfoArguments: 'pageids=' + ruWikiQualityArticles.pageIdCandidates,
                                        apiEditArguments: 'pageid=' + ruWikiQualityArticles.pageIdCandidates,
                                        apiEditData: function( pageInfo ) {
                                                if ( !pageInfo.revisions || !pageInfo.revisions[0] || !pageInfo.revisions[0]['*'] ) {
                                                        alert( 'Невозможно получить текст списка кандидатов' );
                                                        return undefined;
                                                }
                                                var oldContent = pageInfo.revisions[0]['*'];
                                                while ( oldContent.indexOf( dateStr + '|' ) == 0 ) {
                                                        var end = oldContent.indexOf( '\n' );
                                                        var line;
                                                        if ( end == -1 ) {
                                                                line = oldContent + '\n';
                                                                oldContent = '';
                                                        } else {
                                                                line = oldContent.substring( 0, end ) + '\n';
                                                                oldContent = oldContent.substring( end + 1 );
                                                        }
                                                        list = list + line;
                                                }
                                                while ( oldContent.indexOf( '\n' + dateStr + '|' ) != -1 ) {
                                                        var start = oldContent.indexOf( '\n' + dateStr + '|' );
                                                        var end = oldContent.indexOf( '\n', start + 1 );
                                                        var line;
                                                        if ( end == -1 ) {
                                                                line = oldContent.substring( start + 1 ) + '\n';
                                                                oldContent = oldContent.substring( 0, start + 1 );
                                                        } else {
                                                                line = oldContent.substring( start + 1, end ) + '\n';
                                                                oldContent = oldContent.substring( 0, start ) + '\n' + oldContent.substring( end + 1 );
                                                        }
                                                        list = list + line;
                                                }
                                                return {
                                                        summary: '[[' + archiveTitle + '|В архив]]' + ruWikiQualityArticles.summarySuffix,
                                                        text: oldContent,
                                                };
                                        },
                                        progressItemSpan1: $( progressItems[1] ),
                                        progressItemSpan2: $( progressItems[2] ),
                                        errorTextInfoObtainFailure: 'Не удалось получить разрешение на редактирование списка кандидатов',
                                        errorTextEditFailure: 'Не удалось обновить список кандидатов',
                                        onComplete: funcs[1],
                                        onFailure: funcs[3],
                                } );
                        };
                        funcs[1] = function() {
                                ruWikiQualityArticles.apiQueryAndEdit( {
                                        apiQueryInfoArguments: 'titles=' + encodeURIComponent( archiveListTitle ),
                                        apiEditArguments: 'title=' + encodeURIComponent( archiveListTitle ),
                                        apiEditData: {
                                                summary: 'Архивация' + ruWikiQualityArticles.summarySuffix,
                                                appendtext: list
                                        },
                                        progressItemSpan1: $( progressItems[3] ),
                                        progressItemSpan2: $( progressItems[4] ),
                                        errorTextInfoObtainFailure: 'Не удалось получить информацию о служебной странице архива',
                                        errorTextEditFailure: 'Не удалось обновить служебную страницу архива',
                                        onComplete: funcs[2],
                                        onFailure: funcs[3],
                                } );
                        };
                        // Автоматическое создание страницы, отображающей архив
                        funcs[2] = function() {
                                ruWikiQualityArticles.apiQueryAndEdit( {
                                        apiQueryInfoArguments: 'titles=' + encodeURIComponent( archiveTitle ),
                                        apiEditArguments: 'title=' + encodeURIComponent( archiveTitle ) + '&createonly=1',
                                        apiEditData: function( pageInfo ) {
                                                if ( "" === pageInfo.missing ) {
                                                        return {
                                                                summary: 'Автоматическое создание' + ruWikiQualityArticles.summarySuffix,
                                                                text: '{{Навигация по архиву КДС}}\r\n{{Википедия:Кандидаты в добротные статьи/Impl|list={{/Список}}|strike=0}}',
                                                        };
                                                }
                                                return undefined;
                                        },
                                        progressItemSpan1: $( progressItems[5] ),
                                        progressItemSpan2: $( progressItems[6] ),
                                        errorTextInfoObtainFailure: 'Не удалось получить информацию об отображаемой странице архива',
                                        errorTextEditFailure: 'Не удалось получить создать отображаемую страницу архива',
                                        onComplete: funcs[3],
                                } );
                        };
                        funcs[3] = function() {
                                // no op
                        };

                        funcs[0]();
                } );
        },
        addButtonsChangeCategories: function() {
                if (
                // только для ДС
                $( "#qa-message" ).size() === 0 || mw.config.get('wgAction') !== 'view' ) {
                        return;
                }

                $( "div#mw-content-text" )
                                .after(
                                                ''
                                                                + '<div id="ruWikiQAChangeCategoryForm" title="Изменение категорий добротной статьи">'
                                                                + '<form>'
                                                                + '<fieldset>'
                                                                + '<table border="0"><tr><td><label for="category1">Основная категория:</label></td><td><input type="text" name="category1" class="ruWikiQACategoryTextField" id="ruWikiQAChangeCategory1TextField" value="" placeholder="Введите первые буквы категории" size="50"></td></tr>'
                                                                + '<tr><td><label for="category2">Доп. категория:</label></td><td><input type="text" name="category2" class="ruWikiQACategoryTextField" id="ruWikiQAChangeCategory2TextField" value="" size="50"></td></tr>'
                                                                + '<tr><td><label for="category3">Доп. категория 2:</label></td><td><input type="text" name="category3" class="ruWikiQACategoryTextField" id="ruWikiQAChangeCategory3TextField" value="" size="50"></td></tr></table>'
                                                                + '</fieldset>' + '</form>' + '</div>' );
                $( "#ruWikiQAChangeCategoryForm" ).dialog( {
                        autoOpen: false,
                        height: 'auto',
                        width: 600,
                        modal: true,
                        open: function( event, ui ) {
                                var qaMessage = $( '#qa-message' );
                                $( '#ruWikiQAChangeCategory1TextField' ).val( qaMessage.data( 'qa-category-1' ) );
                                $( '#ruWikiQAChangeCategory2TextField' ).val( qaMessage.data( 'qa-category-2' ) );
                                $( '#ruWikiQAChangeCategory3TextField' ).val( qaMessage.data( 'qa-category-3' ) );

                                if ( ruWikiQualityArticles.categories == null ) {
                                        ruWikiQualityArticles.loadCategories();
                                }
                        },
                        buttons: {
                                "Поменять категории": function() {
                                        $( this ).dialog( 'close' );
                                        ruWikiQualityArticles.changeCategoriesImpl();
                                },
                                "Отменить": function() {
                                        $( this ).dialog( 'close' );
                                }
                        }
                } );

                $( "div#mw-content-text" ).after(
                                '' + '<div id="ruWikiQAChangeCategoryProgressForm" title="Изменение категорий добротной статьи">' + '<ul>'
                                                + '<li><span></span> Получение списка основной категории</li>' + '<li><span></span> Добавление в список основной категории</li>'
                                                + '<li><span></span> Получение списка доп. категории</li>' + '<li><span></span> Добавление в список доп. категории</li>'
                                                + '<li><span></span> Получение списка доп. категории 2</li>' + '<li><span></span> Добавление в список доп. категории 2</li>'
                                                + '<li><span></span> Получение списка доп. категории 3</li>' + '<li><span></span> Удаление из списка доп. категории 3</li>'
                                                + '<li><span></span> Получение списка доп. категории 4</li>' + '<li><span></span> Удаление из списка доп. категории 4</li>'
                                                + '<li><span></span> Получение списка доп. категории 5</li>' + '<li><span></span> Удаление из списка доп. категории 5</li>'
                                                + '<li><span></span> Получение текста статьи</li>' + '<li><span></span> Обновление содержимого шаблона</li>' + '</div>' );
                $( "#ruWikiQAChangeCategoryProgressForm" ).hide().dialog( {
                        autoOpen: false,
                        height: 'auto',
                        width: 600,
                        modal: true,
                        buttons: {
                                "Перезагрузить страницу": function() {
                                        ruWikiQualityArticles.purge();
                                        return;
                                }
                        }
                } );

                $( "#p-tb div ul" ).append(
                                $( '<li class="plainlinks"></li>' ).append( $( document.createElement( 'a' ) ).text( 'Категории ДС' ).css( 'cursor', 'pointer' ).click( function() {
                                        ruWikiQualityArticles.changeCategories();
                                } ) ) );
        },
        changeCategories: function() {
                $( "#ruWikiQAChangeCategoryForm" ).dialog( 'open' );
        },
        changeCategoriesImpl: function() {
                var qaMessage = $( '#qa-message' );
                var oldCategory1 = qaMessage.data( 'qa-category-1' );
                var oldCategory2 = qaMessage.data( 'qa-category-2' );
                var oldCategory3 = qaMessage.data( 'qa-category-3' );
                var oldCategories = [ oldCategory1, oldCategory2, oldCategory3 ];
                var newCategory1 = $( '#ruWikiQAChangeCategory1TextField' ).val();
                var newCategory2 = $( '#ruWikiQAChangeCategory2TextField' ).val();
                var newCategory3 = $( '#ruWikiQAChangeCategory3TextField' ).val();
                var newCategories = [ newCategory1, newCategory2, newCategory3 ];

                var changeCategoryProgressForm = $( "div#ruWikiQAChangeCategoryProgressForm" );
                changeCategoryProgressForm.find( 'button' ).button( 'disable' );
                changeCategoryProgressForm.dialog( 'open' );
                var progressItems = changeCategoryProgressForm.find( 'li span' );

                var funcEmpty = function() {
                        alert( 'Empty function call (error)' );
                };
                var funcs = new Array( 8 ).map( function( x, i ) {
                        return funcEmpty;
                } );

                var functionBuilderAdd = function( i ) {
                        return function() {
                                if ( newCategories[i] && $.inArray( newCategories[i], oldCategories ) == -1 ) {
                                        ruWikiQualityArticles.addToCategory( {
                                                title: mw.config.get('wgTitle'),
                                                category: newCategories[i],
                                                progressItemSpan1: $( progressItems[0 + i * 2 + 0] ),
                                                progressItemSpan2: $( progressItems[0 + i * 2 + 1] ),
                                                onComplete: funcs[0 + i + 1],
                                        } );
                                } else {
                                        $( progressItems[0 + i * 2 + 0] ).html( ruWikiQualityArticles.htmlNotNeeded );
                                        $( progressItems[0 + i * 2 + 1] ).html( ruWikiQualityArticles.htmlNotNeeded );
                                        funcs[0 + i + 1]();
                                }
                        }
                };
                var functionBuilderRemove = function( i ) {
                        return function() {
                                if ( oldCategories[i] && $.inArray( oldCategories[i], newCategories ) == -1 ) {
                                        ruWikiQualityArticles.removeFromCategory( {
                                                title: mw.config.get('wgTitle'),
                                                category: oldCategories[i],
                                                progressItemSpan1: $( progressItems[6 + i * 2 + 0] ),
                                                progressItemSpan2: $( progressItems[6 + i * 2 + 1] ),
                                                onComplete: funcs[3 + i + 1],
                                        } );
                                } else {
                                        $( progressItems[6 + i * 2 + 0] ).html( ruWikiQualityArticles.htmlNotNeeded );
                                        $( progressItems[6 + i * 2 + 1] ).html( ruWikiQualityArticles.htmlNotNeeded );
                                        funcs[3 + i + 1]();
                                }
                        }
                };

                for ( var i = 0; i < 3; i++ ) {
                        funcs[0 + i] = functionBuilderAdd( i );
                        funcs[3 + i] = functionBuilderRemove( i );
                }
                funcs[6] = function() {
                        var newTemplate = '{{Добротная статья';
                        for ( var i = 0; i < 3; i++ ) {
                                if ( newCategories[i] ) {
                                        newTemplate = newTemplate + '|' + newCategories[i];
                                }
                        }
                        newTemplate = newTemplate + '}}';

                        ruWikiQualityArticles.apiQueryAndEdit( {
                                apiQueryLastRevisionContent: true,
                                apiQueryInfoArguments: 'titles=' + encodeURIComponent( mw.config.get('wgTitle') ),
                                apiEditArguments: 'title=' + encodeURIComponent( mw.config.get('wgTitle') ),
                                apiEditData: function( pageInfo ) {
                                        if ( !pageInfo.revisions || !pageInfo.revisions[0] || !pageInfo.revisions[0]['*'] ) {
                                                alert( 'Невозможно получить текст статьи' );
                                                return undefined;
                                        }
                                        var content = pageInfo.revisions[0]['*'];
                                        var patt = new RegExp( "\\{\\{Добротная статья[^\\}]*\\}\\}", "i" );
                                        var newContent = content.replace( patt, newTemplate );

                                        if ( content === newContent ) {
                                                $( progressItems[12] ).html( ruWikiQualityArticles.htmlFailure );
                                                $( progressItems[13] ).html( ruWikiQualityArticles.htmlFailure );
                                                alert( "Не могу найти и обновить шаблон {{Добротная статья}} в тексте" );
                                                return undefined;
                                        }
                                        return {
                                                summary: 'Обновление категорий [[ВП:ДС|добротной статьи]]' + ruWikiQualityArticles.summarySuffix,
                                                text: newContent,
                                        };
                                },
                                progressItemSpan1: $( progressItems[12] ),
                                progressItemSpan2: $( progressItems[13] ),
                                onComplete: funcs[7],
                        } );

                };
                funcs[7] = function() {
                        changeCategoryProgressForm.find( 'button' ).button( 'enable' );
                };
                funcs[0]();
        },
        // apiQueryInfoArguments, apiEditArguments, apiEditData,
        // progressItemSpan1, progressItemSpan2, errorTextInfoObtainFailure,
        // errorTextEditFailure
        apiQueryAndEdit: function( args ) {
        var errorTextInfoObtainFailure = args.errorTextInfoObtainFailure ? args.errorTextInfoObtainFailure
                                : 'Не удалось получить информацию о странице (редактирование невозможно)'
                var errorTextEditFailure = args.errorTextEditFailure ? args.errorTextEditFailure : 'Не удалось сохранить изменения'
                var onComplete = args.onComplete ? args.onComplete : function() {
                };
                var onFailure = args.onFailure ? args.onFailure : onComplete;

                args.progressItemSpan1.html( ruWikiQualityArticles.htmlInProgress );
                var uri;
                if ( args.apiQueryLastRevisionContent ) {
                        uri = mw.config.get('wgServer') + mw.config.get('wgScriptPath') + '/api.php?format=json&action=query&prop=' + encodeURIComponent( 'info|revisions' ) + '&intoken=edit&rvprop=content&'
                                        + args.apiQueryInfoArguments;
                } else {
                        uri = mw.config.get('wgServer') + mw.config.get('wgScriptPath') + '/api.php?format=json&action=query&prop=info&intoken=edit&' + args.apiQueryInfoArguments;
                }

                $.ajax( {
                        type: 'GET',
                        url: uri,
                        error: function( jqXHR, textStatus, errorThrown ) {
                                args.progressItemSpan1.html( ruWikiQualityArticles.htmlFailure );
                                args.progressItemSpan2.html( ruWikiQualityArticles.htmlFailure );
                                alert( errorTextInfoObtainFailure + ': ' + textStatus );
                                return;
                        },
                        success: function( result ) {
                var pageInfo = ruWikiQualityArticles.getFirstObjectValue( result.query.pages );
                                var token = pageInfo.edittoken;
                                if ( !token ) {
                                        args.progressItemSpan1.html( ruWikiQualityArticles.htmlFailure );
                                        args.progressItemSpan2.html( ruWikiQualityArticles.htmlFailure );
                                        alert( errorTextInfoObtainFailure );
                                        return;
                                }
                                args.progressItemSpan1.html( ruWikiQualityArticles.htmlSuccess );
                                args.progressItemSpan2.html( ruWikiQualityArticles.htmlInProgress );

                                var apiEditArguments = $.isFunction( args.apiEditArguments ) ? args.apiEditArguments( pageInfo ) : args.apiEditArguments;
                                var apiEditData = ( $.isFunction( args.apiEditData ) ? args.apiEditData( pageInfo ) : args.apiEditData );

                                if ( !$.isEmpty( apiEditData ) ) {
                    apiEditData.token = token;
                                        $.ajax( {
                                                type: 'POST',
                                                url: mw.config.get('wgServer') + mw.config.get('wgScriptPath') + '/api.php?format=json&action=edit' + '&' + apiEditArguments,
                                                data: apiEditData,
                                                error: function( jqXHR, textStatus, errorThrown ) {
                                                        args.progressItemSpan2.html( ruWikiQualityArticles.htmlFailure );
                                                        alert( errorTextEditFailure + ': ' + textStatus );
                                                        onFailure( textStatus );
                                                        return;
                                                },
                                                success: function( result ) {
                                                        // finally
                                                        args.progressItemSpan2.html( ruWikiQualityArticles.htmlSuccess );
                                                        onComplete();
                                                        return;
                                                },
                                        } );

                                } else {
                                        args.progressItemSpan2.html( ruWikiQualityArticles.htmlFailure );
                                        onFailure();
                                }
                        },
                } );
        },
        // title, category, progressItemSpan1, progressItemSpan2, [onComplete, onFailure]
        addToCategory: function( args ) {
                var category = args.category;
                var title = args.title;
                var summaryText = 'Добавление статьи «[[' + title + ']]» в список' + ruWikiQualityArticles.summarySuffix;

                var onComplete = args.onComplete ? args.onComplete : function() {
                };
                var onFailure = args.onFailure ? args.onFailure : onComplete;

                var progress1 = args.progressItemSpan1;
                var progress2 = args.progressItemSpan2;

                var appendtext = '\n[[' + title + ']]';

                ruWikiQualityArticles.apiQueryAndEdit( {
                        apiQueryLastRevisionContent: true,
                        apiQueryInfoArguments: 'titles=' + encodeURIComponent( ruWikiQualityArticles.pagePrefixList + category ),
                        apiEditArguments: 'title=' + encodeURIComponent( ruWikiQualityArticles.pagePrefixList + category ),
                        apiEditData: {
                                summary: summaryText,
                                appendtext: appendtext,
                        },
                        progressItemSpan1: progress1,
                        progressItemSpan2: progress2,
                        errorTextInfoObtainFailure: 'Редактирование списка категории «' + category + '» невозможно',
                        errorTextEditFailure: 'Не удалось дополнить список категории «' + category + '»',
                        onComplete: onComplete,
                        onFailure: onFailure,
                } );
        },
        removeFromCategory: function( args ) {
                var category = args.category;
                var title = args.title;
                var summaryText = 'Удаление статьи «[[' + title + ']]» из списка' + ruWikiQualityArticles.summarySuffix;

                var onComplete = args.onComplete ? args.onComplete : function() {
                };
                var onFailure = args.onFailure ? args.onFailure : onComplete;

                var progress1 = args.progressItemSpan1;
                var progress2 = args.progressItemSpan2;

                ruWikiQualityArticles.apiQueryAndEdit( {
                        apiQueryInfoArguments: 'titles=' + encodeURIComponent( ruWikiQualityArticles.pagePrefixList + category ),
                        apiQueryLastRevisionContent: true,
                        apiEditArguments: 'title=' + encodeURIComponent( ruWikiQualityArticles.pagePrefixList + category ),
                        apiEditData: function( pageInfo ) {
                                if ( !pageInfo.revisions || !pageInfo.revisions[0] || !pageInfo.revisions[0]['*'] ) {
                                        progress1.html( ruWikiQualityArticles.htmlFailure );
                                        progress2.html( ruWikiQualityArticles.htmlFailure );
                                        alert( 'Невозможно получить список категории «' + category + '»' );
                                        return undefined;
                                }
                                var oldContent = pageInfo.revisions[0]['*'] + '\n';
                                if ( oldContent.indexOf( '\n[[' + title + ']]\n' ) === -1 ) {
                                        progress1.html( ruWikiQualityArticles.htmlSuccess );
                                        progress2.html( ruWikiQualityArticles.htmlFailure );
                                        alert( 'Статья не найдена в списке категории «' + category + '»' );
                                        return undefined;
                                }
                                var newListContent = oldContent.replace( '\n[[' + title + ']]\n', '\n' );
                                newListContent = newListContent.substring( 0, newListContent.length - 1 );
                                return {
                                        summary: summaryText,
                                        text: newListContent,
                                };
                        },
                        progressItemSpan1: progress1,
                        progressItemSpan2: progress2,
                        errorTextInfoObtainFailure: 'Редактирование списка категории «' + category + '» невозможно',
                        errorTextEditFailure: 'Не удалось удалить из списка категории «' + category + '»',
                        onComplete: onComplete,
                        onFailure: onFailure,
                } );
        },
        purge: function() {
                window.location.replace( mw.config.get('wgServer') + mw.config.get('wgScriptPath') + '/index.php?action=purge&title=' + encodeURIComponent( mw.config.get('wgPageName') ) );
                return;
        },
    
    updateProjectTemplates: function(content) {
        var patterns = ["\\{\\{статья проекта[^\\}]*\\}\\}", "\\{\\{проект[^\\}]*\\}\\}"];
        var result = content;
        for ( var i = 0; i < patterns.length; i++ ) {
            var patt = new RegExp( patterns[i], "gi" );
            result = result.replace(new RegExp( patterns[i], "gi" ), 
                function (found, offset, s) {
                    var separatorIndex = found.indexOf('\|');
                    if (separatorIndex > 0) {
                        if (found.indexOf('уровень') > 0) {
                            return found.replace(new RegExp('уровень\s*=\s*[A-Za-z0-9А-Яа-я]*', 'i'), 'уровень=ДС');
                        }
                        else { // ранее не было параметра уровень
                            return found.substring(0, separatorIndex) + '\|уровень=ДС' + found.substring(separatorIndex, found.length);
                        }    
                    }
                    else { // статья ранее не была оценена совсем
                        return found.replace('}}', '\|уровень=ДС\|важность=}}');
                    }
            } );
        }
        return result;
    },
};

mediaWiki.loader.using( [ 'jquery.ui.autocomplete', 'jquery.ui.dialog', 'mediawiki.api.edit' ], function() {
        ruWikiQualityArticles.addButtonsDiscussion();
        ruWikiQualityArticles.addButtonsArchive();
        ruWikiQualityArticles.addButtonsNominate();
        ruWikiQualityArticles.addButtonsChangeCategories();
        ruWikiQualityArticles.rq = sajax_init_object();
} );
Downgrade Counter