Участник:Andreyiv/dabfixer.js
Перейти к навигации
Перейти к поиску
if( $.inArray(mw.config.get('wgNamespaceNumber'), [0,2,10,14,100,102]) != -1
&& /edit|submit/.test(mw.config.get('wgAction')) )
addFuncBtn('dabfixer', dabFixer, 'commons/thumb/7/7f/Disambig_red.svg/20px-Disambig_red.svg.png', 'Разрешение неоднозначностей')
function dabFixer(){
var disData = null, disIdx = -1, changes = [], dabMsgTimeout
var wikiText = $('#wpTextbox1').val()
var lnkRegExp, wikiLink, wikiLinkOrig, wikiLinkPos, snippetBefore, snippetAfter
//localization
//ruwiki
var $msg =
{requesting:'Ждём ответа от тулсервера...'
,unlink_tip:'Заменить ссылку на текст'
,undo_tip:'Отменить сделанное исправление'
,choose_tip:'Уточните ссылку, кликнув на более точном значении ниже'
,x_tip:'отменить изменение'
,cancel:'отменить'
,cancel_tip:'отменить все сделанные изменения и закрыть диалог'
,next_tip:'перейти к следующей ссылке на неоднозначность'
,linksback:'есть <b>обратная ссылка</b>, вероятно исправления не нужно'
,nolinks:'В тексте не найдено ссылок на $1'
,cancelled:'Все изменения отменены'
,finished:'Исправлено ссылок:'
,nodablinks:'В статье не найдено ссылок на неоднозначности'
,summary:'разрешение [[ВП:Неоднозначность|неоднозначностей]]'
}
function $i(txt) {
return $msg[txt] || txt
}
//send request
mw.util.addCSS('#dabMsg {background:#cec; border:1px solid; padding:0 10px}')
showMsg( $i('requesting'), 8000)
window.dabLinksProcess = dabLinksProcess
mw.loader.load('https://toolserver.org/~dispenser/cgi-bin/dablinks.py?\
format=json&callback=dabLinksProcess\
&titles='+mw.config.get('wgContentLanguage')+':'+encodeURIComponent(mw.config.get('wgPageName'))
+'&nocache='+Math.random())
return
//reseiving response
function dabLinksProcess(data){
try { disData = data.query.pages[0].disambiguationlinks } catch(e){}
if( !disData ) return showMsg( $i('nodablinks') )
$('#mw-content-text').hide().parent().append('<div id=dabFrame>\
<pre id=dabText style="padding-left:2px;font-family:monospace, sans-serif" />\
<div id=dabTitle style="float:left; border:2px outset; border-bottom:none; padding:0 5px; margin-right:1em">\
<span class=title />\
<span class=choose style="cursor:help">↓ </span></div>\
<div id=dabMenu>\
<div style="float:right">\
<span class=dabCount />\
<button class=next>→</button>\
<button class=cancel /></div>\
<button class=unlink style="opacity:0.6"><s>[\[</s> <s>]]</s></button>\
<button class=x/>\
<span class=info> </span> <span class=linksback /></div>\
<div id=dabPage/>\
</div>')
mw.util.addCSS('\
#dabFrame {padding:2px; border:1px solid gray}\
#dabFrame button {background:#cce; padding:0 5px; opacity:0.8; margin-left:0.5em;\
font-size:85%; line-height:1.5em; vertical-align:top; cursor:pointer;}\
#dabText.text {word-wrap: break-word; white-space:pre-wrap; border:2px inset}\
#dabText .highlighted {background:#FFFF00}\
#dabText .changed {background:#A0E0A0}\
#dabPage {width:100%; border:2px outset; padding:10px 0;\
max-height:230px; overflow-y:auto}\
#dabPage #disambig {font-size:75%; margin-bottom:0 !important; line-height:1em; padding:0}\
#dabPage span.editsection {display:none}\
#dabPage li.highlight {background-color:#F0F5F0; border:1px dotted gray}\
#dabPage a:hover {border-top:1px dotted green; border-top:1px dotted green}\
')
$('#dabFrame button').click(buttonClicked)
$('#dabPage').click(linkClicked)
//automatically localize texts and tooltips using $msg
$('#dabFrame span').add('#dabFrame button').each(function(){
cl = this.className.split(' ')[0]
if( !cl ) return
$(this)
.html( $msg[cl] || $(this).html() || cl )
.attr( 'title', $msg[cl+'_tip'] || '' )
})
//start with 1st link
$('#dabText')[0].scrollIntoView(true)
nextLink()
}
function buttonClicked(){
switch(this.className.split(' ')[0]){
case 'next':
nextLink()
break
case 'cancel':
showMsg( $i('cancelled') )
finishDialog()
break
case 'unlink':
wikiLink = wikiLinkOrig.replace(/^\[\[|\]\]|.+\|/g,'')
showArticleSnippet()
break
case 'x':
wikiLink = wikiLinkOrig
showArticleSnippet()
break
}
return false
}
function showMsg(msg, time){
if( dabMsgTimeout ) clearTimeout(dabMsgTimeout)
$('#dabMsg').remove()
$('<div id=dabMsg />').append(msg).prependTo('#editform')[0].scrollIntoView()
dabMsgTimeout = setTimeout( "$('#dabMsg').remove()", time||3000 )
}
function nextLink(){
//save previous change
if( wikiLink && (wikiLink != wikiLinkOrig) ){
wikiText = wikiText.substring(0,wikiLinkPos) + wikiLink
+ wikiText.substr(wikiLinkPos+wikiLinkOrig.length)
changes.push([wikiLinkOrig, wikiLink])
}
if( findDabInText() ) return showArticleSnippet() //show next link for the same dab title
else if( ++disIdx < disData.length ) nextDabTitle() //switch to next dab title
else finishDialog(true)
}
function nextDabTitle(){
var dab = disData[disIdx]
//show dab title
var ttl = dab.target || dab.title
$('#dabTitle .title').html(
'<a target=_blank href="'
+ mw.config.get('wgArticlePath').replace(/\$1/,'') + encodeURI(ttl).replace(/\?/g,'%3F')
+ '">' + ttl + '</a>'
)
//update other areas
$('#dabPage').empty()
$('#dabFrame .dabCount').text( (disIdx + 1) + '/' + disData.length)
$('#dabMenu .linksback').toggle( dab.linksback==1 )
//create regexp for dab title
var i, ch, re = ''
for( i=0; ch=dab.title.charAt(i), i<dab.title.length; i++ ) //escape special chars
re += ('(){}^$.+*|/\\'.indexOf(ch) != -1 ? '\\' :'') + ch
ch = re.charAt(0) // 'word' -> '(w|W)ord'
if( /^[\wА-ЯЁ]/.test(ch) ) re = '('+ch+'|'+ch.toLowerCase()+')' + re.substring(1)
lnkRegExp = new RegExp('\\[\\[\\s*'+re+'\\s*(\\|[^\\[\\]]+)?\\]\\][a-zа-яё]*', 'g')
//see if we can find dab title in text
if( findDabInText() ){
showArticleSnippet()
$('#dabPage').html('<img src=/skins-1.5/common/images/spinner.gif />')
.load(mw.config.get('wgScript')+'?action=render&title='+encodeURIComponent(dab.title), guessDab)
}else{
$('#dabText').removeClass('text').html(
'<i><center>'
+ $i('nolinks').replace(/\$1/,'<b>[\['+dab.title+']]</b>')
+ '</center></i>' )
}
}
function findDabInText(){
if( !lnkRegExp || !(wikiLink=lnkRegExp.exec(wikiText)) ) return false
wikiLink = wikiLinkOrig = wikiLink[0]
wikiLinkPos = lnkRegExp.lastIndex - wikiLink.length
var p = wikiText.lastIndexOf('\n', wikiLinkPos-100)+1
if (wikiLinkPos-p > 500) p = wikiText.lastIndexOf('. ', wikiLinkPos-150)+2
if (wikiLinkPos-p > 500) p = wikiText.lastIndexOf(' ', wikiLinkPos-200)+1
if (wikiLinkPos-p > 500) p = wikiLinkPos-200
snippetBefore = mw.html.escape(wikiText.substring(p,wikiLinkPos))
p = wikiText.indexOf('\n', wikiLinkPos + 100)
if (p-wikiLinkPos > 500) p = wikiText.indexOf('. ', wikiLinkPos+150)
if (p-wikiLinkPos > 500) p = wikiText.indexOf(' ', wikiLinkPos+200)
if (p-wikiLinkPos > 500) p = wikiLinkPos+200
snippetAfter = mw.html.escape(wikiText.substring(wikiLinkPos+wikiLink.length, p))
return true
}
function showArticleSnippet(){
var isChanged = wikiLink != wikiLinkOrig
$('#dabText').empty().addClass('text').append(snippetBefore
+'<span class=highlighted>'+mw.html.escape(wikiLink)+'</span>'+snippetAfter)
$('#dabText .highlighted').toggleClass('changed', isChanged)
$('#dabMenu button.x').css('visibility', isChanged?'visible':'hidden')
$('#dabMenu button.unlink').css('visibility', /^\[/.test(wikiLink)?'visible':'hidden')
}
function finishDialog(isSuccess){
if( isSuccess ){
$('#wpTextbox1').val(wikiText)
var sm = $('#wpSummary').val()
if( sm.indexOf($i('summary')) == -1 )
$('#wpSummary').val( sm + (sm?', ':'') + $i('summary') )
showMsg( $i('finished') + ' ' + changes.length )
}
$('#dabFrame').remove()
$('#mw-content-text').show()
}
function linkClicked(e){
e.preventDefault()
if( e.target.nodeName != 'A' ) return
var targ = $(e.target)
// !!! todo: check for parent metadata
var ttl = targ.attr('href')
ttl = targ.hasClass('new')
? /\?title=([^&]+)/. exec( ttl )
: /\/wiki\/([^\?]+)/.exec( ttl )
if( !ttl ) return
ttl = decodeURIComponent( ttl[1] ).replace( /_/g, ' ' )
wikiLink = wikiLinkOrig.replace( /\[\[(.+\|)?(.+)\]\](.+)?/,
function(str, lnk, name, trail){
return '[\[' + ttl + '|' + name + (trail||'') + ']]'
})
showArticleSnippet()
return false
}
function guessDab(){ //try to guess wich link on dab page is closer to article being edited
$('#floating_object').remove()
var words, word, score, count, ma, lis = $('#dabPage li')
for (var l=0; l<lis.length;l++){
score = 0; count = 0
words = lis.eq(l).text().replace(/[^\wа-яё]+/gi,' ').split(' ')
for (var i=0; i<words.length; i++){
word = words[i]
if (/^[а-яё]+$/i.test(word)) word = word.substr(0, word.length-2) //rus suffix
if (word.length < 4) continue //too short
if (disData[disIdx].title.match(RegExp('^'+word,'i'))) continue //disambig title
count++
ma = wikiText.match(RegExp(word, 'ig'))
if (!ma) continue
score += ma.length
}
lis[l].score = score / count
}
lis.sort(function(a,b){return b.score-a.score})
lis.eq(0).addClass('highlight')
}
}