Перейти к содержанию

MediaWiki:Gadget-pagenominator.js

Материал из Викитеки — свободной библиотеки

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

  • Firefox / Safari: Удерживая клавишу Shift, нажмите на панели инструментов Обновить либо нажмите Ctrl+F5 или Ctrl+R (⌘+R на Mac)
  • Google Chrome: Нажмите Ctrl+Shift+R (⌘+Shift+R на Mac)
  • Edge: Удерживая Ctrl, нажмите Обновить либо нажмите Ctrl+F5
  • Opera: Нажмите Ctrl+F5.
// На основе https://ru.wikipedia.org/w/index.php?title=Участник:Higimo/remove.js
// Оставлено создание номинаций КУ, много КУ, КБУ. Остальные отключены, хотя остались в коде.
var namespace = mw.config.get('wgNamespaceNumber');

if (namespace !== -1) {
	$(document).ready(function() {
	    /*
	        Инициализация итератора
	    */
	    var i = 0,
	        /*
	            Инициализация переменной устанавливающей флаг на чекбоксе,
	            который влияет на выполнение функции оповещающей создателя статьи
	        */
	        g_user_alert = 0, // указать, чтоб не уведомлять пользователя
	        setAlert = (typeof g_user_alert === 'undefined') ? 1 : g_user_alert,
	
	        // Переключатель открытия номинаций (новых тем) на ВТ:КУ
	        createNomination = true,
	
	        /* 
	            Список всех доступных причин КБУ
	            Коды для админов, текст для остальных.
	            Используется максимально короткий шаблон.
	            Третий параметр — условие для появления <input>
	        */
	        fastRemove = [
	            ['d|',		'Причина не указана'						],
	            ['d|О1 Бессвязная статья',		'О1 Бессвязная статья'			],
	            ['d|О2 Тестовая статья',		'О2 Тестовая статья'			],
	            ['d|О3 Вандальная статья',		'О3 Вандальная статья'			],
	            ['d|О4 Повторное создание',		'О4 Повторное создание'			],
	            ['d|О5 Автор запросил удаление','О5 Автор запросил удаление'	],
	            ['d|О6 СО или подстраница',		'О6 СО или подстраница'			],
	            ['d|О7 Для переименования',		'О7 Для переименования', 		'страницу'],
	            ['d|О8 Дубликат статьи',		'О8 Дубликат статьи',			'страницу'],
	            ['d|О9 Реклама или спам',		'О9 Реклама или спам' 			],
	            ['d|О10 Нецелев. использ. СО',	'О10 Нецелев. использ. СО'		],
	            ['d|О11 Нарушены АП',			'О11 Нарушены АП',				'ссылку'],
	            ['d|С1 Пусто или коротко',		'С1 Пусто или коротко'			],
	            ['d|С2 Надмозг',				'С2 Надмозг'					],
	            ['d|С3 Лишь ссылки',			'С3 Лишь ссылки'				],
	            ['d|С5 Значимости нет',			'С5 Значимости нет'				],
	            ['d|П1 Перенаправл. в никуда',	'П1 Перенаправл. в никуда'		],
	            ['d|П2 Межпростр. перенаправ.',	'П2 Межпростр. перенаправ.'		],
	            ['d|П3 Ошибочное перенап.',		'П3 Ошибочное перенап.'			],
	            ['d|П4 Не прав. падеж',			'П4 Не прав. падеж'				],
	            ['d|П5 Бессмысленное перенаправ.',		'П5 Бессмысленное перенаправ.'	],
	            ['П6 Перенаправление на СО',	'П6 Перенаправление на СО'		],
	            ['Ф1 Копия файла',				'Ф1 Копия файла',				'файл'],
	            ['Ф2 Повреждённый файл',		'Ф2 Повреждённый файл'			],
	            ['Ф3 Нет данных о лицензии', 	'Ф3 Нет данных о лицензии'		],
	            ['Ф3 Нет данных о источнике',	'Ф3 Нет данных о источнике'		],
	            ['Ф3 Нет данных о авторе',		'Ф3 Нет данных о авторе'		],
	            ['Ф3 Сомнительные данные файла','Ф3 Сомнительные данные файла'	],
	            ['Ф4 Неиспользуемый КДИ',		'Ф4 Неиспользуемый КДИ'			],
	            ['Ф5 Нет КДИ',					'Ф5 Нет КДИ'					],
	            ['Ф6 Неоправданное КДИ',		'Ф6 Неоправданное КДИ'			],
	            ['Ф8 Есть на Складе',			'Ф8 Есть на Складе',			'файл'],
	            ['Ф9 Файл — ВП:НЕХОСТИНГ',		'Ф9 Файл — ВП:НЕХОСТИНГ'		],
	            ['К1 Пустая категория',			'К1 Пустая категория'			],
	            ['К2 Переимен. кат.',			'К2 Переимен. кат.',			'категорию'],
	            ['У1 По запросу владельца',		'У1 По запросу владельца'		],
	            ['У2 Обсуждение анонима',		'У2 Обсуждение анонима'			],
	            ['У3 Несуществующий участник',	'У3 Несуществующий участник'	],
	            ['У4 Нецелевое использование',	'У4 Нецелевое использование'	],
	            ['У5 Подстраница инактива',		'У5 Подстраница инактива'		]
	        ],
	        /*
	            Генератор кода для меню на каждой странице
	        */
	        // menu = 'imp=КУЛ|rnm=КПМ|tRm=КУ|mRm=МНОГО КУ|ret=Оставить|noRnm=Не переименовано|fRm=КБУ|merge=КОБ|recov=ВУС|split=Разделить|'.replace(/(.*?)=(.*?)\|/g, '<li><a id=$1>$2</a></li>'),
	        menu = 'tRm=КУ|mRm=МНОГО КУ|fRm=КБУ|'.replace(/(.*?)=(.*?)\|/g, '<li><a id=$1>$2</a></li>'),
	        /*
	            Селектор для темы Вектор, чтобы добавлять собственное выпадающее меню
	        */
	        vector = $('#p-views'),
	        /*
	            Функция запроса к API.
	            Запрос бывает двух видов: edit и parse.
	            Чтоб каждый раз не передавать параметр, он — булева переменная
	            Токен и формат каждый раз дополняется перед запросом.
	            Токен и формат обязателен.
	            Аргументы:
	                1. Передаваемые параметры
	                2. Используемый режим
	                3. Колбек
	            void apiReq(object, bool, function(result, status))
	        */
	        apiReq = function(param, mode, callback) {
	            param.format = 'json';
	            param.token  = mw.user.tokens.get('csrfToken');
	            param.action =
	                mode === 0 ? 'edit'	:
	                    mode === 1 ? 'parse'	: 'query';
	            $.post('/w/api.php', param, callback);
	        },
	        /*
	            Функция получения даты.
	            Необходимо, например, для КУ-запросов.
	            Есть возможность указать собственную дату для подытоживания номинации.
	            ['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>';
	        },
	        /*
	            Функция получения текстов статьи и её СО
	            getTexts(string, string, function(string, string))
	        */
	        getTexts = function(pg, pgtl, clbck) {
	            getText = {prop: 'wikitext'};
	                getText.page = pg;
	            apiReq(getText, 1, function(txt1) {
	                getText.page = pgtl;
	                apiReq(getText, 1, function(txt2) {
	                    clbck(
	                        txt1.parse ? txt1.parse.wikitext['*'] : '',
	                        txt2.parse ? txt2.parse.wikitext['*'] : ''
	                    );
	                });
	            });
	        },
	        /*
	            Функция отправки уведомления пользователю
	            По выполнению вызывает callback
	            userAlert(object, string, string, function())
	        */
	        userAlert = function(param, pg, msg, clbck) {
	            apiReq({
	                prop: 'revisions',
	                rvprop: 'user',
	                rvdir: 'newer',
	                titles: pg
	            }, 2, function (t) {
	                i = t.query.pages;
	                name = (typeof i['-1'] === 'undefined') ? i[Object.keys(i)[0]].revisions[0].user : '';
	                if (!/(\d{1,3}\.){3}\d/.test(name) && setAlert) {
	                    apiReq({
	                        title: 'оу:' + name,
	                        section: 'new',
	                        sectiontitle: param.sum,
	                        summary: param.sum,
	                        text: '~~\~~'
	                    }, 0, function() {
	                        clbck();
	                    });
	                } else {
	                    clbck();
	                }
	            });
	        },
	        /*
	            Функция работы с текстом статьи.
	            Получает адрес страницы обсуждения, получает тексты, определяет
	            необходимые шаблоны и устанавливает их на СО или статью.
	            changeArticle(object, string, string, function(string))
	        */
	        changeArticle = function(param, pg, date, clbck) {
	            var so = mw.config.get('wgFormattedNamespaces')[namespace + 1] + ':' + pg.replace(/.*?:/, ''),
	                fiRm = function(s) {   // строка в викиссылку
	                    s = s.replace(/^[\s\[]+|[\s\]]+$/g, '');  // trim
	                    return s.length > 0 ? '[['+s+']]' : '';   // обёртка в '[[]]' 
	                };
	            getTexts(pg, so, function(article, talk) {                
	                // Дописать остальные итоговые кнопочки и просто добавить. еще и привести в норм. состояние.
	                var tpl;
	                if (/(noRnm)/g.test(param[0])) { //не переименовано
	                    tpl = RegExp('(' + param[3].join('|') + ')\\|(\\d{4}-\\d\\d-\\d\\d)\\|?(.*?)}', 'gi').exec(article);
	                    if (tpl === null)
	                        location.reload();
	                    date = getDate(tpl[2]);
	                    apiReq({
	                        summary: param.sum.replace(/(\[В.*)\/.*?#/g, '$1/' + date[1] + '#'),
	                        title: so,
	                        text: '{\{' + param[4] + '|' + date[1] + '|' + pg + '|' + tpl[3] + '}}\n' + talk
	                    }, 0);
	                    article = article.replace(RegExp('(<noin.*?>)?{\{(' + param[3].join('|') + ').*?}}?(<\/noin.*?>)?', 'gi'), '');
	                }
	                if (/(ret)/g.test(param[0])) {//оставлено
	                    tpl = RegExp('(' + param[3].join('|') + ')\\|(\\d{4}-\\d\\d-\\d\\d)\\|?(.*?)}', 'gi').exec(article);
	                    if (tpl === null)
	                        location.reload();
	                    date = getDate(tpl[2]);
	                    apiReq({
	                        summary: param.sum.replace(/(\[В.*)\/.*?#/g, '$1/' + date[1] + '#'),
	                        title: so,
	                        text: '{\{' + param[4] + '|' + date[1] + '|' + tpl[3] + '}}\n' + talk
	                    }, 0);
	                    article = article.replace(RegExp('(<noin.*?>)?{\{(' + param[3].join('|') + ').*?}}?(<\/noin.*?>)?', 'gi'), '');
	                }
	                tpl = '<noinclude>{\{' +
	                    (
	                        param[0] == 'imp'
	                            ? 'подст:КУЛ'
	                            : /(tRm|mRm)/g.test(param[0])
	                            ? 'К удалению|date=' + date[0]
	                            : param[0] == 'fRm'
	                                ? fastRemove[$('#rmSel').val()][0] + ' ' + fiRm($('#fiRm').val())
	                                : param[0] == 'rnm'
	                                    ? 'Кпм|' + date[0] + '|' + $('#rmHeader').val() + '|' + param.rmnNom
	                                    : param[0] == 'merge'
	                                        ? 'subst:слить|' + $('#rmHeader').val()
	                                        : param[0] == 'split'
	                                            ? 'split|' + date[0] + '|' + '[[' + $('#rmHeader').val() + ']] и [[' + $('#rmHeader2').val() + ']]'
	                                            : ''
	                    ) + '}}</noinclude>';
	                apiReq({
	                    title: pg,
	                    text: (tpl.length > 30 ? tpl : '') + article,
	                    summary: param.sum
	                }, 0, function() {
	                	clbck(pg);
	                });
	            });
	        },
	        /*
	            Функция установки номинации на соответствующую страницу
	            Аргументы:
	                1. Параметры
	                2. Заголовок номинации
	                3. Текст размещаемого сообщения
	                4. Колбек
	                void setNominate(param, section, msg, callback)
	        */
	        setNominate = function(param, section, msg, callback) {
	            if (/(imp|rnm|tRm|mRm|merge|recov|split)/g.test(param[0])) {
	                apiReq({
	                    title: param.place,
	                    section: 'new',
	                    sectiontitle:
	                        'mRm' == param[0]
	                            ? section
	                            : /(rnm|split|merge)/g.test(param[0])
	                            ? '[[:' + param.rmnNom.replace(/( → |, )/g, ']]$1[[:') + ']]'
	                            : '[[:' + section + ']]',
	                    summary: param.sum,
	                    text: msg
	                }, 0, function() {
	                    callback();
	                });
	            } else {
	                callback();
	            }
	        },
	        /*
	            Функция создания и обработки модального окна
	            void modalHandler(array)
	        */
	        modalHandler = function(param) {
	            var 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 (/(imp|tRm|mRm|rnm|merge|recov|split)/g.test(param[0])) {
	                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[1] + '</h1>' +
	                content + '<br>' +
	                '<label><input name="rmUAlert" type=checkbox ' + ((setAlert) ? 'checked' : '') + '>Оповещать пользователя</label><br>' +
	                (param[0] == 'fRm' ? '' : '<label><input name="rmCreateNomination" type=checkbox ' + (createNomination ? 'checked' : '') + '>Открывать номинацию на ВТ:КУ</label><br>') +
	                '<div style="margin-top:1em;margin-right:1em;" ><button id=rmBtn class=mw-ui-button>Отправить</button><button id=rmClose class=mw-ui-button>Отмена</button><div>'
	            );
	
	            // дополнительное поле ("укажите страницу" и т.п.)
	            $('#rmSel').change(function() {
	                i = fastRemove[this.value][2];
	                $('#fiRm').attr({type: (i ? 'text' : 'hidden'), placeholder: 'Укажите ' + i});
	            });
	
	            $('#rmClose').click(function() {
	                $('#rmWindow').remove();
	            });
	
	            $('#rmBtn').click(function() {
	                setAlert = $('[name="rmUAlert"]').is(':checked');
	                createNomination = $('[name="rmCreateNomination"]').is(':checked');
	                $('#rmWindow')
	                    .append('<b class=mw-small-spinner></b>')
	                    .children().attr('disabled', '1');
	                var date = getDate(),
	                    msg = $('#rmMsg').val(),
	                    wind = $('#rmWindow'),
	                    pg = mw.config.get('wgPageName').replace(/_/g, ' '),
	                    ttl = $('#rmHeader').val(),
	                    ttl2 = $('#rmHeader2').length ? $('#rmHeader2').val() : '';
	                param.place = param[2] ? 'Викитека:' + param[2] : '';
	                param.rmnNom = pg + ' → ' + ttl + (ttl2.length ? ', ' + $('#rmHeader2').val() : '');
	                if (createNomination) {
	                    param.sum = 'Удалятор: [[' + (param.place ? param.place + '#' : '') + pg + ']] — ' + param[1];
	                } else {
	                    param.sum = 'Удалятор: ' + param[1];
	                }
	                i = 0;
	                if ($('#rmArticle0')[0]) {
	                    i = 4;
	                    msg = '=== По всем ===\n' + msg;
	                }
	                if (/(rnm|split|merge)/g.test(param[0])) {
	                    param.sum = param.sum.replace(/#.*]]/g, '#' + param.rmnNom + ']]');
	                }
	                for (; i >= 0; i--) {
	                    if ($('#rmArticle0')[0])
	                        pg = $('#rmArticle' + i).val();
	                    if (pg.length) {
	                        if ($('#rmArticle0')[0]) {
	                            param.sum = param.sum.replace(/#.*?\]/g, '#' + (ttl ? ttl : pg) + ']');
	                            msg = '=== [[:' + pg + ']] ===\n' + msg;
	                        }
	                        changeArticle(param, pg, date, function(pg) {
	                            wind.append('Исправлена статья «' + pg + '»<br>');
	                            userAlert(param, pg, msg + ' ~~\~~', function() {
	                                if (setAlert) wind.append('Уведомлен создатель<br>');
	                                setNominate(param, (ttl ? ttl : pg), msg + ' --~~\~~', function() {
	                                    if (createNomination) {
	                                        wind.append('Номинация записана<br>');
	                                        if (/(imp|rnm|tRm|mRm|recov|merge)/g.test(param[0])) {
	                                            wind.append('Открытие номинации<br>');
	                                            window.open('/wiki/' + param.place + '#' + encodeURI(pg.replace(/ /g, '_')).replace(/%/g, '.'));
	                                        }
	                                        location.reload();
	                                    }
	                                })
	                            })
	                        })
	                    }
	                }
	            });
	            /*
	                Реализация ctrl+enter события
	            */
	            $(window).keydown(function (e) {
	                if (e.ctrlKey && e.keyCode === 13)
	                    $('#rmBtn').click();
	            });
	        };
	    /*
	        Добавление выпадающего меню на все страницы
	    */
	    if (/\.([0-7]|1([0-1]([01])?|[45])?)\./g.test('.' + namespace + '.')) {
			if (mw.config.get('skin') == 'vector') 
				$('#p-views').after('<nav class="mw-portlet vector-menu vector-menu-dropdown vector-menu-dropdown-noicon" id="p-remove-js"><input class="vector-menu-checkbox" type="checkbox" aria-labelledby="p-remove-js-label"><h3 id="p-remove-js-label" class="vector-menu-heading"><span>Удалятор</span></h3><div class="vector-menu-content"><ul class="vector-menu-content-list">' + menu + '</ul></div></nav>');
			else
				$('#ca-history').after(menu);
	    }
	    /*
	        Событие по клику на любую кнопку выпадающего меню
	    */
	    $('#imp,#tRm,#mRm,#ret,#fRm,#noRnm,#rnm,#merge,#recov,#split').click(function() {
	        i = this.id;
	        modalHandler(
	            // [текущее действие, название модального окна и комментарий, название страницы, поддерживаемые шаблоны
	            i == 'imp'	? [ i, 'Номинация КУЛ',			'К улучшению'		] :
	            i == 'rnm'	? [ i, 'Номинация КПМ',			'К переименованию'	] :
	            i == 'tRm'	? [ i, 'Номинация КУ',			'К удалению'		] :
	            i == 'mRm'	? [ i, 'Номинация МНОГО КУ',	'К удалению'		] :
	            i == 'ret' 	? [ i, 'Оставлено',				'К удалению',		['ку', 'к удалению'],		'Оставлено' ] :
	            i == 'noRnm'? [ i, 'Не переименовано',		'К переименованию',	['кпм', 'к переименованию'],'Не переименовано' ] :
	            i == 'merge'? [ i, 'Номинация КОБ',			'К объединению'		] :
	            i == 'recov'? [ i, 'Номинация ВУС',			'К восстановлению'	] :
	            i == 'split'? [ i, 'Номинация к разделению','К разделению'		] :
	            i == 'fRm'	? [ i, 'Номинация КБУ'		] : 0
	        );
	    });
	});
}