// Подсвечивает все ссылки на непатрулируемые страницы.
// Если определено Ignatus.hlnp.pagere=/^Портал:(Портал1|Портал2)$/ и т. п.,
// то работает только на страницах, соответствующих этому РВ (пробелы заменятся подчёркиваниями).
// код частично основан на MediaWiki:Gadget-bkl-check.js
if(typeof Ignatus != 'object')Ignatus={hlnp:{}};
else if(typeof Ignatus.hlnp != 'object') Ignatus.hlnp={};
// **************** Настройки гаджета ****************** //
// Пример: напишите на странице [[Special:MyPage/common.js]] строку (без //)
// Ignatus = { hlnp: { pagere: new RegExp("^(Проект|Портал):.*/Новые (страницы|статьи)"), noimg: true, stdclasses: true } };
var pagere = Ignatus.hlnp.pagere;// Регулярное выражение имени страницы, где гаджет работает <везде>
var noimg = Ignatus.hlnp.noimg;// Не обрабатывать ссылки, содержащие изображения
var stdclasses = Ignatus.hlnp.stdclasses;// Использовать классы подсветки в СН (проверено для скина Vector)
// ***************************************************** //
if ( mw.config.get('wgNamespaceNumber') >= 0 && ( !pagere || pagere.test( mw.config.get('wgPageName') ) )
&& mw.config.get('wgUserName') && {submit:true, view:true, historysubmit:true, purge:true}[mw.config.get('wgAction')]
) {
// Добавляем классы в начало (переопределите при надобности в [[Special:MyPage/common.css]])
if(!stdclasses)$('head').prepend(
'<style type=text/css>.unpat-link {background-color: #FFFF80; padding-left: 1px; padding-right: 1px; padding-top: 1px; padding-bottom: 2px}\n'+
'.totally-unpat-link {background-color: #FFB080; padding-left: 1px; padding-right: 1px; padding-top: 1px; padding-bottom: 2px}</style>');
var patnss = {0:true, 6:true, 10:true, 14:true, 100:true, 828:true}; // Здесь должен быть актуальный список патрулируемых пространств имён
var className= (stdclasses ? "flaggedrevs-pending" : 'unpat-link'), // Класс для ссылок на статью с непроверенной последней версией
className2= (stdclasses ? "flaggedrevs-unreviewed" : "totally-unpat-link"), // Класс для ссылок на непатрулировавшуюся статью
titleAppend = ' (не патрулировано)',
titleAppend2= ' (не патрулировалось)',
titleAppend3= ' (непатрулированное перенаправление)',
titleAppend4= ' (не патрулировавшееся перенаправление)',
queryUrlPreview= mw.config.get( 'wgScriptPath' ) + '/api.php?action=query&format=json&prop=flagged&indexpageids',
titles= {}, //{"название страницы":["класс CSS", "что дописать к названию ссылки"],...}
redirects= {},// Список редиректов по названию
links,// Доступный всем функциям список элементов-ссылок
linksfrompg,//Получать страницы из DOM (иначе запрашвать через generator=links)
count,//счётчик помечаемых страниц
ta,// Хранилище части имён страниц к запросу
previewQueryCount,//счётчик ожидаемых запросов, когда вернётся к 0, помечаем
execute, storeTitles, markLinks, PreviewQuery, getLinks, nsExists;// Функции, кот. нам понадобятся
nsExists = function(n) {
return mw.config.get('wgNamespaceIds')[n.toLowerCase().replace(/\s/g,"_")]
}
storeTitles = function ( res ) {// Запись в titles и redirects результатов запроса к API
if ( !res || !res.query || !res.query.pageids ) return;
var q = res.query; var pids=q.pageids;var i;
var ra;// Массив-накопитель редиректов
// Если редирект не патрулирован, показываем его статус и направляем ссылку без перехода.
// Если патрулирован, то потом запросим и покажем статус статьи.
if(q.redirects){// Если вызываем для набора перенаправлений
var rdlist = q.redirects; // [{from:'редирект',to:'куда'},...]
ra={};// Здесь переводим в ассоциативную базу
for ( i=0; i<rdlist.length; i++) ra[rdlist[i].to]=rdlist[i].from;//{статья:перенаправление, ...}
}
for ( i = 0; i < pids.length; i++ ) {
var page = q.pages[pids[i]];
var isrd = page.title in redirects;
if ( page.missing === '' || !patnss[page.ns] ) continue;// Не обрабатываем чужие п. и.
if ( page.flagged && !page.flagged.pending_since ) continue; //Патрулировано
else if (isrd) delete redirects[page.title];// Непатрулированное перенаправление не надо запрашивать
count++;
titles[ 'redirects' in q ? ra[page.title] : page.title ] = page.flagged
? [ className, ( isrd?titleAppend3:titleAppend ).replace( ')', ' с ' + page.flagged.pending_since + ')' ) ]
: [ className2, ( isrd?titleAppend4:titleAppend2 ) ];
}
};
markLinks = function () {// Собственно, отобразить пометки
if ( !count ) return;
if ( !links ) return;
for ( var i = 0; i < links.length; i++ ) {
// Do not mess with images and user-specified objects
if ( /image/.test( links[i].className) || noimg && $(links[i]).find('img').length )continue;
var tpl = titles[links[i].title];
if ( !tpl ) continue;
// Помещаем внутренность ссылки в цветной span
$(links[i]).wrapInner('<span class="' + tpl[0] + '" title="'+links[i].title+tpl[1]+'"></span>');
if(tpl[1].indexOf('перенапр')!=-1)links[i].href+=(links[i].href.indexOf('?')==-1?'?':'&')+'redirect=no';
//Если это непатрулированное перенаправление, то меняем ссылку на статью на ссылку на редирект
}
};
PreviewQuery = function ( titles, wut ) {//Конструктор запроса к БД, используется для предпросмотра и редиректов
previewQueryCount++;//Размечать будем, когда придут все ответы
//We have to keep the titles in memory in case we get a query-continue
this.data ='titles='+ titles.join( '|' );// Редиректы запрашиваем по pageids, остальное - по titles
this.doQuery( queryUrlPreview + wut );
};
execute = function ($content) {// Получаем список ссылок в предпросмотре и делаем по ним запросы
links = getLinks( $content );
count=0;
previewQueryCount=0;
if ( !links ) return;
ta=[]; var m, m1;
linksfrompg = mw.config.get('wgAction')!=='view' || mw.config.get('wgNamespaceNumber')===14;
// В режиме просмотра получать ссылки быстрее через generator=links, если это не категория
var unique = {};
var rxEscape = function(s) {return s.replace( /([\/\.\*\+\?\|\(\)\[\]\{\}\\])/g, '\\$1' );};
var siteRegex = new RegExp( rxEscape( mw.config.get('wgServer') ).replace( "\\.wiki","(\\.m)?\\.wiki") // для мобильных версий
+ rxEscape( mw.config.get('wgArticlePath').replace( /\$1/, '' ) ) + '([^#]*)' );
var patnsregex = new RegExp("^(|Шаблон|Файл|Модуль|Категория|Портал)$");// Здесь должен быть актуальный список патрулируемых п. и.
//We only care for some ns pages, so we can filter out the most common cases to save some requests
for ( var i = 0; i < links.length; i++ ) {//Помещаем в локальную titles базу заголовков
if (!links[i].title || !( m = decodeURI(links[i].href).match( siteRegex ) ) || ( m1=m[2].match('^([^:]+):') )
&& ( !m1[1].match( patnsregex ) && nsExists(m1[1]) )
|| unique[m[2]] || noimg && $(links[i]).find('img').length ) continue;
unique[m[2]] = true; //Avoid requesting same title multiple times
if( $(links[i]).hasClass('mw-redirect') ) redirects[links[i].title] = true;//Запоминаем, что это редирект
if(linksfrompg){
ta.push( m[2].replace( /_/g, '%20' ) ); //Avoid normalization of titles // Надо ли?
if ( ta.length < 50 ) continue;// Лимит заглавий 50
new PreviewQuery( ta, '' );
ta =[];
}else linksfrompg=null;//Сигнал, что что-то есть
}
if ( ta.length ) new PreviewQuery( ta, '' );
else if(linksfrompg===null){
for(i in patnss){
ta.push(String(i));
}
new PreviewQuery([mw.config.get('wgPageName')] ,'&generator=links&gpllimit=max&gplnamespace='+ta.join('|'));
}
},
getLinks = function ( el ) {
return el && el.find( 'a' );
};
PreviewQuery.prototype.doQuery = function( url ) {
var q = this;
$.ajax( {
url: url,
method: 'POST',
contentType: 'application/x-www-form-urlencoded',
data: q.data,
success: function( data, textStatus, jqXHR ) {
q.resultArrived( data );
}
} );
};
PreviewQuery.prototype.resultArrived = function ( res ) {//Обработка запроса в предпросмотре
storeTitles( res );
if ( res && res.continue ) {//Не уложились в лимит
var c=res.continue;
var url = queryUrlPreview +
'&gplcontinue=' + encodeURIComponent( c.gplcontinue ) +
'&continue=' + encodeURIComponent( c.continue );
if(!linksfrompg)url+='&generator=links&gpllimit=max&gplnamespace='+ta.join('|');// Если продолжаем запрос ссылок из БД
if(res.query && res.query.redirects) url += '&redirects'; // Если продолжаем запрос редиректов
this.doQuery( url );// Посылаем продолженный запрос по тем же страницам в this.data
} else {//Все данные по текущему набору получены, уменьшаем счётчик запросов
if( !--previewQueryCount ){// Все запросы выполнены
if(!(res.query && res.query.redirects)){//обрабатываем редиректы, если мы не этим занимались
var rids=[];
for(var rid in redirects){
rids.push(rid);
if(rids.length<50)continue;
new PreviewQuery(rids, '&redirects');//Запрашиваем редиректы
rids=[];
}
if(rids.length)new PreviewQuery(rids, '&redirects');
}
if( !previewQueryCount ) markLinks();//Если редиректы не запущены, размечаем
}
}
};
mw.hook('wikipage.content').add( execute );
}//if