Участник:Землеройкин/remove.js

/*CC-BY-SA 4.0 Основано на u:higimo/remove.js?oldid=107716412 // v5.0.4Вынесение на КБУ (+ отсроченное), КУ (+ множественное, + оставлено), КУЛ, КПМ.Подключение (на своём /common.js):var g_user_alert = 0 // указать, чтоб не уведомлять автораimportScript('у:Землеройкин/remove.js');*/$(document).ready(function() {var config = mw.config.get(['skin', 'wgNamespaceIds', 'wgFormattedNamespaces', 'wgNamespaceNumber', 'wgPageName', 'wgPageContentModel', 'wgIsRedirect', 'wgUserName']),/*Пространства имён, в которых будет включён удалятор*/rmNamespaces = (typeof g_rm_namespaces == 'undefined') ? [0, 2, 4, 6, 10, 14, 100, 104, 828] : g_rm_namespaces,/*Все кнопки меню*/menu_raw = {imp:'КУЛ', rnm:'КПМ', tRm:'КУ', mRm:'Много КУ', fRm:'КБУ', merge:'КОБ', split:'КРАЗД', recov:'ВУС', ret:'Оставить', noRnm:'Не переименовано'},/*Доступные кнопки*/rmActions = (typeof g_rm_actions == 'undefined') ? Object.keys(menu_raw) : g_rm_actions,/*Переменная, управляющая функцией оповещения создателя статьи*/setAlert = (typeof g_user_alert == 'undefined') ? 0 : g_user_alert,/*Индикатор ошибки api*/isError,/*Здесь хранятся параметры номинации*/param,/*Возможные разделы КБУ в зависимости от пространства имён*/fastRemovePrefix = (config.wgIsRedirect ? 'ОП' : 'О') + ({0:'Сd', 2:'У', 3:'У', 6:'Ф', 14:'К'}[config.wgNamespaceNumber] || ''),/*Список всех доступных причин КБУКоды для админов, текст для остальных.Используется максимально короткий шаблон.Третий параметр — условие для появления <input>*/fastRemove = [['подст:ds','ds Отсроченное'],['уд-бессвязно','О1 Бессвязный текст'],['уд-тест','О2 Тестовая страница'],['уд-ванд','О3 Вандальная страница'],['уд-повторно','О4 Уже удалялось'],['уд-автор','О5 По просьбе автора'],['уд-обс','О6 Ненужная подстраница'],['уд-переим','О7 Для переименования','страницу'],['уд-дубль','О8 Дубликат','страницу'],['уд-реклама','О9 Реклама или спам'],['db-badtalk','О10 Нецелевая СО'],['уд-копивио','О11 Нарушение АП','ссылку'],['уд-пусто','С1 Пусто или коротко'],['уд-иностр','С2 Не на русском'],['уд-ссылки','С3 Лишь ссылки'],['уд-нз','С5 Явно незначимо'],['уд-в никуда','П1 Перенапр. в никуда'],['db-redirspace','П2 Межпростр. перенапр.'],['уд-опечатка','П3 Перенапр. с опечаткой'],['уд-падеж','П4 Не именительный падеж'],['уд-смысл','П5 Неверное перенапр.'],['db-redirtalk','П6 Перенапр. на СО'],['db-duplicate','Ф1 Копия файла','файл'],['db-badimage','Ф2 Повреждённый файл'],['подст:nld','Ф3 Нет данных о лицензии'],['подст:nsd','Ф3 Нет данных о источнике'],['подст:nad','Ф3 Нет данных о авторе'],['подст:dd','Ф3 Сомнительные данные файла'],['подст:ofud','Ф4 Неиспользуемый КДИ'],['подст:dfud','Ф5 Нет КДИ'],['db-badfairuse','Ф6 Неоправданное КДИ'],['NCT','Ф8 Есть на Складе','файл'],['подст:Nothost','Ф9 Файл — ВП:НЕХОСТИНГ'],['уд-пусткат','К1 Пустая категория'],['уд-перекат','К2 Переименованная кат.','категорию'],['уд-владелец','У1 По желанию владельца'],['уд-анон','У2 Устаревшая СО анонима'],['уд-несущ','У3 Несуществующий участник'],['уд-нецелевое','У4 Нецелевое использ. ЛП'],['уд-неактив','У5 Подстраница неактивного'],['db','Особый случай','причину']].filter(function(arr) {return fastRemovePrefix.indexOf(arr[1].charAt(0)) >= 0}),/*Функция запроса к API.Токен и формат каждый раз дополняется перед запросом.Аргументы:1. Передаваемые параметры2. Режим запроса (query, edit или parse)3. Колбекvoid apiReq(object, string, function(result, status))*/apiReq = function(par, mode, clbck) {par.format = 'json'par.token  = mw.user.tokens.get('csrfToken')par.action = mode$.post('/w/api.php', par, clbck)},/*Функция получения даты.Необходимо, например, для КУ-запросов.Есть возможность указать собственную дату для подытоживания номинации.['1051-32-33', '20 апреля 2014'] getDate(string)*/getDate = function(s) {var d = (!!s) ? new Date(s) : new Date()return [d.toISOString().substr(0, 10), d.getUTCDate() + ' ' +'января,февраля,марта,апреля,мая,июня,июля,августа,сентября,октября,ноября,декабря'.split(',')[d.getUTCMonth()] +' ' + d.getUTCFullYear()]},/*Функция получения <input>* Атрибут «h» используется в КБУ, указывая type* Атрибут placeholder используется везде, для улучшения UI* Атрибут id используется везде для получения информации из поляstring getInput(string, string, bool)*/getInput = function(id, p, h) {return '<input id=' + id + ' type=' + (h ? 'hidden' : 'text') + ' placeholder="' + p + '" class=messagebox>'},/*Определяет СО страницы*/getSO = function(pg) {var tmp = /([^:]*:)?(.*)/.exec(pg)if (tmp[1]) {var ns = config.wgNamespaceIds[tmp[1].slice(0, -1).toLowerCase().replace(/ /g, '_')]if (ns != undefined)return config.wgFormattedNamespaces[ns | 1] + ':' + tmp[2]}return 'Обсуждение:' + pg},/*Функция получения текста страницы, null если ошибкаgetText(string, function(string))*/getText = function(pg, clbck) {apiReq({prop: 'wikitext',page: pg}, 'parse', function(txt) {clbck(txt.parse ? txt.parse.wikitext['*'] : null)})},/*Функция отправки уведомления пользователюПо выполнению вызывает callbackuserAlert(string, function(error))*/userAlert = function(pg, clbck) {apiReq({prop: 'revisions',rvprop: 'user',rvdir: 'newer',titles: pg}, 'query', function (t) {var i = t.query.pagesif (!('-1' in i)) {var rvdata = i[Object.keys(i)[0]].revisions[0]if (!('anon' in rvdata) && !rvdata.userhidden && (rvdata.user && rvdata.user !== config.wgUserName)) {apiReq({title: 'оу:' + rvdata.user,section: 'new',sectiontitle: 'Удалятор: [[:' + pg + ']]',summary: param.sum,text: 'Страница [[:' + pg + ']], созданная вами, ' + (param[3] ? '' : 'предложена ') + param[1] + '. ' +(param.place ? 'Обсуждение — на странице [[' + param.place + '#' + param.sectionNW + ']]. ' : '') +'~~\~~<br><small>Это автоматическое уведомление, сгенерированное [[у:Землеройкин/remove.js|скриптом «Удалятор»]].</small>'}, 'edit', function(t) {clbck(t.error)})}else clbck('не нужно')}else clbck('страница удалена')})},/*Функция работы с текстом статьи.Определяет необходимые шаблоны и устанавливает их на СО или статью.changeArticle(string, function(object))*/changeArticle = function(pg, clbck) {if (/(noRnm|ret)/g.test(param[0]))changeArticleDenom(pg, clbck)elsechangeArticleNom(pg, clbck)},// Закрытие номинации (снять в статье, установить на СО)changeArticleDenom = function(pg, clbck) {getText(pg, function(article) {var tpl = RegExp('{\{(' + param[3] + ')\\|(\\d{4}-\\d\\d-\\d\\d)\\|?(.*?)}}', 'gi').exec(article)if (tpl == null) {clbck({code: 'ошибка',info: 'Невозможно снять шаблон «' + param[3] + '».'})return}param.date = getDate(tpl[2])param.place = 'ВП:' + param[3].replace(/\|.*/, '') + '/' + param.date[1]if (param[0] == 'noRnm') { //не переименованоparam.sectionNW = pg + ' → ' + tpl[3]param.tplpar = pg + '|' + tpl[3]}if (param[0] == 'ret') { //оставленоparam.sectionNW = tpl[3].length ? tpl[3] : pgparam.tplpar = 'l1=' + param.sectionNW}param.sum = '[[у:Землеройкин/remove.js|Удалятор]]: номинация [[' + (param.place ? param.place + '#' : '') + param.sectionNW + ']] — ' + param[2]apiReq({summary: param.sum,title: getSO(pg),prependtext: '{{' + param[2] + '|' + param.date[1] + '|' + param.tplpar + '}}\n'}, 'edit')article = article.replace(RegExp('(<noin.*?>)?{\{(' + param[3] + ')\\|.*?}}\n?(<\/noin.*?>)?\n?', 'gi'), '')apiReq({title: pg,text: article,summary: param.sum}, 'edit', function(t) {clbck(t.error)})})},// Открытие номинации (установка шаблона в статье)changeArticleNom = function(pg, clbck) {getText(pg, function(article) {if (article == null) {clbck({code: 'ошибка',info: 'Страница «' + pg + '» не существует.'})return}var tpl = ''if (param[0] == 'fRm') {tpl = fastRemove[$('#rmSel').val()][0] + '|1=' + $('#fiRm').val()}else {tpl = param.tplparif (param[0] == 'merge') {tpl = ('|' + tpl + '|').replace('|' + pg + '|', '|').slice(1, -1)}tpl = param[2] + '|' + param.date[0] + (tpl.length ? '|' + tpl : '')}apiReq({title: pg,text: (tpl.length ? '<noinclude>{{' + tpl + '}}\n</noinclude>' : '') + article,summary: param.sum}, 'edit', function(t) {clbck(t.error)})})},/*Функция установки номинации на соответствующую страницуvoid setNominate(callback)*/setNominate = function(clbck) {apiReq({title: param.place,createonly: '1',text: '{{' + param[4] + '-Навигация}}\n',summary: '[[у:Землеройкин/remove.js|Удалятор]]: автоматическая шапка',}, 'edit', function(t) {apiReq({title: param.place,section: 'new',sectiontitle: param.section,summary: param.sum,text: param.msg + ' ~~\~~'}, 'edit', function(t) {clbck(t.error)})})},/*Заполнение параметров номинации (переменная param)..date — дата номинации.msg — текст номинации.place — место обсуждения (ВП:к_чему-то-там... или пусто, если КБУ).section — заголовок раздела номинации.sectionNW — то же, без викификации.tplpar — параметры шаблона, для установки в статье.sum — описание правок скриптаВозвращает массив страниц для обработки (до 5 шт. для МногоКУ, 2 для КОБ, 0 для ВУС, иначе 1)*/setParam = function() {vari,pg = config.wgPageName.replace(/_/g, ' '),ttl = $('#rmHeader').val(),ttl2 = $('#rmHeader2').length ? $('#rmHeader2').val() : '',msg = $('#rmMsg').val(),pgs = [pg]if (/(noRnm|ret)/g.test(param[0]))return pgsparam.date = getDate()param.msg = msg ? msg.trim() : ''param.place = param[0] != 'fRm' ? 'ВП:' + param[2] + '/' + param.date[1] : ''param.section =param[0] == 'mRm' ? ttl: '[[:' + pg + ']]'param.tplpar = ''if (param[0] == 'rnm') {param.tplpar = ttlparam.section += ' → [[:' + ttl + ']]'}else if (param[0] == 'merge') {param.tplpar = pg + '|' + ttlparam.section += ' и [[:' + ttl + ']]'}else if (param[0] == 'split') {param.tplpar = '[[:' + ttl + ']]' + (ttl2 ? ' и [[:' + ttl2 + ']]' : '')param.section += ' → ' + param.tplpar}param.sectionNW = param.section.replace(/\[\[:/g, '').replace(/]]/g, '')param.sum = '[[у:Землеройкин/remove.js|Удалятор]]: номинация [[' + (param.place ? param.place + '#' : '') + param.sectionNW + ']]' + (param[0] == 'fRm' ? ' ' + param[2] : '')if (param[0] == 'mRm') {pgs = []param.msg = '=== По всем ===\n' + param.msgfor (i = 4; i >= 0; i--) {pg = $('#rmArticle' + i).val()if (pg.length) {pgs.push(pg)param.msg = '=== [[:' + pg + ']] ===\n' + param.msg}}}else if (param[0] == 'merge') {pgs.push(ttl)}else if (param[0] == 'recov') {pgs = []}return pgs},/*Вывод сообщений об ошибках*/logError = function(s, err) {if (err && err.code) isError = 1$('#rmWindow').append('<br>' + s + ' — ' + (err ? (err.code ? '<span class="error"><small>' + err.code + ': ' + err.info + '</small></span>' : err): 'OK'))},/*Обработка массива страниц*/processPages = function(pgs) {if (pgs.length) {var pg = pgs.pop()changeArticle(pg, function(err) {logError('Правка статьи «' + pg + '»', err)if (isError) {finalizeWindow()return}if (setAlert) {userAlert(pg, function(err) {logError('Уведомление создателя', err)processPages(pgs)})}else processPages(pgs)})}else {if (param[4]) {setNominate(function(err) {logError('Запись номинации', err)//window.open('/wiki/' + param.place + '#' + encodeURI(param.sectionNW.replace(/ /g, '_')))finalizeWindow()})}else finalizeWindow()}},/*Вызывается, когда всё сделано*/finalizeWindow = function() {if (isError) {$('.mw-small-spinner').remove()$('#rmWindow').append('<p class="error">При выполнении скрипта случились ошибки. Поправьте всё, что надо, вручную.').children().prop('disabled', false)$('#rmBtn').attr('disabled', 1)$('#rmClose').text('Закрыть')}else location.reload()},/*Функция создания модального окна*/modalHandler = function() {var i,content = ''if (param[0] == 'mRm') {content += getInput('rmHeader', 'Заголовок номинации')for (i = 0; i < 5; i++) {content += getInput('rmArticle' + i, 'Статья' + (i + 1))}}if (param[0] == 'fRm') {content += '<select id=rmSel class=messagebox>'for (i = 0; i < fastRemove.length; i++) {content += '<option value=' + i + '>' + fastRemove[i][1] + '</option>'}content += '</select>' + getInput('fiRm', '', 1)}if (param[0] == 'rnm') {content += getInput('rmHeader', 'Новое название')}if (param[0] == 'merge') {content += getInput('rmHeader', 'Объединить с…')}if (param[0] == 'split') {content += getInput('rmHeader', 'Разделить на эту')content += getInput('rmHeader2', 'И на эту')}if (param[4]) {content += '<textarea id=rmMsg placeholder="Текст номинации без «~~\~~»." rows=4></textarea>'}$('#content').prepend('<div id=rmWindow style="padding:2em;margin:1em;border:1px solid #985; background: #fec;">' +'<h1>Удалятор: ' + param[2] + '</h1>' + content +'<br><label><input name="rmUAlert" type=checkbox ' + ((setAlert) ? 'checked' : '') + '>Оповестить автора</label><br>' +'<button id=rmBtn class=mw-ui-button>Отправить</button><button id=rmClose class=mw-ui-button>Отмена</button>')if (param[0] == 'mRm') $('#rmArticle0').val(config.wgPageName.replace(/_/g, ' '))$('#rmSel').change(function() {var i = fastRemove[this.value][2]$('#fiRm').attr({type: (i ? 'text' : 'hidden'), placeholder: 'Укажите ' + i})})$('#rmClose').click(function() {$('#rmWindow').remove()})$('#rmBtn').click(function() {$('#rmWindow').append('<b class=mw-small-spinner></b>').children().attr('disabled', '1')setAlert = $('[name="rmUAlert"]').is(':checked')var pgs = setParam()processPages(pgs)})/*Реализация ctrl+enter события*/$(window).keydown(function (e) {if (e.ctrlKey && e.keyCode == 13)$('#rmBtn').click()})};/*Добавление выпадающего меню на все страницы*/if ((rmNamespaces.indexOf(config.wgNamespaceNumber & ~1) >= 0) && (config.wgPageContentModel == 'wikitext')) {var menuLocation = 'p-cactions';var nextNode = '#ca-move';if ( config.skin === 'timeless' || config.skin === 'minerva' ) {menuLocation = 'p-tb';nextNode = null;}if ( config.skin === 'vector' || config.skin === 'vector-2022' ) {nextNode = null;var $portletClone = $( '#p-variants' ).eq( 0 ).clone();$portletClone.attr( 'id', 'p-remove-js' ).attr( 'aria-labelledby', 'p-remove-js-label' ).removeClass( 'emptyPortlet' );$portletClone.find( '.emptyPortlet' ).removeClass( 'emptyPortlet' );$portletClone.find( 'ul' ).empty();$portletClone.find( 'input' ).attr( 'aria-labelledby', 'p-remove-js-label' );$portletClone.find( 'input' ).attr( 'aria-label', '' );$portletClone.find( 'label' ).attr( 'id', 'p-remove-js-label' ).find( 'span' ).text( 'Удалятор' );$portletClone.insertAfter( '#p-views' );menuLocation = 'p-remove-js';}for (var a of rmActions) {var portletLink = mw.util.addPortletLink( menuLocation, '#', menu_raw[ a ], 'ca-remove-' + a, null, null, nextNode );$( portletLink ).find( 'a' ).click(function( e ) {e.preventDefault();var i = $( this ).parent().attr( 'id' ).replace( 'ca-remove-', '' );param = (// [текущее действие, комментарий, шаблон/место обсуждения, поддерживаемые шаблоныi == 'imp'? [ i, 'к срочному улучшению','к улучшению','','КУЛ'] :i == 'rnm'? [ i, 'к переименованию','к переименованию','','КПМ'] :i == 'tRm'? [ i, 'к удалению','к удалению','','КУ'] :i == 'mRm'? [ i, 'к удалению','к удалению','','КУ'] :i == 'merge'? [ i, 'к объединению с другой','к объединению','','КОБ'] :i == 'split'? [ i, 'к разделению','к разделению','','КР'] :i == 'fRm'? [ i, 'к [[ВП:КБУ|быстрому удалению]]','к быстрому удалению'] :i == 'recov'? [ i, '','к восстановлению','','ВУС'] :i == 'ret'? [ i, 'оставлена','оставлено','к удалению|ку'] :i == 'noRnm'? [ i, 'не переименована','не переименовано','к переименованию|кпм|rename'] :0)isError = 0modalHandler()});}}})
🔥 Top keywords: Заглавная страницаЯндексДуров, Павел ВалерьевичСлужебная:ПоискYouTubeЛунин, Андрей АлексеевичПодносова, Ирина ЛеонидовнаВКонтактеФоллаут (телесериал)WildberriesTelegramРеал Мадрид (футбольный клуб)Богуславская, Зоя БорисовнаДуров, Валерий СемёновичРоссияXVideosСписок умерших в 2024 годуЧикатило, Андрей РомановичFallout (серия игр)Список игроков НХЛ, забросивших 500 и более шайбПопков, Михаил ВикторовичOzon17 апреляИльин, Иван АлександровичMail.ruСёгун (мини-сериал, 2024)Слово пацана. Кровь на асфальтеПутин, Владимир ВладимировичЛига чемпионов УЕФАГагарина, Елена ЮрьевнаБишимбаев, Куандык ВалихановичЛига чемпионов УЕФА 2023/2024Турнир претендентов по шахматам 2024Манчестер СитиMGM-140 ATACMSРоссийский миротворческий контингент в Нагорном КарабахеЗагоризонтный радиолокаторПинапВодительское удостоверение в Российской Федерации