Участник:Arbnos/wikilinker.js
Страница персонального оформления. После сохранения очистите кэш браузера.
// Russian Wiki Linker
// Find link for selected text
if (/edit|submit/.test(wgAction)){
var bpar = [WikiLinker, 'commons/b/bd/Wikilinker.png', 'Вики-ссыльщик. Подбирает вики-ссылку для выделенного слова или словосочетания'];
// Чтоб работало и до, и после MediaWiki:Editpage.js
if(addFuncBtn)addFuncBtn('wikilinker',bpar[0],bpar[1],bpar[2]);else{mwCustomEditButtons['wikilinker'] = bpar};
if(typeof Ignatus == 'object'){
Ignatus.wikilinker = Ignatus.wikilinker || {}
}else{
Ignatus = { 'wikilinker': {} }
};
// Подключение дизамбигуатора
if( !Ignatus.wikilinker.silent && (
!("dabfix" in Ignatus.wikilinker) || (Ignatus.wikilinker.dabfix && Ignatus.wikilinker.dabfix!='no')
) && !Ignatus.wikilinker.nodabdetect
&& (!Ignatus.dabfixer || !Ignatus.dabfixer.dabfix) // скрипт ещё не загружен
){
mw.loader.load('//ru.wikipedia.org/w/index.php?title=user:Ignatus/dabfixer.js&action=raw&ctype=text/javascript')
};
}
function WikiLinker() {
var CantWork = 'Сначала нужно выделить слово или словосочетание';
var range;
var browserType = 0;
var txt = '', nft;
var wpTextbox1 = document.editform.wpTextbox1;
var winScroll = document.documentElement.scrollTop;
wpTextbox1.focus();
if (typeof wpTextbox1.selectionStart != 'undefined') { // Modern browsers
browserType = 1;
var textScroll = wpTextbox1.scrollTop;
var startPos = wpTextbox1.selectionStart;
var endPos = wpTextbox1.selectionEnd;
txt = wpTextbox1.value.substring(startPos, endPos);
// отсекаем последние пробелы
while (txt.slice(-1) == ' ') {
txt = txt.slice(0,-1);
endPos = endPos - 1;
}
nft = mw.Title.newFromText(txt);
if (txt == '') {
alert(CantWork);
}
else {
processText();
}
wpTextbox1.selectionStart = startPos;
wpTextbox1.selectionEnd = startPos + txt.length;
wpTextbox1.scrollTop = textScroll;
} else if (document.selection && document.selection.createRange) { //IE
browserType = 2;
range = document.selection.createRange();
txt = range.text;
// отсекаем последний пробел
while (txt.slice(-1) == ' ') {
txt = txt.slice(0,-1);
range.moveEnd('character', -1);
}
nft = mw.Title.newFromText(txt);
if (txt == '') {
alert(CantWork);
}
else {
processText();
}
} else { // other browsers
alert("Your browser is not supported by Wikilinker :(");
}
document.documentElement.scrollTop = winScroll // scroll back, for IE/Opera
function processText() {
var phrase=txt.substr(0,100);
phrase=phrase.replace(/\s+|—|[_!?.,:]/g, " ");
phrase=phrase.replace(/»|«|\%|\'|\"/g, "");
phrase=phrase.replace(/(^\s+)|(\s+$)/g, "");
if( "exceptions" in Ignatus.wikilinker && initialLower(phrase) in Ignatus.wikilinker.exceptions ){
recordText( Ignatus.wikilinker.exceptions[initialLower(phrase)] );
return 0
};
$.ajax({
type: "GET", // request type ( GET or POST )
url: mw.util.wikiScript('api') + '?action=query&list=search&srlimit=5&srprop=redirecttitle&format=json&srsearch=' + phrase,
dataType: 'json',
success: stateChanged
})
}
function joino(o){
var a = new Array();
for(var e in o){a.push(e)};
return a.join('|')
}
function likeness(q){// Оценка сходства результата запроса с txt
var TXT = txt.toUpperCase(), i=0;
q = q.toUpperCase();
while( i<TXT.length && i<q.length && q.substr(0,i) == TXT.substr(0,i) )i++;
if( TXT.charAt(i+1)==q.charAt(i) || TXT.charAt(i)==q.charAt(i+1) )i+=0.5;// беглые гласные
return ( ( q.length-i && (q.length-i<4 ? (q.length-i)/6.01 : 0.499) )
+ ( TXT.length-i && (TXT.length-i<4 ? (TXT.length-i)/6.01 : 0.499) ) - i/TXT.length )
// Функция смещает максимум на 1 позицию вверх или чуть менее вниз
}
function warnred(isred,l){
if(Ignatus.wikilinker.warnredirects && isred){
warna('Добавлена ссылка на перенаправление на', l, 'подставить основное имя', function(){
$("#wpTextbox1").textSelection(
'encapsulateSelection',
{ 'peri': "", 'selectPeri': true, 'replace': true }
);
var restoretxt = /\[\[(?:.*\|)?(.*)\]\](.*)?/.exec(txt);
if(restoretxt)txt = restoretxt[1]+(restoretxt[2]||'');
recordText( l )
})
}
}
function loadpageprops(arr) {
var onreadystatechange = function(resp){
var p = resp.query.pages;
var id=false, rank=false;
// [КОСТЫЛЬ] на глюк Цирруса: не опознаёт страницы #перенаправление [[…]] как надо
/*[*/if('redirects' in resp.query){
for(var rn in resp.query.redirects){
arr[resp.query.redirects[rn].to] = arr[resp.query.redirects[rn].from]
}
}/*] Впрочем, можно и оставить для чего-нибудь*/
for(var a in p){// Выбираем самый ранжированый результат из не-дизамбигов
if( ("missing" in p[a]) || ("invalid" in p[a]) ){
//нет страницы
}else{
// Расчёт "веса" варианта с учётом места в выдаче,
var this_rank = arr[p[a].title][0] +
// дизамбиг или нет,
( "pageprops" in p[a] && "disambiguation" in p[a].pageprops
? ('penda' in Ignatus.wikilinker ? Ignatus.wikilinker.penda : 1000)
: 0
) +
// а также относительной схожести основного имени с исходным заданием
( arr[p[a].title]==txt ? -1 : likeness(p[a].title) );
if(
!id || this_rank < rank
){
id = a;
rank = this_rank
}
}
}
if( "pageprops" in p[id] && "disambiguation" in p[id].pageprops ){//это дизамбиг
operate_on_disambig(p[id].title)
};
if(Ignatus.wikilinker.noredirects){
recordText( p[id].title )
}else{
warnred( arr[p[id].title][1] != p[id].title && !(arr[p[id].title][0]==1 && nft && nft.getPrefixedText()==p[id].title), p[id].title );
recordText( (arr[p[id].title])[1] )
}
};//onreadystatechange
$.ajax({
type: "GET", // request type ( GET or POST )
url: mw.util.wikiScript('api') + '?action=query&prop=pageprops&format=json&redirects=1&titles='
+ encodeURIComponent(joino(arr)),
dataType: 'json',
success: onreadystatechange
})
}
function operate_on_disambig(t){
if(Ignatus.wikilinker.silent)return;// нечего делать
var df;
if( !("dabfix" in Ignatus.wikilinker) || Ignatus.wikilinker.dabfix && Ignatus.wikilinker.dabfix!='no' ){
df = Ignatus.wikilinker.dabfix || Ignatus.dabfixer.dabfix
};
warna('Добавлена ссылка на неоднозначность',t,(df?'разрешить':null),function(){df(t)})
}
function warna(c,t,l,f){
if(Ignatus.wikilinker.silent)return;
var popup = document.createElement('div');
// Текст сообщения
popup.appendChild(document.createTextNode(c+' '));
popup.style='background:white;';
var clorrer = function(){popup.parentElement.removeChild(popup);return false};
// Ссылка на статью t
var a = document.createElement('a');
a.href = wgServer+mw.util.getUrl(t);
a.appendChild(document.createTextNode(t));
popup.appendChild(a);
// Предложение действия
if(l){
popup.appendChild(document.createTextNode(', '));
var b = document.createElement('a');
b.appendChild(document.createTextNode(l));
b.onclick = function(){clorrer();if(f)f();}
popup.appendChild(b);
}
// Крестик-убиралка
a = document.createElement('span');
a.appendChild(document.createTextNode('\u00d7'));
a.style.color="gray";a.style.fontWeight="bold";a.style.marginLeft="1em";
a.onclick = clorrer;
popup.appendChild(a);
// Добавляем сообщение на верх формы редактирования
var ef = document.getElementById("editform");
ef.insertBefore(popup,ef.firstChild)
}
function initialLower(str) {
return str.substr(0, 1).toLowerCase() + str.substr(1);
}
function recordText(page_name){
// для "форумы" будет "[[форум]]ы", а не "[[форум|форумы]]"
if ( page_name != '' && initialLower(txt.substr(0, page_name.length)) == initialLower(page_name) && page_name.length <= txt.length) {
txt = '[[' + txt.substr(0, page_name.length) + ']]' + txt.substr(page_name.length, txt.length - page_name.length) ;
}
else {
txt = '[[' + page_name + '|' + txt + ']]';
}
if (browserType == 1) { //Mozilla/Opera/Safari3
wpTextbox1.value = wpTextbox1.value.substring(0, startPos) + txt + wpTextbox1.value.substring(endPos);
wpTextbox1.selectionStart = startPos;
wpTextbox1.selectionEnd = startPos + txt.length;
wpTextbox1.scrollTop = textScroll;
} else if (browserType == 2) { //IE
range.text = txt;
} else { // other browsers
alert(CantWork);
}
}
function stateChanged(resp) {
var pn = new Object(), i = 0;
while (typeof resp.query.search[i++] != 'undefined') {
var next_elem = [
i,// ВНИМАНИЕ! на следующей строчке — [КОСТЫЛЬ], который может понадобиться выкинуть
resp.query.search[i-1].redirecttitle /*[*/ && resp.query.search[i-1].redirecttitle.mTextform /*]*/
|| resp.query.search[i-1].title // редирект ближе к требуемому
];
// Если текст первого варианта равен в смысле вики-ссылки txt, меняем его на txt
if( i==1 && nft && nft.getPrefixedText() == next_elem[1] ) next_elem[1]=txt;
pn[resp.query.search[i-1].title] = next_elem
}
// Проверяем, дизамбиг ли и есть ли по исходному имени
if( i>1 ){//что-то нашли
if( Ignatus.wikilinker.silent || Ignatus.wikilinker.nodabdetect ){//нас не интересую дизамбиги
var sn = 0;
if(
likeness(resp.query.search[0].title) - likeness(resp.query.search[1].title) >= 1
&& ( !nft || pn[resp.query.search[0].title][1] != nft.getPrefixedText() )
){
sn=1;//перестановка вариантов, если второй куда ближе к исходнику
warnred( resp.query.search[1].redirecttitle, resp.query.search[1].title );// NB! Не закостылено по глюку CirrusSearch, см. выше
}else{warnred( resp.query.search[0].redirecttitle, resp.query.search[0].title )};// Поскольку основное назначение режима — уменьшать кол-во запросов, то и не будем костылить
for(var z in pn){ if(pn[z][0]==sn ){
recordText( Ignatus.wikilinker.noredirects ? z : pn[z][1] )
}}
}else{ loadpageprops(pn) }
}else{//ничего не найдено
var sugg = resp.query.searchinfo.suggestion;
warna("Ничего не нашлось по запросу",txt,"подставить «"+sugg+"»",function(){
$("#wpTextbox1").textSelection(
'encapsulateSelection',
{ 'peri': sugg, 'selectPeri': true, 'replace': true }
);
});
recordText("")
}
}
}