Медиавики:Gadget-qualityArticles.js
Эзоҳ: Баъди захира намудан, Шумо метавонед тағйиротҳои худро аз хотираи браузер гузариш карда, бубинед. Дар браузерҳои Mozilla / Firefox / Safari: тугмаи Shift-ро пахш намуда бо мушак Reload-ро пахш кунед, ё Ctrl-Shift-R-ро пахш намоед (Cmd-Shift-R барои компютерҳои Apple Mac); дар браузери IE: тугмаи Ctrl-ро пахш намуда бо мушак Refresh-ро пахш намоед, ё Ctrl-F5-ро пахш намоед; дар браузери Konqueror:: бо мушак Reload-ро пахш кунед, ё тугмаи F5-ро пахш намоед; дар браузери Opera ба Шумо пурра тоза кардани хотираи браузер ба воситаи Tools→Preferences лозим аст.
/*
Скрипт автоматизирует ряд действий для проекта Добротные статьи:
1. Добавляет ссылку "Номинировать в ДС" в группе "Инструменты" слева -> номинация статей на ВП:КДС.
См. addButtonsNominate
2. Добавляет ссылку "Номинировать на лишение статуса ДС" в группе "Инструменты" слева -> номинация на снятие статуса ДС.
См. addNominateToCancellationButtons
3. На подстраницах ВП:КДС добавляет кнопки За, Против и Комментарий,
а для избрирающих - кнопки Избрать, Избрать + в ХС, Отказать, Отказать + в ХС/ИС.
См. addButtonsDiscussion
4. На страницу ВП:КДС добавляет кнопку для архивирования завершенных обсуждений.
См. addButtonsArchive
5. На страницы добротных статей добавляет кнопку "Категории ДС" для изменения категорий.
См. addButtonsChangeCategories
Список избирающих задается ниже в isOfficer.
Developers: актуальная разработческая версия скрипта здесь: Участник:Нирваньчик/ds.js
*/
var TgWikiQualityArticles = function() {
var tgWikiQualityArticles = this;
var summarySuffix = TgWikiQualityArticles.summarySuffix;
// Википедиа:Номзад ба мақолаҳои хушсифат/Рӯйхат
var PAGE_ID_CANDIDATES = 5020826;
// Википедиа:Мқолаҳои хушсифат/Гурӯҳҳо
var PAGE_ID_CATEGORIES = 5027966;
var PAGE_PREFIX_LIST = 'Википедиа:Номзад ба мақолаҳои хушсифат/Рӯйхат/';
var PAGE_CANCEL_DISC = this.PAGE_CANCEL_DISC = 'Лоиҳа:Мақолаҳои хушсифат/Маҳруми унвон';
var categories = null;
var COMMONS_UPLOAD = 'https://upload.wikimedia.org/wikipedia/commons/thumb';
var T_ERR = ' Хато!';
var T_OK = ' Бо муваффақият.';
var T_SIGN = '~' + '~' + '~' + '~';
var T_SIGN_A = ' — ' + T_SIGN;
function isOfficer() {
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 == 'EKBCitizen' //
|| userName == 'EvaInCat' //
|| userName == 'Fastboy' //
|| userName == 'Giulini' //
|| userName == 'Horim' //
|| userName == 'Kosta1974' //
|| userName == 'Lapsy' //
|| userName == 'Melissanda' //
|| userName == 'Minina' //
|| userName == 'Pessimist2006' //
|| userName == 'P.Fisxo' //
|| userName == 'Sir Shurf' //
|| userName == 'Triumphato' //
|| userName == 'Vlsergey'//
|| userName == 'Vicpeters' //
|| userName == 'Voyagerim' //
|| userName == 'Vyacheslav84' //
|| userName == 'Wanwa' //
|| userName == 'WindWarrior' //
|| userName == 'Yuri Rubtcov' //
|| userName == 'Есстествоиспытатель' //
|| userName == 'Иван Богданов' //
|| userName == 'Красный Партизан' //
|| userName == 'Люба КБ' //
|| userName == 'Николай Эйхвальд' //
|| userName == 'Полиционер' //
|| userName == 'Роман Курносенко' //
|| userName == 'Томасина' //
|| userName == 'Юлия 70';
};
var notifyOptions = this.notifyOptions = {
autoHide: true,
tag: 'QA-Gadget',
};
var notifyOptOk = notifyOptions;
// Ошибки показываем как ошибки - в красной рамке
// и не убираем чтобы юзер успел прочитать, и закрыть сам.
var notifyOptError = {
autoHide: false,
type: 'error',
};
var getFirstObjectValue = TgWikiQualityArticles.getFirstObjectValue;
var funcArray = function(size) {
var funcEmpty = function() {
alert( 'Empty function call (error)' );
};
var funcs = new Array( size ).map( function( x, i ) {
return funcEmpty;
} );
return funcs;
};
this.addButtonsDiscussion = function() {
// check if this is nominations page
if ( $( "tgWikiQualityArticlesNavigation" ).length != 1 )
return;
var officer = isOfficer();
addButtonsHtmlToKDS(officer);
addOpinionForm();
if (officer) {
addSummaryForm();
}
};
var addButtonsHtmlToKDS = function(officer) {
$( "div#mw-content-text > h2" ).each(
function( index ) {
var jThis = $( this );
var hasSubsection = false;
var curr = jThis.next();
while ( curr.length === 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( '§ion=' ) + '§ion='.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( 'tgWikiQualityButton' ).addClass( 'tgWikiQualityButtonOpinion' ) //
.data( 'opinion-type', 'Тарафдор' ).data( 'section-index', sectionIndexStr ).data( 'section-title', sectionTitle )//
.text( 'Тарафдор' ).appendTo( div );
$( document.createElement( 'div' ) ) //
.addClass( 'tgWikiQualityButton' ).addClass( 'tgWikiQualityButtonOpinion' ) //
.data( 'opinion-type', 'Муқобил' ).data( 'section-index', sectionIndexStr ).data( 'section-title', sectionTitle )//
.text( 'Муқобил' ).appendTo( div );
$( document.createElement( 'div' ) ) //
.addClass( 'tgWikiQualityButton' ).addClass( 'tgWikiQualityButtonOpinion' ) //
.data( 'opinion-type', 'Шарҳ' ).data( 'section-index', sectionIndexStr ).data( 'section-title', sectionTitle )//
.text( 'Шарҳ' ).appendTo( div );
var hintText = 'Внимание: большой процент совпадения может ничего не означать. Например, это нужные цитаты и неперерабатываемые словосочетания, или наоборот, скопировано из статьи Википедии, или сайт является клоном Википедии.';
$( document.createElement( 'br' ) ).appendTo( div );
$( document.createElement( 'div' ) ).html(
' <small><a href="//tools.wmflabs.org/copyvios/?lang=ru&project=wikipedia&oldid=&action=search&use_engine=1&use_links=1&title='
+ encodeURIComponent( sectionTitle )
+ '">Проверить плагиат</a></small>'
+ ' <img title="' + hintText + '" src="' + COMMONS_UPLOAD
+ '/f/fb/Unknown_toxicity_icon.svg/16px-Unknown_toxicity_icon.svg.png" width="16" height="16">' )
.appendTo( div );
if ( officer ) {
$( document.createElement( 'br' ) ).appendTo( div );
$( document.createElement( 'div' ) ) //
.addClass( 'tgWikiQualityButton' ).addClass( 'tgWikiQualityButtonSummary' ) //
.data( 'summary-type', 'yes' ).data( 'section-index', sectionIndexStr ).data( 'section-title', sectionTitle )//
.text( 'Избрать' ).appendTo( div );
$( document.createElement( 'div' ) ) //
.addClass( 'tgWikiQualityButton' ).addClass( 'tgWikiQualityButtonSummary' ) //
.data( 'summary-type', 'togood' ).data( 'section-index', sectionIndexStr ).data( 'section-title', sectionTitle )//
.text( 'Избрать + в ХС' ).appendTo( div );
$( document.createElement( 'br' ) ).appendTo( div );
$( document.createElement( 'div' ) ) //
.addClass( 'tgWikiQualityButton' ).addClass( 'tgWikiQualityButtonSummary' ) //
.data( 'summary-type', 'no' ).data( 'section-index', sectionIndexStr ).data( 'section-title', sectionTitle )//
.text( 'Отказать' ).appendTo( div );
$( document.createElement( 'div' ) ) //
.addClass( 'tgWikiQualityButton' ).addClass( 'tgWikiQualityButtonSummary' ) //
.data( 'summary-type', 'toobig' ).data( 'section-index', sectionIndexStr ).data( 'section-title', sectionTitle )//
.text( 'Отказать + в ХС/ИС' ).appendTo( div );
}
jThis.after( div );
} );
$( "div.tgWikiQualityButton" ).button();
};
var addOpinionForm = function() {
$( "div#mw-content-text" ).after(
'<div id="tgWikiAddOpinionForm" title="Добавление оценки для статьи"><form><fieldset>' + '<p id="tgWikiAddOpinionFormTitle"></p>'
+ '<textarea name="opiniontext" id="tgWikiAddOpinionFormOpinionText" style="height: 150px;" class="text ui-widget-content ui-corner-all"></textarea>'
+ '<p class="validateTips" style="color:gray">Поле комментария обязательно к заполнению</p>'
+ '<p class="tgWikiAddOpinionFormDesc" style="color:gray"></p>' + '<input type="hidden" name="type" id="tgWikiAddOpinionFormOpinionType" value="">'
+ '<input type="hidden" name="section" id="tgWikiAddOpinionFormOpinionSectionIndex" value="">'
+ '<input type="hidden" name="section" id="tgWikiAddOpinionFormOpinionSectionTitle" value="">' + '</fieldset>' + '</form>' + '</div>' );
$( "div#ruWikiAddOpinionForm" ).hide();
$( "div.tgWikiQualityButtonOpinion" ).click(
function( event ) {
var opinionType = $( this ).data( 'opinion-type' );
var sectionIndex = $( this ).data( 'section-index' );
var sectionTitle = $( this ).data( 'section-title' );
var opinionFormDiv = $( "div#tgWikiAddOpinionForm" );
var opinionFormDivDesc = opinionFormDiv.find( 'p.tgWikiAddOpinionFormDesc' );
var opinionTextField = opinionFormDiv.find( '#tgWikiAddOpinionFormOpinionText' );
var opinionTypeField = opinionFormDiv.find( '#tgWikiAddOpinionFormOpinionType' );
var opinionSectionIndexField = opinionFormDiv.find( '#tgWikiAddOpinionFormOpinionSectionIndex' );
var opinionSectionTitleField = opinionFormDiv.find( '#tgWikiAddOpinionFormOpinionSectionTitle' );
var allFields = $( [] ).add( opinionTextField ).add( opinionTypeField ).add( opinionSectionIndexField ).add( opinionSectionTitleField );
var tips = opinionFormDiv.find( 'p.validateTips' );
var addOpinionFormTitle = 'Шарҳ барои мақола «' + sectionTitle + '»:';
if ( opinionType == 'За' ) {
addOpinionFormTitle = 'Шарҳи баҳо <img src="' + COMMONS_UPLOAD
+ '/c/c2/Pictogram_voting_support.svg/15px-Pictogram_voting_support.svg.png"/>'
+ '<b>За</b> для статьи «' + sectionTitle + '»:';
} else if ( opinionType == 'Муқобил' ) {
addOpinionFormTitle = 'Шарҳи баҳо <img src="' + COMMONS_UPLOAD
+ '/e/e9/Pictogram_voting_oppose.svg/15px-Pictogram_voting_oppose.svg.png"/>'
+ '<b>Муқобил</b> барои мақола «' + sectionTitle + '»:';
}
$( "#tgWikiAddOpinionFormTitle" ).html( addOpinionFormTitle );
opinionFormDivDesc.text( 'Шаблон {{' + opinionType + '}} ва имзои корбар (' + T_SIGN + ') бо тарзи автоматӣ илова мешаванд ' );
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 && tgWikiQualityArticles.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() + T_SIGN_A;
var operation = 'Захираи матни нави фасл…';
mw.notify(operation, notifyOptOk);
new mw.Api().postWithEditToken( {
action: 'edit',
pageid: mw.config.get( 'wgArticleId' ),
section: sectionIndex,
summary: '/* ' + sectionTitle + ' */ «' + type + '» ' + summarySuffix,
appendtext: newText,
} ).done( function( result ) {
mw.notify(operation + T_OK + ' Саҳифаро нав кунед, барои намоиши тағйирот', notifyOptOk);
return;
} ).fail( function( jqXHR, textStatus, errorThrown ) {
mw.notify(operation + T_ERR, notifyOptError);
alert( "Саҳифаро захира кардан нашуд: " + textStatus );
return;
} );
}
},
"Лағв": function() {
$( this ).dialog( "close" );
}
},
close: function() {
}
} );
opinionFormDiv.dialog( "open" );
} );
};
var addSummaryForm = function() {
var commonTitlePrefix = 'Номзад ба мақолаҳои хушсифат/';
$( "div#mw-content-text" ).after(
'<div id="tgWikiSummaryForm" title="Подведение итога по статье">'
+ '<form>'
+ '<fieldset>'
+ '<label for="opiniontext" id="tgWikiSummaryFormSummaryTitle">Комментарий:</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="tgWikiSummaryCategorySpan">'
+ '<p id="tgWikiSummaryFormTitle"><br/>А также укажите подходящую категорию из <a href="https://tg.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="tgWikiSummaryFormSummaryType" value="">'
+ '<input type="hidden" name="section" id="tgWikiSummaryFormSectionIndex" value="">'
+ '<input type="hidden" name="section" id="tgWikiSummaryFormSectionTitle" value="">' + '</fieldset>' + '</form>' + '</div>' );
$( "div#ruWikiSummaryForm" ).hide();
$( "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.tgWikiSummaryFormDesc' );
var summaryCategory1Field = summaryFormDiv.find( '#tgWikiSummaryFormCategory1' );
var summaryCategory2Field = summaryFormDiv.find( '#tgWikiSummaryFormCategory2' );
var summaryCategory3Field = summaryFormDiv.find( '#tgWikiSummaryFormCategory3' );
var summaryTextField = summaryFormDiv.find( '#tgWikiSummaryFormSummaryText' );
var summaryTypeField = summaryFormDiv.find( '#tgWikiSummaryFormSummaryType' );
var summarySectionIndexField = summaryFormDiv.find( '#tgWikiSummaryFormSectionIndex' );
var summarySectionTitleField = summaryFormDiv.find( '#tgWikiSummaryFormSectionTitle' );
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>:';
$( "#tgWikiSummaryFormSummaryTitle" ).html( summaryFormTitle );
$( "#tgWikiSummaryFormSummaryText" ).attr( 'placeholder', 'Требованиям [[ВП:ТДС]] соответствует.' );
}
if ( summaryType == "yes" ) {
summaryFormDivDesc.text( 'Шаблон {{Сделано|Статья избрана}} и подпись участника (' + T_SIGN + ') будут добавлены автоматически ' );
summaryText = 'Статья «[[' + sectionTitle + ']]» избрана' + summarySuffix;
newStatus = 'accepted';
$( "span.ruWikiSummaryCategorySpan" ).show();
}
if ( summaryType == "togood" ) {
summaryFormDivDesc.text( 'Шаблон {{Сделано|Статья избрана и рекомендована в хорошие}} и подпись участника (' + T_SIGN
+ ') будут добавлены автоматически ' );
summaryText = 'Статья «[[' + sectionTitle + ']]» избрана и рекомендована в хорошие' + summarySuffix;
newStatus = 'accepted';
$( "span.tgWikiSummaryCategorySpan" ).show();
}
if ( summaryType == "no" ) {
summaryFormTitle = 'Комментарий при <b>отказе в статусе</b>:';
$( "#tgWikiSummaryFormSummaryTitle" ).html( summaryFormTitle );
$( "#tgWikiSummaryFormSummaryText" ).attr( 'placeholder', 'Подробная причина отказа со ссылками на требования ВП:ТДС' );
summaryFormDivDesc.text( 'Шаблон {{Не сделано|Статья не избрана}} и подпись участника (' + T_SIGN + ') будут добавлены автоматически ' );
summaryText = 'Статья «[[' + sectionTitle + ']]» НЕ избрана' + summarySuffix;
newStatus = 'declined';
$( "span.tgWikiSummaryCategorySpan" ).hide();
}
if ( summaryType == "toobig" ) {
summaryFormTitle = 'Комментарий при <b>отказе в статусе</b> из-за большого размера:';
$( "#tgWikiSummaryFormSummaryTitle" ).html( summaryFormTitle );
summaryFormDivDesc.text( 'Шаблон {{Не сделано|Статья не избрана}} и подпись участника (' + T_SIGN + ') будут добавлены автоматически ' );
$( "#tgWikiSummaryFormSummaryText" ).attr( 'placeholder', 'Подробная причина отказа со ссылками на требования ВП:ТДС' );
summaryText = 'Статья «[[' + sectionTitle + ']]» НЕ избрана' + summarySuffix;
newStatus = 'declined';
$( "span.tgWikiSummaryCategorySpan" ).hide();
}
summaryTypeField.val( summaryType );
summarySectionIndexField.val( sectionIndex );
summarySectionTitleField.val( sectionTitle );
summaryFormDiv.dialog( {
autoOpen: false,
height: 'auto',
width: 600,
modal: true,
buttons: {
"Подвести итог": function() {
var success = true;
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 templText;
switch ( summaryType ) {
case "yes": templText = 'Сделано|Статья избрана'; break;
case "no":
case "toobig": templText = 'Не сделано|Статья не избрана'; break;
case "togood": templText = 'Сделано|Статья избрана и рекомендована в хорошие'; break;
}
var newText = "\r\n=== Итог ===\r\n{{" + templText + "}} "
+ 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 + '}}';
var funcs = funcArray(9);
// Добавление раздела "Итог" на текущую страницу (в текущую секцию)
funcs[0] = function() {
var operation = 'Добавление итога на страницу номинации…';
mw.notify(operation, notifyOptOk);
new mw.Api().postWithEditToken( {
action: 'edit',
pageid: mw.config.get( 'wgArticleId' ),
section: sectionIndex,
summary: summaryText,
appendtext: newText
} ).done( function() {
mw.notify(operation + T_OK, notifyOptOk);
funcs[1]();
} ).fail( function() {
success = false;
console.log( arguments );
mw.notify(operation + T_ERR, notifyOptError);
finalize('Ошибка', 'Не удалась операция: ' + operation, 'error');
} );
};
// Замена "inprogress" на новый статус в списке кандидатов
funcs[1] = function() {
tgWikiQualityArticles.changeStatusInList( sectionTitle, 'inprogress', newStatus, summaryText )
.fail(function() { success = false; })
.always( funcs[2] );
};
// Замена шаблона КХС или просто добавление шаблона ДС
funcs[2] = function() {
var operation1 = 'Получение текста номинированной статьи…';
mw.notify(operation1, notifyOptOk);
tgWikiQualityArticles.apiQueryLatestRevision( {
titles: sectionTitle,
} ).done( function( result ) {
var pageInfo = getFirstObjectValue( result.query.pages );
if ( !pageInfo.revisions || !pageInfo.revisions[0] || !pageInfo.revisions[0]['*'] ) {
mw.notify(operation1 + T_ERR, notifyOptError);
success = false;
funcs[3]();
return undefined;
}
mw.notify(operation1 + T_OK, notifyOptOk);
var content = pageInfo.revisions[0]['*'];
var patt = new RegExp( "\\{\\{Кандидат в добротные статьи\\|([0-9а-я ]*)\\}\\}", "i" );
var newContent;
if ( summaryType == "no" || summaryType == "toobig" ) {
newContent = content.replace( patt, '' );
} else {
newContent = content.replace( patt, newTemplate );
if ( content === newContent ) {
newContent = content + '\n' + newTemplate;
}
}
var operation2 = 'Обновление текста номинированной статьи…';
mw.notify(operation2, notifyOptOk);
new mw.Api().postWithEditToken( {
action: 'edit',
nocreate: true,
title: sectionTitle,
summary: summaryText,
text: newContent,
} ).done( function() {
mw.notify(operation2 + T_OK, notifyOptOk);
} ).fail( function() {
success = false;
console.log( arguments );
mw.notify(operation2 + T_ERR, notifyOptError);
} ).always( funcs[3] );
return {};
} ).fail( function() {
success = false;
mw.notify(operation1 + T_ERR, notifyOptError);
funcs[3];
});
};
// Добавление шаблона {{Сообщение ДС|...}} на страницу обсуждения статьи
funcs[3] = function() {
var insert_param = '';
if ( summaryType == "no" ) {
insert_param = '|Кандидат';
} else if ( summaryType == "toobig" ) {
insert_param = '|Кандидат в ХС/ИС';
}
var toAppend = '{{Сообщение ДС|' + mw.config.get( 'wgTitle' ).substring( commonTitlePrefix.length ) + '|'
+ RuWikiQualityArticles.getCurrentDateWikitext() + insert_param + '}}';
appendTemplateToTalkPage('Обсуждение:' + sectionTitle, toAppend, summaryText)
.fail(function() { success = false; })
.always( funcs[4] );
};
// Обновление шаблонов проектов
funcs[4] = function() {
if ( summaryType == "no" || summaryType == "toobig" ) {
funcs[5]();
return;
}
updateProjectTemplates('Обсуждение:' + sectionTitle, 'ДС' )
.fail(function() { success = false; })
.always( funcs[5] );
};
// Обновление списков категорий
var addToCategoryIndex = 5;
for ( var catIndex = 0; catIndex < 3; catIndex++ ) {
funcs[addToCategoryIndex + catIndex] = ( function( i ) {
return function() {
if ( summaryType == "no" || summaryType == "toobig" || !categoriesNames[i] ) {
funcs[addToCategoryIndex + i + 1]();
return;
}
ruWikiQualityArticles.addToCategory( categoriesNames[i], sectionTitle )
//.fail(function() { success = false; }) fail() может не прокатить, см. внутрь функции, надо рефакторить
.always( funcs[addToCategoryIndex + i + 1] );
};
} )( catIndex );
}
funcs[addToCategoryIndex + 3] = function() {
if (success) {
finalize('Всё сделано', 'Все правки завершены успешно', 'info');
} else {
finalize('Завершено', 'Завершено с ошибками. Просмотрите ваш вклад и попробуйте доделать нужные правки вручную.', 'error');
}
};
var finalize = function(title, message, status) {
ruWikiQualityArticles.reloadWithMessage(title, message, status);
};
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" ) && tgWikiQualityArticles.categories == null ) {
tgWikiQualityArticles.loadCategories();
}
} );
};
this.loadCategories = function() {
mw.notify( 'Загружаем список категорий добротных статей', tgWikiQualityArticles.notifyOptions );
fillCategoriesFromWikitext = function( wikitext ) {
var lines = wikitext.split( '\n' );
var repeat = function( x, n ) {
"use strict";
var s = '';
for ( ;; ) {
if ( n & 1 )
s += x;
n >>= 1;
if ( n )
x += x;
else
break;
}
return s;
};
var fill = function( startLine, level, previousLevelPrefix ) {
"use strict";
for ( var lineIndex = startLine; lineIndex < lines.length; lineIndex++ ) {
var re = new RegExp( "^" + repeat( '\\*', level ) + "\\s+(.*)$", "" );
var match = re.exec( lines[lineIndex] );
if ( !match ) {
if ( level == 1 )
continue;
return lineIndex - 1;
}
var categoryName = match[1];
tgWikiQualityArticles.categories.push( {
value: categoryName,
label: previousLevelPrefix + categoryName,
} );
lineIndex = fill( lineIndex + 1, level + 1, previousLevelPrefix + categoryName + ': ' );
}
};
fill( 0, 1, '' );
};
new mw.Api().get( {
action: 'query',
prop: 'revisions',
rvprop: 'content',
pageids: PAGE_ID_CATEGORIES,
} ).done( function( data ) {
var text = data.query.pages[PAGE_ID_CATEGORIES].revisions[0]['*'];
if ( !text ) {
alert( 'Список категорий не найден' );
mw.notify( 'Список категорий добротных статей не найден', ruWikiQualityArticles.notifyOptions );
return;
}
tgWikiQualityArticles.categories = [];
fillCategoriesFromWikitext( text );
ruWikiQualityArticles.categories.sort();
$( '.ruWikiQACategoryTextField' ).autocomplete( {
source: ruWikiQualityArticles.categories
} );
mw.notify( 'Список категорий добротных статей успешно загружен', tgWikiQualityArticles.notifyOptions );
} ).fail( function( jqXHR, textStatus, errorThrown ) {
mw.notify( 'Проблема с загрузкой списка категорий:\n' + textStatus, ruWikiQualityArticles.notifyOptions );
alert( 'Проблема с загрузкой списка категорий:\n' + textStatus );
} );
};
this.addFinalDialog = function() {
$( "div#mw-content-text" ).after(
'<div id="ruWikiQualityFinalDialog" title="Готово">'
+ '<table border="0"><tr><td width="70" align="center" id = "ruWikiQualityFinalIcon">'
+ '</td><td>'
+ '<p id="ruWikiQualityFinalMessage">Успех</p>'
+ '<p id="ruWikiQualityCountDownText">Страница будет перезагружена через <b>10</b> секунд</p>'
+ '</td></tr></table>'
+ '</div>' );
var formDiv = $( "div#ruWikiQualityFinalDialog" );
formDiv.hide();
formDiv.dialog( {
autoOpen: false,
height: 'auto',
width: 600,
modal: true
} );
}
// Simple Countdown class from stackoverflow.com
function Countdown(options) {
var timer,
instance = this,
seconds = options.seconds || 5,
updateStatus = options.onUpdateStatus || function () {},
counterEnd = options.onCounterEnd || function () {};
function decrementCounter() {
updateStatus(seconds);
if (seconds === 0) {
counterEnd();
instance.stop();
}
seconds--;
}
this.start = function () {
clearInterval(timer);
timer = 0;
seconds = options.seconds;
timer = setInterval(decrementCounter, 1000);
};
this.stop = function () {
clearInterval(timer);
};
}
/**
* Покажет диалог с обратным счётчиком, по истечении него перезагрузит страницу.
* status = 'error', 'warn', 'info'
*/
var reloadWithMessage = this.reloadWithMessage = function(title, message, status) {
var formDiv = $( "div#ruWikiQualityFinalDialog" );
formDiv.dialog( "option", "title", title );
formDiv.find( '#ruWikiQualityFinalMessage' ).html(message);
iconTable = {
"info": COMMONS_UPLOAD + '/9/99/Nuvola_apps_important_green.svg/64px-Nuvola_apps_important_green.svg.png',
"warn": COMMONS_UPLOAD +'/d/dc/Nuvola_apps_important_yellow.svg/64px-Nuvola_apps_important_yellow.svg.png',
"error": COMMONS_UPLOAD + '/f/f7/Nuvola_apps_important.svg/64px-Nuvola_apps_important.svg.png'
};
icon = iconTable[status]
if (!icon) {
icon = iconTable["info"]
}
formDiv.find('#ruWikiQualityFinalIcon').html('<img src="'+ icon +'" height="64" width="64">');
var SECONDS_COUNT = 5;
if (status=='error') {
SECONDS_COUNT = 10; // Больше времени чтобы юзер успел обратить внимание и прочитать
}
var countDownText = formDiv.find( '#ruWikiQualityCountDownText' );
countDownText.html('Страница будет перезагружена через <b>' + SECONDS_COUNT + '</b> секунд');
var myCounter = new Countdown({
seconds:SECONDS_COUNT, // number of seconds to count down
onUpdateStatus: function(sec){
console.log(sec);
countDownText.html('Страница будет перезагружена через <b>' + sec + '</b> секунд');
},
onCounterEnd: function(){
formDiv.dialog( "close" );
ruWikiQualityArticles.purge();
}
});
myCounter.start();
formDiv.dialog( "option", "buttons", {
"Перезагрузить сейчас": function() {
$( this ).dialog( "close" );
ruWikiQualityArticles.purge();
},
"Отмена": function() {
$( this ).dialog( "close" );
myCounter.stop();
}
});
formDiv.dialog( "open" );
};
this.addButtonsNominate = function() {
if (
// уже ДС
$( "#qa-message" ).length !== 0 || $( "#quality-candidate" ).length !== 0 ||
// уже ХС
$( "#ga-message" ).length !== 0 || $( "#good-candidate" ).length !== 0 ||
// уже ИС
$( "#fa-message" ).length !== 0 || $( "#featured-candidate" ).length !== 0 ||
// Дисамбиги в ДС не выдвигаются
$( "table#disambig" ).length !== 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="' + COMMONS_UPLOAD + '/6/67/Grey_star_boxed_plus.svg/40px-Grey_star_boxed_plus.svg.png" height="40" width="40"></td><td>'
+ '<p>Перед выдвижением ознакомьтесь с <a href="https://tg.wikipedia.org/wiki/Википедия:ТДС">требованиями к добротным статьям</a></b>.<br/>'
+ 'Пожалуйста, не номинируйте <b>более 3 статей в день</b>. Если номинируете статью впервые, укажите это при номинировании и дождитесь итога по первой номинации, прежде чем действовать дальше.</p>'
+ '</td></tr></table>' + '<form><fieldset>'
+ '<textarea name="opiniontext" id="tgWikiQualityNominateComment" 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( '#tgWikiQualityNominateComment' );
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( nominateCommentField.val() );
}
},
"Отменить": function() {
$( this ).dialog( "close" );
}
}
} );
RuWikiQualityArticles.addToolboxMenuButton( 'Номинировать в ДС', function() {
tgWikiQualityArticles.nominate();
} );
};
function appendTemplateToTalkPage(articleTitle, templateText, summaryText) {
//operation = 'Добавление шаблона сообщения ДС на страницу обсуждения статьи…';
return pageGetEditSave(articleTitle, 'Добавление шаблона сообщения ДС на страницу обсуждения статьи… ',
appendTemplateToTalkPageImpl, {templateText: templateText}, summaryText);
}
function trim(str) {
return str.replace(/^\s+|\s+$/g,"");
}
function appendTemplateToTalkPageImpl(content, params) {
var templateText = params.templateText;
if (!content || 0 === content.length) return templateText;
if (trim(content) == "") return content + templateText;
var regexp1 = /^\s*\{\{/i;
var regexp2 = /^\s*\{\{(Википедия:Рецензирование|Архив|Новые|ВП-проекты)/i;
var next = content.indexOf('\n', 0);
var index = 0, lastT = 0;
for (;index < content.length; index = next+1, next = content.indexOf('\n', index)) {
if (next == -1) next = content.length;
var line = trim(content.substring(index, next));
if (line === "") continue;
if (regexp1.test(line)) {
if (regexp2.test(line)) break;
lastT = next+1;
continue;
}
break;
}
if (lastT > content.length) lastT = content.length;
if (lastT > 0 && content.substr(lastT-1, 1) != '\n') templateText = "\n" + templateText;
return content.substring(0, lastT) + templateText + "\n" + content.substring(lastT);
}
this.changeStatusInList = function( articleTitle, oldStatus, newStatus, summaryText ) {
var d = $.Deferred();
mw.notify( 'Получение служебного списка кандидатов для обновления…', {
tag: 'QA-Gadget::changeStatusInList',
type: 'info',
} );
ruWikiQualityArticles.apiQueryLatestRevision( {
pageids: PAGE_ID_CANDIDATES,
} ).done( function( result ) {
try {
var pageInfo = getFirstObjectValue( result.query.pages );
if ( !pageInfo.revisions || !pageInfo.revisions[0] || !pageInfo.revisions[0]['*'] ) {
mw.notify( 'Получение служебного списка кандидатов для обновления… Неизвестная ошибка!', {
tag: 'QA-Gadget::changeStatusInList',
type: 'error',
} );
alert( 'Невозможно получить текст списка кандидатов' );
d.reject();
return;
}
var content = pageInfo.revisions[0]['*'];
if ( content.indexOf( '|' + articleTitle + '|' + oldStatus ) === -1 ) {
mw.notify( 'Получение служебного списка кандидатов для обновления… Статья не найдена в списке кандидатов!', {
tag: 'QA-Gadget::changeStatusInList',
type: 'error',
} );
alert( 'Статья «' + articleTitle + '» не найдена в списке кандидатов' );
d.reject();
return;
}
mw.notify( 'Обновление служебного списка кандидатов…', {
tag: 'QA-Gadget::changeStatusInList',
type: 'info',
} );
content = content.replace( '|' + articleTitle + '|' + oldStatus, '|' + articleTitle + '|' + newStatus );
new mw.Api().postWithEditToken( {
action: 'edit',
nocreate: true,
pageid: PAGE_ID_CANDIDATES,
summary: summaryText,
text: content,
} ).done( function() {
mw.notify( 'Обновление служебного списка кандидатов… Успешно.', {
tag: 'QA-Gadget::changeStatusInList',
type: 'info',
} );
d.resolve();
} ).fail( function() {
console.log( arguments );
mw.notify( 'Обновление служебного списка кандидатов… Неизвестная ошибка!', {
tag: 'QA-Gadget::changeStatusInList',
type: 'error',
} );
d.reject.apply( d, arguments );
} );
} catch ( error ) {
console.log( error );
mw.notify( 'Обновление служебного списка кандидатов… Неизвестная ошибка!', {
tag: 'QA-Gadget::changeStatusInList',
type: 'error',
} );
d.reject( error );
}
} ).fail( function() {
mw.notify( 'Получение служебного списка кандидатов для обновления… Неизвестная ошибка!', {
tag: 'QA-Gadget::changeStatusInList',
type: 'error',
} );
d.reject.apply( d, arguments );
} );
return d.promise();
};
var nominate = this.nominate = function() {
var nominateFormDiv = $( "div#ruWikiQualityNominate" );
nominateFormDiv.dialog( "open" );
var nominateCommentField = nominateFormDiv.find( '#tgWikiQualityNominateComment' );
nominateCommentField.focus();
};
var nominateImpl = this.nominateImpl = function( nominateComment ) {
var commonTitlePrefix = 'Википедия:Кандидаты в добротные статьи/';
var summaryEditCurrentArticle = '[[ВП:КДС|Номинирование статьи в добротные]]' + summarySuffix;
var summaryEditNotCurrentArticle = 'Номинирование статьи «[[' + mw.config.get( 'wgTitle' ) + ']]»' + summarySuffix;
var funcs = funcArray(8);
var success = true;
funcs[0] = function() {
var operation = 'Определение текущей даты по серверу…';
mw.notify(operation, notifyOptOk );
new mw.Api().get( {
action: 'expandtemplates',
text: '{{CURRENTDAY}} {{CURRENTMONTHNAMEGEN}} {{CURRENTYEAR}}',
} ).done( funcs[1] ).fail( function( jqXHR, textStatus, errorThrown ) {
mw.notify( operation + ' не удалось: ' + textStatus, notifyOptError );
finalize('Ошибка','Не удалась операция: ' + operation + '. Перезагрузите страницу и попробуйте ещё раз', 'warn');
return;
} );
};
var todayDateStr;
funcs[1] = function( data ) {
var operation = 'Определение текущей даты по серверу…';
todayDateStr = data.expandtemplates['*'];
if ( !todayDateStr ) {
console.log( data );
mw.notify( operation + ' не удалось', notifyOptError );
finalize('Ошибка','Не удалась операция: ' + operation + '. Перезагрузите страницу и попробуйте ещё раз', 'warn');
return;
}
mw.notify( 'Определение текущей даты по серверу: «' + todayDateStr + '»', notifyOptOk );
funcs[2]();
};
// Добавление шаблона {{Кандидат в добротные статьи|...}} на текущую страницу
funcs[2] = function() {
var operation = 'Добавление шаблона кандидата в добротные статьи на страницу статьи…';
mw.notify(operation, notifyOptOk );
new mw.Api().postWithEditToken( {
action: 'edit',
pageid: mw.config.get( 'wgArticleId' ),
appendtext: '\r\n{{Кандидат в добротные статьи|' + todayDateStr + '}}\r\n',
summary: summaryEditCurrentArticle,
} ).done( function() {
mw.notify( operation + ' Добавлен.', notifyOptOk );
} ).fail( function( jqXHR, textStatus, errorThrown ) {
mw.notify( operation + ' Не удалось: ' + textStatus, notifyOptError );
success = false;
} ).always( funcs[3] );
};
// Добавление строки кандидата на страницу [[Википедия:Кандидаты в добротные статьи/Список]]
funcs[3] = function() {
var operation = 'Добавление информации о кандидате в служебный список…';
mw.notify(operation, notifyOptOk );
new mw.Api().postWithEditToken( {
action: 'edit',
pageid: PAGE_ID_CANDIDATES,
appendtext: '\r\n' + todayDateStr + '|' + mw.config.get( 'wgTitle' ) + '|inprogress',
summary: summaryEditNotCurrentArticle,
} ).done( function() {
mw.notify(operation + T_OK, notifyOptOk );
} ).fail( function() {
mw.notify(operation + T_ERR, notifyOptError );
success = false;
} ).always( funcs[4] );
};
// Добавление обсуждения кандидата на страницу [[Википедия:Кандидаты в добротные статьи/...]],
// 1) проверяем есть ли такая страница
// 2) Если нет, создаём, если есть, дописываем в неё
var KDE_Title;
funcs[4] = function() {
KDE_Title = commonTitlePrefix + todayDateStr;
new mw.Api().get( {
action: 'query',
prop: 'info',
titles: KDE_Title,
} ).done( function( result ) {
if (Object.keys( result.query.pages )[0] == '-1') {
funcs[5]();
} else {
funcs[6]();
}
} ).fail( function() {
mw.notify( 'Получение информации о существовании статьи ' + KDE_Title + ':' + T_ERR, notifyOptError);
finalize('Ошибка', 'Не удалось определить, существует ли страница ' + KDE_Title +'\nПожалуйста, добавьте обсуждение вручную.', 'error');
} );
};
funcs[5] = function() {
"use strict";
var operation = 'Создание страницы с секцией обсуждения кандидата…';
mw.notify(operation, notifyOptOk );
new mw.Api().postWithEditToken( {
action: 'edit',
title: KDE_Title,
createonly: true,
text: '{{Кандидаты в добротные статьи - Навигация}}\r\n\r\n== [[' + mw.config.get( 'wgTitle' ) + ']] ==\r\n' + nominateComment + T_SIGN_A + '\r\n',
summary: summaryEditNotCurrentArticle,
} ).done( function() {
mw.notify( operation + T_OK, notifyOptOk );
} ).fail( function() {
mw.notify( operation + T_ERR, notifyOptError );
success = false;
}).always(funcs[7]);
};
funcs[6] = function() {
"use strict";
var operation = 'Добавление секции обсуждения кандидата…';
mw.notify(operation, notifyOptOk );
var withExistingPage = new mw.Api().postWithEditToken( {
action: 'edit',
title: KDE_Title,
nocreate: true,
appendtext: '\r\n== [[' + mw.config.get( 'wgTitle' ) + ']] ==\r\n' + nominateComment + T_SIGN_A + '\r\n',
summary: summaryEditNotCurrentArticle,
} ).done( function() {
mw.notify(operation + T_OK, notifyOptOk );
} ).fail( function() {
mw.notify(operation + T_ERR, notifyOptError );
success = false;
}).always(funcs[7]);
};
funcs[7] = function() {
if (success) {
finalize('Всё сделано', 'Все правки завершены успешно', 'info');
} else {
finalize('Завершено', 'Завершено с ошибками. Просмотрите ваш вклад и попробуйте доделать нужные правки вручную.', 'error');
}
};
var finalize = function(title, message, status) {
tgWikiQualityArticles.reloadWithMessage(title, message, status);
};
funcs[0]();
};
var updateTips = this.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 );
};
var checkNotEmpty = this.checkNotEmpty = function( o ) {
if ( o.val().length === 0 ) {
tgWikiQualityArticles.updateTips( o, "Поле должно быть заполнено." );
return false;
} else {
return true;
}
};
this.addButtonsArchive = function() {
$( "span.ruWikiQualityCandatatesToArchivButton" ).before( "<br >" ).text( "Отправить в архив" ).button().click(
function() {
var dateStr = $( this ).data( "date" )
var funcs = funcArray(5);
var archiveTitle;
var archiveListTitle;
var list = '\n';
funcs[0] = function() {
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: {
mw.notify( 'Неизвестное название месяца: «' + month + '»', ruWikiQualityArticles.notifyOptions );
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>' );
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>' );
mw.notify( 'Обновление служебного списка кандидатов (удаление)…', ruWikiQualityArticles.notifyOptions );
tgWikiQualityArticles.apiQueryLatestRevision( {
pageids: PAGE_ID_CANDIDATES,
} ).done( function( result ) {
var pageInfo = getFirstObjectValue( result.query.pages );
if ( !pageInfo.revisions || !pageInfo.revisions[0] || !pageInfo.revisions[0]['*'] ) {
alert( 'Невозможно получить текст списка кандидатов' );
funcs[1]();
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;
}
new mw.Api().postWithEditToken( {
action: 'edit',
pageid: PAGE_ID_CANDIDATES,
summary: '[[' + archiveTitle + '|В архив]]' + summarySuffix,
text: oldContent,
} ).always( funcs[1] );
} ).fail( funcs[1] );
};
funcs[1] = function() {
mw.notify( 'Обновление служебного списка кандидатов в архиве…', ruWikiQualityArticles.notifyOptions );
new mw.Api().postWithEditToken( {
action: 'edit',
title: archiveListTitle,
summary: 'Архивация' + summarySuffix,
appendtext: list,
} ).always( funcs[2] );
};
funcs[2] = function() {
mw.notify( 'Автоматическое создание страницы отображения архива…', ruWikiQualityArticles.notifyOptions );
new mw.Api().postWithEditToken( {
action: 'edit',
title: archiveTitle,
summary: 'Автоматическое создание' + summarySuffix,
text: '{{Навигация по архиву КДС}}\r\n{{Википедия:Кандидаты в добротные статьи/Impl|list={{/Список}}|strike=0}}',
createonly: true
} ).always( funcs[3] );
};
funcs[3] = function() {
mw.notify( 'Закрытие страницы номинаций…', tgWikiQualityArticles.notifyOptions );
var nomTitle = 'Википедия:Кандидаты в добротные статьи/' + dateStr
tgWikiQualityArticles.apiQueryLatestRevision( {
titles: nomTitle,
rvsection: 0,
} ).done( function( result ) {
var pageInfo = getFirstObjectValue( result.query.pages );
if ( !pageInfo.revisions || !pageInfo.revisions[0] || !pageInfo.revisions[0]['*'] ) {
mw.notify( 'Закрытие страницы номинаций… ' + T_ERR, ruWikiQualityArticles.notifyOptions );
alert( 'Невозможно получить текст заголовка страницы номинаций' );
funcs[4]();
return undefined;
}
var oldContent = pageInfo.revisions[0]['*'];
oldContent = oldContent.replace( '{{Кандидаты в добротные статьи - Навигация}}', '{{Кандидаты в добротные статьи - Навигация|closed=1}}' );
new mw.Api().postWithEditToken( {
action: 'edit',
title: nomTitle,
section: 0,
text: oldContent,
summary: 'Закрытие страницы номинаций' + summarySuffix,
} ).always( funcs[4] );
} ).fail( funcs[4] );
};
funcs[4] = function() {
// no op
};
funcs[0]();
} );
};
this.addButtonsChangeCategories = function() {
if (
// только для ДС
$( "#qa-message" ).length === 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 ( tgWikiQualityArticles.categories == null ) {
tgWikiQualityArticles.loadCategories();
}
},
buttons: {
"Поменять категории": function() {
$( this ).dialog( 'close' );
tgWikiQualityArticles.changeCategoriesImpl();
},
"Отменить": function() {
$( this ).dialog( 'close' );
}
}
} );
RuWikiQualityArticles.addToolboxMenuButton( 'Категории ДС', function() {
tgWikiQualityArticles.changeCategories();
} );
};
var changeCategories = this.changeCategories = function() {
$( "#ruWikiQAChangeCategoryForm" ).dialog( 'open' );
};
var changeCategoriesImpl = this.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 funcs = funcArray(8);
var functionBuilderAdd = function( i ) {
return function() {
if ( newCategories[i] && $.inArray( newCategories[i], oldCategories ) == -1 ) {
tgWikiQualityArticles.addToCategory( newCategories[i], mw.config.get( 'wgTitle' ) ).always( funcs[0 + i + 1] );
} else {
funcs[0 + i + 1]();
}
};
};
var functionBuilderRemove = function( i ) {
return function() {
if ( oldCategories[i] && $.inArray( oldCategories[i], newCategories ) == -1 ) {
tgWikiQualityArticles.removeFromCategory( oldCategories[i], mw.config.get( 'wgTitle' ) ).always( funcs[3 + i + 1] );
} else {
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 + '}}';
mw.notify( 'Получение текста статьи…', ruWikiQualityArticles.notifyOptions );
tgWikiQualityArticles.apiQueryLatestRevision( {
titles: mw.config.get( 'wgTitle' ),
} ).done( function( result ) {
var pageInfo = getFirstObjectValue( result.query.pages );
if ( !pageInfo.revisions || !pageInfo.revisions[0] || !pageInfo.revisions[0]['*'] ) {
mw.notify( 'Получение текста статьи… ' + T_ERR, tgWikiQualityArticles.notifyOptions );
alert( 'Невозможно получить текст статьи' );
funcs[7]();
return undefined;
}
var content = pageInfo.revisions[0]['*'];
var patt = new RegExp( "\\{\\{Добротная статья[^\\}]*\\}\\}", "i" );
var newContent = content.replace( patt, newTemplate );
if ( content === newContent ) {
mw.notify( 'Обновление текста статьи… ' + T_ERR, tgWikiQualityArticles.notifyOptions );
alert( "Не могу найти и обновить шаблон {{Добротная статья}} в тексте" );
funcs[7]();
return undefined;
}
mw.notify( 'Обновление содержимого шаблона {{Добротная статья}} в тексте статьи…', tgWikiQualityArticles.notifyOptions );
new mw.Api().postWithEditToken( {
title: mw.config.get( 'wgTitle' ),
summary: 'Обновление категорий [[ВП:ДС|добротной статьи]]' + summarySuffix,
text: newContent,
} ).always( funcs[7] );
} ).fail( funcs[7] );
};
funcs[7] = function() {
tgWikiQualityArticles.purge();
};
funcs[0]();
};
var apiQueryLatestRevision = this.apiQueryLatestRevision = function( args ) {
args.action = 'query';
args.prop = 'revisions';
args.rvprop = 'content';
return new mw.Api().get( args );
};
var addToCategory = this.addToCategory = function( category, title ) {
mw.notify( 'Добавление статьи «' + title + '» в список статей категории «' + category + '»…', {
tag: 'QA-Gadget::addToCategory',
type: 'info',
} );
return new mw.Api().postWithEditToken( {
action: 'edit',
title: PAGE_PREFIX_LIST + category,
summary: 'Добавление статьи «' + title + '» в список' + summarySuffix,
appendtext: '\n[[' + title + ']]',
} ).done( function() {
mw.notify( 'Статья «' + title + '» добавлена в список статей категории «' + category + '»', {
tag: 'QA-Gadget::addToCategory',
type: 'info',
} );
} ).fail( function() {
console.log( arguments );
mw.notify( 'Не удалось добавить статью «' + title + '» в список статей категории «' + category + '»', {
tag: 'QA-Gadget::addToCategory',
type: 'error',
} );
} );
};
this.removeFromCategory = function( category, title ) {
var d = $.Deferred();
var summaryText = 'Удаление статьи «[[' + title + ']]» из списка' + summarySuffix;
mw.notify( 'Получение текущего служебного списка категории «' + summarySuffix + '»…', tgWikiQualityArticles.notifyOptions );
tgWikiQualityArticles.apiQueryLatestRevision( {
titles: PAGE_PREFIX_LIST + category,
} ).done(
function( result ) {
var pageInfo = getFirstObjectValue( result.query.pages );
if ( !pageInfo.revisions || !pageInfo.revisions[0] || !pageInfo.revisions[0]['*'] ) {
mw.notify( 'Получение текущего служебного списка категории «' + summarySuffix + '»… Ошибка!', tgWikiQualityArticles.notifyOptions );
alert( 'Невозможно получить список категории «' + category + '»' );
d.reject();
return undefined;
}
var oldContent = pageInfo.revisions[0]['*'] + '\n';
if ( oldContent.indexOf( '\n[[' + title + ']]\n' ) === -1 ) {
mw.notify(
'Удаление статьи «' + title + '» из служебного списка категории «' + summarySuffix + '»… Ошибка: статья не найдена в служебном список категории',
tgWikiQualityArticles.notifyOptions );
alert( 'Статья не найдена в списке категории «' + category + '»' );
d.reject();
return undefined;
}
var newListContent = oldContent.replace( '\n[[' + title + ']]\n', '\n' );
newListContent = newListContent.substring( 0, newListContent.length - 1 );
mw.notify( 'Обновление служебного списка категории «' + summarySuffix + '»…', tgWikiQualityArticles.notifyOptions );
new mw.Api().postWithEditToken( {
title: PAGE_PREFIX_LIST + category,
summary: summaryText,
text: newListContent,
} ).done( function() {
d.resolve.apply( d, arguments );
} ).fail( function() {
d.reject.apply( d, arguments );
} );
} ).fail( function() {
d.reject.apply( d, arguments );
} );
return d.promise();
};
this.purge = function() {
mw.notify( 'Перезагрузка страницы…', notifyOptOk);
window.location.replace( mw.config.get( 'wgServer' ) + mw.config.get( 'wgScriptPath' ) + '/index.php?action=purge&title='
+ encodeURIComponent( mw.config.get( 'wgPageName' ) ) );
return;
};
function updateProjectTemplatesImpl(content, params) {
var newLevel = params.newLevel;
var patterns = [ "\\{\\{статья проекта[^\\}]*\\}\\}", "\\{\\{проект[^\\}]*\\}\\}" ];
var result = content;
for ( var i = 0; i < patterns.length; i++ ) {
var patt = new RegExp( patterns[i], "gi" );
result = result.replace( patt, 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' ), 'уровень=' + newLevel );
} else { // ранее не было параметра уровень
return found.substring( 0, separatorIndex ) + '\|уровень=' + newLevel + found.substring( separatorIndex, found.length );
}
} else { // статья ранее не была оценена совсем
return found.replace( '}}', '\|уровень=' + newLevel + '\|важность=}}' );
}
} );
}
return result;
}
function updateProjectTemplates(articleTitle, newLevel) {
return pageGetEditSave(articleTitle, 'Обновление шаблонов проектов… ',
updateProjectTemplatesImpl, {newLevel: newLevel}, 'Обновление шаблонов проектов', 'ignore');
};
function pageGetEditSave(title, operation, editFunc, params, summary, no_page) {
var d = $.Deferred();
var op1 = 'Получение текста страницы ' + title + '…';
mw.notify(operation + op1, notifyOptOk);
tgWikiQualityArticles.apiQueryLatestRevision( {
titles: title,
rvsection: 0,
} ).done( function( result ) {
var content = '';
var pageInfo = getFirstObjectValue( result.query.pages );
if ( !pageInfo.revisions || !pageInfo.revisions[0] || !pageInfo.revisions[0]['*'] ) {
if (no_page == 'error') {
mw.notify( operation + op1 + T_ERR + ' Страница не существует.', notifyOptError);
d.reject( 'Невозможно получить текст страницы ' + title);
return;
} else if (no_page == 'ignore') {
mw.notify( operation + ' Страница не существует. Обновление не требуется. ', notifyOptOk);
d.resolve();
return;
} else {
mw.notify(operation + op1 + T_OK + ' Страница ещё не создана. ', notifyOptOk);
}
} else {
mw.notify(operation + op1 + T_OK, notifyOptOk);
mw.notify(operation + 'Анализ текста страницы ' + title + '…', notifyOptOk);
content = pageInfo.revisions[0]['*'];
}
var newContent = editFunc(content, params);
if ( content === newContent ) {
mw.notify(operation + 'Обновление страницы ' + title + ' не требуется.', notifyOptOk);
d.resolve();
return;
}
var op2 = 'Сохранение изменений страницы ' + title + '…';
mw.notify(operation + op2, notifyOptOk);
var summaryText = summary || title;
new mw.Api().postWithEditToken( {
action: 'edit',
title: title,
summary: summaryText + summarySuffix,
section: 0,
text: newContent,
} ).done( function() {
mw.notify(operation + op2 + T_OK, notifyOptOk);
d.resolve();
} ).fail( function() {
mw.notify(operation + op2 + T_ERR, notifyOptError);
d.reject.apply( d, arguments );
} );
} ).fail( function() {
mw.notify( operation + op1 + T_ERR, notifyOptError);
d.reject.apply( d, arguments );
} );
return d.promise();
}
this.addNominateToCancellationButtons = function() {
if ( $( "#qa-message" ).length === 0 )
// не является ДС
return;
TgWikiQualityArticles.addToolboxMenuButton(
'Номинировать на лишение статуса ДС',
function() {
var nominateFormDiv = $( '<div id="tgWikiQualityNominateToCancellation" title="Выдвижение статьи на лишение статуса добротной">'
+ '<table border="0"><tr><td width="50" align="center">'
+ '<img src="' + COMMONS_UPLOAD + '/e/e5/Crystal_Clear_action_bookmark_Silver_doubt.svg/40px-Crystal_Clear_action_bookmark_Silver_doubt.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="tgWikiQualityNominateToCancellationComment" style="height: 150px;" class="text ui-widget-content ui-corner-all"></textarea>'
+ '</fieldset></form>'
+ '<p class="validateTips" style="color:gray">Поле комментария обязательно к заполнению,<br/>ваша подпись будет добавлена автоматически.</p>'
+ '</div>' );
var nominateCommentField = nominateFormDiv.find( '#ruWikiQualityNominateToCancellationComment' );
nominateFormDiv.dialog( {
autoOpen: true,
height: 'auto',
width: 600,
modal: true,
buttons: {
"Номинировать на лишение статуса": function() {
var bValid = true;
nominateCommentField.removeClass( "ui-state-error" );
bValid = bValid && ruWikiQualityArticles.checkNotEmpty( nominateCommentField );
if ( bValid ) {
$( this ).dialog( "close" );
tgWikiQualityArticles.nominateToCancellation( nominateCommentField.val() );
}
},
"Отменить": function() {
$( this ).dialog( "close" );
}
}
} )
} );
};
this.nominateToCancellation = function( comment ) {
var replaceTemplateInArticle = this.nominateToCancellation_replaceTemplate( mw.config.get( 'wgTitle' ), '{{Добротная статья|', '{{К лишению статуса добротной|'
+ TgWikiQualityArticles.getCurrentDateWikitext() + '|' );
var addToDiscussionPage = this.nominateToCancellation_addToDiscussionPage( mw.config.get( 'wgTitle' ), comment );
$.when( replaceTemplateInArticle, addToDiscussionPage ).done( function() {
tgWikiQualityArticles.purge();
} );
};
this.nominateToCancellation_addToDiscussionPage = function( articleTitle, comment ) {
var operation = 'Номинирование на лишение статуса… Создание секции обсуждения… ';
mw.notify( operation, notifyOptOk);
return new mw.Api().postWithEditToken( {
action: 'edit',
title: PAGE_CANCEL_DISC,
section: 0,
appendtext: '\n\n== [[' + articleTitle + ']] ==\n' + comment + T_SIGN_A + '\n',
summary: 'Номинирование «[[' + articleTitle + ']]» на лишение статуса добротной' + TgWikiQualityArticles.summarySuffix,
} ).done( function() {
mw.notify( operation + T_OK, notifyOptOk);
} ).fail( function() {
mw.notify( operation + 'Неизвестная ошибка!', notifyOptError);
} );
};
this.nominateToCancellation_replaceTemplate = function( articleTitle, oldTemplateName, newTemplateName ) {
var d = $.Deferred();
var operation = 'Номинирование на лишение статуса… Замена шаблона добротной статьи… ';
var operation_p1 = 'Получение текста статьи… ';
var operation_p2 = 'Сохранение текста статьи… ';
mw.notify( operation + operation_p1, notifyOptOk);
new mw.Api().get( {
action: 'query',
prop: 'revisions',
rvprop: 'content',
titles: articleTitle,
} ).done( function( result ) {
var pageInfo = RuWikiQualityArticles.getFirstObjectValue( result.query.pages );
var content = pageInfo.revisions[0]['*'];
var newContent = content.replace( new RegExp( "(" + $.ui.autocomplete.escapeRegex( oldTemplateName ) + ")", "gi" ), newTemplateName );
mw.notify( operation + operation_p2, notifyOptOk);
new mw.Api().postWithEditToken( {
action: 'edit',
title: articleTitle,
summary: 'Номинирование на лишение статуса добротной' + RuWikiQualityArticles.summarySuffix,
text: newContent,
} ).done( function() {
mw.notify( operation + operation_p2 + T_OK, notifyOptOk);
d.resolve();
} ).fail( function() {
mw.notify( operation + operation_p2 + ' Неизвестная ошибка!', notifyOptError);
d.reject.apply( d, arguments );
} );
} ).fail( function() {
mw.notify( operation + operation_p1 + T_ERR, notifyOptError);
console.log( arguments );
d.reject.apply( d, arguments );
} );
return d.promise();
};
};
RuWikiQualityArticles.summarySuffix = ' с помощью гаджета QA (v. ' + mw.loader.moduleRegistry['ext.gadget.qualityArticles'].version + ')';
RuWikiQualityArticles.addToolboxMenuButton = function( label, click ) {
$( "#p-tb div ul" ).append( $( '<li class="plainlinks"></li>' ).append( $( document.createElement( 'a' ) ).text( label ).css( 'cursor', 'pointer' ).click( click ) ) );
};
RuWikiQualityArticles.getFirstObjectValue = function( obj ) {
"use strict";
return obj[Object.keys( obj )[0]];
};
RuWikiQualityArticles.getCurrentDateWikitext = function() {
"use strict";
return '{{su' + 'bst:CURRENTDAY}} {{su' + 'bst:CURRENTMONTHNAMEGEN}} {{su' + 'bst:CURRENTYEAR}}';
};
mediaWiki.loader.using( [ 'jquery.ui', 'mediawiki.api' ], function() {
var ruWikiQualityArticles = new RuWikiQualityArticles();
tgWikiQualityArticles.addButtonsDiscussion();
tgWikiQualityArticles.addButtonsArchive();
tgWikiQualityArticles.addButtonsNominate();
tgWikiQualityArticles.addButtonsChangeCategories();
tgWikiQualityArticles.addNominateToCancellationButtons();
tgWikiQualityArticles.addFinalDialog();
} );