Community Central
Community Central
No edit summary
No edit summary
Line 3: Line 3:
 
// Load various external scripts
 
// Load various external scripts
 
// *****************************************************************
 
// *****************************************************************
 
importScriptURI('http://en.wikipedia.org/w/index.php?title=User:Js/diffs.js&action=raw&ctype=text/javascript');
 
   
 
importScriptURI('http://janitor.wikia.com/index.php?title=User:Exlex/scripts.js&action=raw&ctype=text/javascript');
 
importScriptURI('http://janitor.wikia.com/index.php?title=User:Exlex/scripts.js&action=raw&ctype=text/javascript');
  +
  +
  +
  +
$(function(){
  +
  +
  +
var dfPopupSheet
  +
  +
  +
mw.util.addCSS('\
  +
td.diff-addedline:hover .diffchange, td.diff-deletedline:hover .diffchange {background:#fdd}\
  +
')
  +
var localDomain = new RegExp('^https?:' + wgServer.replace(/([\.\/])/g,'\\$1') + '\/')
  +
  +
  +
$(function(){
  +
  +
var $tbl = $('table.diff')
  +
if( $tbl.length ){
  +
improveTable($tbl)
  +
dfAddToolbar($tbl, '#contentSub')
  +
}
  +
  +
mw.util.$content.click(dfClick)
  +
  +
mw.util.addCSS('\
  +
a[href*="diff="][href^="/w"],\
  +
a[href*="diff="][href*="' + wgServer + '"]' +
  +
(window.dfDiffLinksCSS || '{font-style:italic}') +'\
  +
a[href*="diff="][href^="/w"]:hover,\
  +
a[href*="diff="][href*="' + wgServer + '"]:hover\
  +
{color:red !important}\
  +
.df-popup {margin:0.5em}\
  +
')
  +
  +
  +
})
  +
  +
$(document).keyup( function(e){ //close popup on Escape
  +
if( e.which == 27 ) popupClose('.df-instance:last')
  +
})
  +
  +
  +
  +
function dfClick(e){
  +
  +
cursorWait() //cancel waiting indicator if something went wrong
  +
if( e.shiftKey || e.which != 1) return
  +
  +
//is it a diff link?
  +
var lnk = $(e.target).closest('a')
  +
if( !lnk.length ) return
  +
var url = lnk.attr('href').replace(localDomain, '/')
  +
if( ! /^\//.test(url) ) return //external URL
  +
  +
var loadURL, dfContainer
  +
  +
if( /[&?]diff=/.test(url) ){
  +
// diff
  +
if( /differences-(next|prev)link/.test( lnk.attr('id') ) )//prev/next link in diff table
  +
dfContainer = lnk.closest('table.diff').parent()
  +
else
  +
markClickedLink(lnk)
  +
if( /:Undelete/.test(url) )
  +
loadURL = url + '&useskin=myskin #content'
  +
else
  +
loadURL = url + '&action=render&diffonly=true'
  +
  +
}else if( wgCanonicalSpecialPageName == 'Watchlist'
  +
&& window.dfPinWatchlist //popup for any link
  +
&& ! lnk.closest('fieldset').length ){
  +
  +
if( ! /\?/.test(url) && ! /(special|служебная):/i.test(url) )
  +
loadURL = url + '?action=render'
  +
else
  +
loadURL = url + '&useskin=myskin #content'
  +
  +
}else{
  +
return
  +
}
  +
  +
//load diff
  +
e.preventDefault()
  +
cursorWait(true)
  +
dfContainer = dfContainer || popupCreate(e)
  +
dfContainer
  +
.attr('dfURL', url)
  +
.load( loadURL, afterDiffLoaded )
  +
  +
}
  +
  +
  +
  +
  +
function afterDiffLoaded(){
  +
  +
cursorWait()
  +
var $container = $(this)
  +
  +
var url = $container.attr('dfURL')
  +
var dfLink = outputLink2('', $container.attr('dfURL'), 'Δ', 'current diff')
  +
  +
var $tbl = $container.find('table.diff')
  +
if( $tbl.length ) improveTable( $tbl )
  +
  +
if ( $container.hasClass('df-popup') ){
  +
  +
var pgTitle = getTitleFromURL( $tbl.find('td.diff-ntitle a').attr('href') )
  +
var caption = $(
  +
'<div class=df-caption>' +
  +
'<b>' + outputLink2(pgTitle) + '</b>' +
  +
' (' + outputLink2(pgTitle, '?action=history', 'h') + ' ' + dfLink + ')' +
  +
'</div>'
  +
)
  +
.prependTo($container)
  +
  +
dfAddToolbar($tbl, caption)
  +
$container.parent().appendTo('body')
  +
  +
}else{
  +
$('#contentSub')
  +
.children('.df-link').remove().end()
  +
.append(
  +
$('<span class=df-link style="margin-left:1em; font-weight:bold" />')
  +
.append( dfLink )
  +
)
  +
}
  +
  +
}
  +
  +
  +
  +
  +
  +
  +
  +
function popupCreate(e){
  +
  +
//set CSS
  +
if( ! dfPopupSheet ){
  +
dfPopupSheet = mw.util.addCSS('\
  +
.df-clicked {background-color:#E0E0E0}\
  +
a.df-clicked-last {background-color:#FFDDDD}\
  +
.df-popup {position:absolute; z-index:5; width:95%; border:1px solid #000033; \
  +
font-size:110%; background-color:white; padding:0 9px 9px 9px }\
  +
.df-caption {background:#F0F0FF; border:1px outset gray; padding:2px; margin:0 -9px}\
  +
.df-closer {position:absolute; z-index:10; border:2px outset gray;\
  +
width:20px; height:20px; cursor:pointer; background:gray; opacity:0.5}')
  +
if( ! /[&?]diff=/.test(document.URL) )
  +
importStylesheetURI('//bits.wikimedia.org/ru.wikipedia.org/load.php?modules=mediawiki.action.history.diff&only=styles')
  +
//importStylesheetURI('/skins-1.5/common/diff.css')
  +
}
  +
  +
//create popup
  +
var dfN = $('.df-popup').length
  +
var dfPopup = $('<div class=df-popup />')
  +
.css({
  +
top: $(window).scrollTop() + 30 + dfN * 5 + 'px',
  +
left: 10 + dfN * 5 + 'px'
  +
})
  +
.click( function(e){ //close popup when clicking on edges and and caption
  +
if( /df-(popup|caption)/.test(e.target.className) ) popupClose(this)
  +
else $(this).addClass('persistent')
  +
})
  +
.click(dfClick)
  +
// .mouseleave( function(e){
  +
// if( ! /persistent/.test(this.className) ) popupClose(this)
  +
// })
  +
  +
//create 'closing' square on mouse position
  +
var dfCloser = $('<div class=df-closer title=close>&nbsp;</div>')
  +
.css({top: e.pageY-10, left: e.pageX-10})
  +
.mouseleave( function(){ $(this).remove() })
  +
.click( function(){ popupClose(this) } )
  +
  +
$('<div class=df-instance />') //container for popup and closer
  +
.append(dfPopup, dfCloser)
  +
  +
// if (isIE) hideAllSelectElements(true) // !!!
  +
return dfPopup
  +
  +
}
  +
  +
  +
  +
function popupClose(el){
  +
$(el).closest('.df-instance').remove()
  +
}
  +
  +
  +
  +
//******************************************************************************************
  +
  +
function cursorWait(isWait){
  +
if( window.dfNoWaitCursor ) return
  +
document.body.style.cursor = isWait ? 'wait' : ''
  +
}
  +
  +
  +
function markClickedLink(lnk){ //and mark link as "clicked"
  +
$('a.df-clicked-last').removeClass('df-clicked-last') //rm class from previos click
  +
lnk.addClass('df-clicked df-clicked-last')
  +
if( /Watchlist|Recentchanges/.test(wgCanonicalSpecialPageName) )
  +
lnk.closest('li').add(lnk.closest('tr')).addClass('df-clicked')
  +
}
  +
  +
var dfHighlightSheet, dfImprovementSheet
  +
function addDiffTableCSS(){
  +
if( dfImprovementSheet ) return
  +
  +
dfImprovementSheet = mw.util.addCSS('\
  +
td.diff-addedline, td.diff-deletedline {font-size:100%}\
  +
table.diff {border-spacing:1px}\
  +
table.diff td {vertical-align:top}\
  +
table.diff {width:99%}\
  +
body table.diff, td.diff-otitle, td.diff-ntitle {background:#FBFBFB}\
  +
table.diff td.diff-lineno {border-top: 25px solid #FBFBFB}\
  +
tr.df-deleted td {background-color:#FEC}\
  +
table.diff td div {min-height:1em}\
  +
td.df-deletedwords, td.df-addedwords\
  +
{background:white; border:1px dotted gray; padding:2px}\
  +
td.df-deletedwords span.diffchange {background-color:#FFA}\
  +
td.df-addedwords span.diffchange {background-color:#CFC; color:black; font-weight:normal}\
  +
tr.odd td.diff-addedline {background-color:#BEB}\
  +
span.sig {border:1px dotted gray; border-bottom:none; font-family:cursive; font-size:90%}\
  +
td.df-header {font-weight:bold; font-size:120%; padding-top:15px}\
  +
tr.df-change td {font-size:100%}\
  +
tr.df-added ins.diffchange {color:inherit; font-weight:normal; border:none}\
  +
div.df-toolbar span.df-improve-btn {border:1px inset #EEEEEE}\
  +
.df-btn {padding:2px; border:1px solid gray; margin-right:2px; cursor:pointer}\
  +
table.diff td {cursor:help}\
  +
table.diff td div, table.diff td.diff-multi {margin:0 8px 0 2px; cursor:default}'
  +
+ (window.dfDiffTableCSS || '')) //user CSS
  +
  +
//cursor stuff shows that TD is clickable (sticking out from under DIV inside)
  +
  +
//padding: 0 8px 0 2px
  +
  +
//different approach to make cells clickable
  +
//+ 'table.diff {border-spacing:0} table.diff td {border-top:4px solid #FBFBFB} table.diff td.diff-deletedline {border-right: 6px solid #FBFBFB}'
  +
}
  +
  +
  +
  +
  +
  +
  +
//==============================================================================
  +
  +
  +
  +
function improveTable($tbl){
  +
if (window.dfMaxImproveSize && $tbl.html().length>dfMaxImproveSize) return
  +
//improve rows
  +
//curTitle = $tbl.parent()[0].diffTitle //needed in improveCell() for relative links
  +
curTitle = getTitleFromURL( $tbl.parent().attr('dfURL') )
  +
curStripes = false
  +
addDiffTableCSS()
  +
$tbl.find('tr').each(improveRow)
  +
$tbl.click(tableOnclick)
  +
}
  +
  +
  +
function dfAddToolbar($tbl, where){
  +
//return
  +
$('<div class=df-toolbar style="float:right" />')
  +
.append(
  +
//btn(changeTable, '¤', 'Enable/disable improvements'),
  +
btn(diffJSEngine, 'js', 'Javascript diff engine')
  +
)
  +
.prependTo(where)
  +
  +
function changeTable(){alert(11)}
  +
function btn(func, txt, tip){ //creates <span> button
  +
return $('<span class=df-btn title="' + tip + '">' + txt + '</span>')
  +
.click( { dTable: $tbl }, func )
  +
}
  +
}
  +
  +
  +
  +
  +
  +
  +
  +
  +
  +
function improveRow(){
  +
  +
var tr = this, tds = $(this).find('td'), td
  +
  +
  +
if (tds.length <= 2) return // 'diff info' or 'intermediate revisions' or 'Line xx:'
  +
// case 'diff-otitle': case 'diff-multi': case 'diff-lineno':
  +
  +
if( tds.length == 3 ){
  +
if( tds[1].className == 'diff-deletedline' ){
  +
tr.className += ' df-deleted' //new class, means the line was simply deleted, has pink background
  +
if( tds[1].innerHTML.length==0 ) tds[1].innerHTML = '<br />'
  +
expandCell(tds[1])
  +
return
  +
}else if( tds[2].className == 'diff-addedline' ){
  +
tr.className += ' df-added'
  +
improveCell(tds[2])
  +
htm = tds[2].innerHTML
  +
if( !htm.length ) tds[2].innerHTML = '<br />'
  +
if( curStripes ) tr.className += ' odd'
  +
if( /<span class="sig">/i.test(htm) ) curStripes = !curStripes
  +
expandCell(tds[2])
  +
return
  +
}
  +
}else if (tds[1].className == 'diff-context'){
  +
tr.className = 'df-context'
  +
if (window.dfParseContext) improveCell(tds[1])
  +
expandCell(tds[1])
  +
curStripes = false
  +
return
  +
}else{ //normal yellow/green rows with 4 cells
  +
tr.className = 'df-change'
  +
tds[1].colSpan = tds[3].colSpan = 2
  +
tr.removeChild(tds[2]); tr.removeChild(tds[0])
  +
}
  +
//if( window.dfImproveAdvanced ) improveRowMore(tr)
  +
return
  +
  +
  +
  +
  +
  +
  +
  +
function expandCell(td, clss){
  +
/*
  +
while (td.nextSibling) tr.removeChild(td.nextSibling)
  +
while (td.previousSibling) tr.removeChild(td.previousSibling)
  +
td.colSpan = 4
  +
if( clss ) td.className = clss
  +
*/
  +
tr.innerHTML = '<td colspan=4 class="' + td.className + (clss?' ' + clss:'') + '">'
  +
+ td.innerHTML + '</td>'
  +
}
  +
  +
  +
function splitRowsUp(tdGoesUp){
  +
tds[0].colSpan = 4
  +
tds[1].colSpan = 4
  +
//tr.removeChild(tds[2])
  +
//tr.removeChild(tds[0])
  +
var trnew = document.createElement('tr')
  +
trnew.className = 'df-change'
  +
trnew.appendChild(tdGoesUp)
  +
tr.parentNode.insertBefore(trnew, tr)
  +
}
  +
  +
  +
  +
  +
} //improveRow()
  +
  +
  +
  +
  +
  +
  +
  +
  +
  +
function improveCell(cell){
  +
if (window.dfNoWikiParsing) return
  +
  +
cell = $(cell)
  +
var htm = cell.html()
  +
if (htm.length == 0) return //cell.innerHTML = '&nbsp;'
  +
  +
cell.data('origHTML', htm)
  +
if (/^==.*== *$/i.test(cell.text())) cell.addClass('df-header')
  +
  +
  +
htm = htm.replace(/\u00A0/g, '<b>\u00B7</b>')
  +
htm = htm.replace(/({\{u(?:ser(?:links)?)?\|)([^}]+)}\}/g, function(str,tmpl,user){
  +
return tmpl + outputLink2('special:contributions/'+user,'',user) + '}}' })
  +
  +
//mark signatures
  +
htm = htm.replace(/(\[\[[^\[]{4,65})?\d\d:\d\d, \d\d? \S{3,9} 20\d\d \(UTC\)/g, '<span class="sig">$&</span>')
  +
htm = htm.replace(/\{\{unsigned[^\}]\}\}/i, '<span class="sig">$&</span>')
  +
  +
//[[link]]
  +
var CatOrFileRegExp = RegExp('^('+wgFormattedNamespaces[6]+'|'
  +
+wgFormattedNamespaces[14]+'|category|image|file):|\.(jpg|png|svg|gif)$','i')
  +
htm = htm.replace(/\[\[([^\]><}{|]+)\|?([^\]><]*)?\]\]/g,
  +
function(wikicode,page,name){
  +
if (/http:\/\//i.test(page)) return wikicode //user made a mistake
  +
if (CatOrFileRegExp.test(page)) name = page+(name?'|'+name:'') //file or category, show in full
  +
else if (!name) name = page
  +
if (/^[#\/]/.test(page)) page = curTitle + page //relative link
  +
else if (/^[a-z]{2,7}:/.test(page)) page = 'Special:Search/'+page //possible interproject link, some are not "local"
  +
return outputLink2(page, '', name, wikicode)
  +
})
  +
  +
// [http://...]
  +
htm = htm.replace(/\[(https?:\/\/[^ \]><]*)( [^\]]*)?\]/g, //
  +
function (str,link,name){
  +
var output = '<a href=' + link, title, tip, nameWas = name
  +
if (link.indexOf(wgServer+wgScript) == 0){ //local link
  +
tip = tryDecodeURI(link.substring((wgServer+wgScript).length+1))
  +
if (!name){
  +
name = getTitleFromURL(link) || tip
  +
if (/diff=/.test(link)) name = 'diff: ' + name
  +
else if (tip.match(/action=history/)) name = 'hist: ' + name
  +
else if (tip.match(/oldid=/)) name = 'oldid: ' + name
  +
else name = 'wiki: ' + name
  +
}
  +
} else { //ext link
  +
tip = tryDecodeURI(link.substring(7))
  +
output += ' class="external text"'
  +
if (!name) name = tip
  +
}
  +
if (!nameWas && (name.length > 70)) name = name.substring(0,60) + '… …'
  +
return output + ' title="' + tip + '">[' + name + ']</a>'
  +
})
  +
  +
cell.html(htm)
  +
  +
function tryDecodeURI(s){ try{s=decodeURIComponent(s)}catch (e){}; return s }
  +
  +
}
  +
  +
  +
  +
  +
function outputLink2(page, params, name, tooltip){
  +
name = name || page
  +
page = page.replace(/&amp;/gi,'&').replace(/#.+$/, calcAnchor)
  +
return '<a href="'+ wgArticlePath.replace(/\$1/,'')
  +
+ encodeURI(page).replace(/\?/g,'%3F')
  +
+ (params||'')
  +
+ '" title="' + (tooltip||name).replace(/"/g,'&quot;') + '">' + name + '</a>' //'
  +
}
  +
  +
  +
function calcAnchor(txt){ //try to create href anchor similar to Parser.php::guessSectionNameFromWikiText()
  +
txt = $.trim(txt).replace(/#/g,'')
  +
.replace(/\[\[([^|]+\|)?([^\]]+)\]\]/g, '$2') //[[foo|bar]] -> bar
  +
.replace(/<.*?>/g, '').replace(/ /g,'_')
  +
// (we skip step "HTML entities are turned into their proper characters")
  +
return '#' + encodeURIComponent(txt).replace('%3A', ':').replace(/%([0-9A-F][0-9A-F])/g, '.$1')
  +
//maybe encodeURI(p1.replace(/\?/g,'%3F').replace(/&/g,'%26')) ?
  +
}
  +
  +
  +
function getTitleFromURL(url){
  +
var tt = /title=([^&>"]+)/.exec(url) //"
  +
if( tt ) return decodeURIComponent(tt[1]).replace(/_/g,' ')
  +
else return ''
  +
}
  +
  +
  +
function tableOnclick(e){
  +
var trg = e.target
  +
if( trg.className ) switch ( trg.className ){
  +
//case 'diff-lineno': changeBlock(trg.parentNode); return
  +
//case 'diff-otitle': case 'diff-ntitle': return
  +
case 'diff-addedline': case 'diff-deletedline': case 'diff-context':
  +
//if( trg.nodeName != 'TD' || $(trg).parents('table.diff').length == 0 ) break
  +
//parse wikicode in already improved row when clicked on white border above row
  +
var orig = $(trg).data('origHTML')
  +
if( orig ) $(trg).html(orig).data('origHTML','')
  +
else improveCell(trg)
  +
return
  +
}
  +
}
  +
  +
  +
function changeBlockXXX(row){ //switch improvement level for this part of diff table
  +
var dTbody = row.parentNode, rowIdx = 1, isImproved
  +
//find clicked row number
  +
while (rowIdx < dTbody.rows.length && dTbody.rows[rowIdx] != row) rowIdx++
  +
if (dTbody.rows[rowIdx] != row) return
  +
//check if rows are improved or not
  +
if (row.className == 'df-lineno'){
  +
isImproved = true
  +
var origTable = createTableFromHTML(requestedPages[dTbody.parentNode.parentNode.dfURL])
  +
}else
  +
dfImprovementSheet.disabled = false
  +
//improve / de-improve rows
  +
do{
  +
if (isImproved) dTbody.replaceChild(origTable.rows[rowIdx].cloneNode(true), row)
  +
else improveRow(row)
  +
}while((row=dTbody.rows[++rowIdx]) && row.cells[0].className != 'diff-lineno')
  +
  +
}
  +
  +
  +
  +
  +
  +
  +
  +
  +
  +
  +
  +
  +
  +
  +
  +
// *** JS Diff Engine ***
  +
function diffJSEngine(e){
  +
var $tbl = e.data.dTable
  +
var htm = $tbl.data('origHTML')
  +
  +
//call and run JS diff engine
  +
if( window.WDiffString ) diffJSGo()
  +
else importScriptAndRun('http://en.wikipedia.org/w/index.php?title=User:Cacycle/diff.js', diffJSGo)
  +
  +
function diffJSGo(){
  +
cursorWait(true)
  +
//var
  +
var oldVer = '', newVer = '', txt, marker
  +
$tbl.find('td').each(function(){
  +
txt = $(this).data('origHTML') || this.innerHTML
  +
txt = txt.replace(/<.+?>/g,'') + '\n'
  +
switch( this.className ){
  +
case 'diff-context':
  +
marker = '\x03' + txt + '\x04\n'
  +
oldVer += marker
  +
newVer += marker
  +
i += 2 //skip other context cell
  +
break
  +
case 'diff-lineno':
  +
//oldVer += '\n\n\n\n\n\n'
  +
//newVer += '\n\n\n\n\n\n'
  +
break // !!!
  +
case 'diff-deletedline':
  +
oldVer += txt
  +
break
  +
case 'diff-addedline':
  +
newVer += txt
  +
break
  +
}
  +
})
  +
//compare and display
  +
txt = WDiffString(oldVer, newVer)
  +
//txt = txt.replace(/\x03.*?\x04/g, '<br><br><hr><br><br>')
  +
txt = txt.replace(/\x03|\x04/g, '')
  +
txt = WDiffShortenOutput(txt)
  +
//txt = txt.replace(/¶/g,'<br>')
  +
txt = txt.replace(/&amp;/g,'&')
  +
//txt = txt.replace(/&lt;/g,'<').replace(/&gt;/g, '>')
  +
$('<div style="padding:2px"><br><br><h3>JS Engine diff</h3><hr style="height:5px" />'
  +
+ txt + '</div>')
  +
.insertAfter($tbl)[0].scrollIntoView()
  +
cursorWait()
  +
}
  +
  +
  +
}
  +
  +
  +
  +
function importScriptAndRun(url, func) {
  +
var s = document.createElement('script')
  +
s.type = 'text/javascript'
  +
s.src = url + '&action=raw&ctype=text/javascript'
  +
if( $.client.profile().name == 'msie')
  +
s.onreadystatechange = function(){ if( /loaded|complete/.test(this.readyState) ) func() }
  +
else
  +
s.onload = func
  +
document.getElementsByTagName('head')[0].appendChild(s)
  +
}
  +
  +
  +
  +
  +
  +
})
   
 
//</pre>
 
//</pre>

Revision as of 15:01, 13 November 2011

//<pre>
// *****************************************************************
// Load various external scripts 
// *****************************************************************

importScriptURI('http://janitor.wikia.com/index.php?title=User:Exlex/scripts.js&action=raw&ctype=text/javascript');



$(function(){


var dfPopupSheet
 

mw.util.addCSS('\
td.diff-addedline:hover .diffchange, td.diff-deletedline:hover .diffchange {background:#fdd}\
')
 var localDomain = new RegExp('^https?:' + wgServer.replace(/([\.\/])/g,'\\$1') + '\/')
 

$(function(){
 
 var $tbl = $('table.diff')
 if( $tbl.length ){
   improveTable($tbl)
   dfAddToolbar($tbl, '#contentSub')
 }
 
 mw.util.$content.click(dfClick)

 mw.util.addCSS('\
a[href*="diff="][href^="/w"],\
a[href*="diff="][href*="' + wgServer + '"]' +
 (window.dfDiffLinksCSS || '{font-style:italic}') +'\
a[href*="diff="][href^="/w"]:hover,\
a[href*="diff="][href*="' + wgServer + '"]:hover\
 {color:red !important}\
.df-popup {margin:0.5em}\
 ')
 
 
})
 
 $(document).keyup( function(e){ //close popup on Escape
   if( e.which == 27 ) popupClose('.df-instance:last')
 })



function dfClick(e){

 cursorWait() //cancel waiting indicator if something went wrong
 if( e.shiftKey || e.which != 1) return

 //is it a diff link?
 var lnk = $(e.target).closest('a')
 if( !lnk.length ) return
 var url = lnk.attr('href').replace(localDomain, '/')
 if( ! /^\//.test(url)  ) return //external URL
 
 var loadURL, dfContainer
 
 if( /[&?]diff=/.test(url) ){
 // diff
   if( /differences-(next|prev)link/.test( lnk.attr('id') ) )//prev/next link in diff table
      dfContainer = lnk.closest('table.diff').parent()
   else
      markClickedLink(lnk)
   if( /:Undelete/.test(url) )
     loadURL = url + '&useskin=myskin #content'
   else
     loadURL = url + '&action=render&diffonly=true'
   
 }else if( wgCanonicalSpecialPageName == 'Watchlist' 
        && window.dfPinWatchlist //popup for any link 
        && ! lnk.closest('fieldset').length ){

    if( ! /\?/.test(url) && ! /(special|служебная):/i.test(url) )
      loadURL = url + '?action=render'
    else 
      loadURL = url + '&useskin=myskin #content'
 
 }else{
   return
 }  
 
 //load diff
 e.preventDefault()
 cursorWait(true)
 dfContainer = dfContainer || popupCreate(e)
 dfContainer
 .attr('dfURL', url)
 .load( loadURL, afterDiffLoaded )

}




function afterDiffLoaded(){

 cursorWait()
 var $container = $(this)
 
 var url = $container.attr('dfURL')
 var dfLink = outputLink2('', $container.attr('dfURL'), 'Δ', 'current diff')

 var $tbl = $container.find('table.diff')
 if( $tbl.length ) improveTable( $tbl )

 if ( $container.hasClass('df-popup') ){

   var pgTitle = getTitleFromURL( $tbl.find('td.diff-ntitle a').attr('href') )
   var caption = $(
    '<div class=df-caption>' + 
    '<b>' + outputLink2(pgTitle) + '</b>' +
    ' (' + outputLink2(pgTitle, '?action=history', 'h') + ' ' + dfLink  + ')' +
    '</div>'
   )
   .prependTo($container)

   dfAddToolbar($tbl, caption)
   $container.parent().appendTo('body')
 
 }else{
   $('#contentSub')
   .children('.df-link').remove().end()
   .append(
     $('<span class=df-link style="margin-left:1em; font-weight:bold" />')
     .append( dfLink )
   )
 }

}






 
function popupCreate(e){ 

 //set CSS
 if( ! dfPopupSheet ){
   dfPopupSheet = mw.util.addCSS('\
  .df-clicked {background-color:#E0E0E0}\
  a.df-clicked-last {background-color:#FFDDDD}\
  .df-popup {position:absolute; z-index:5; width:95%; border:1px solid #000033; \
    font-size:110%; background-color:white; padding:0 9px 9px 9px }\
  .df-caption {background:#F0F0FF; border:1px outset gray; padding:2px; margin:0 -9px}\
  .df-closer {position:absolute; z-index:10; border:2px outset gray;\
    width:20px; height:20px; cursor:pointer; background:gray; opacity:0.5}')
   if( ! /[&?]diff=/.test(document.URL) ) 
     importStylesheetURI('//bits.wikimedia.org/ru.wikipedia.org/load.php?modules=mediawiki.action.history.diff&only=styles')
     //importStylesheetURI('/skins-1.5/common/diff.css')
 }

 //create popup
 var dfN = $('.df-popup').length
 var dfPopup = $('<div class=df-popup />')
 .css({
   top: $(window).scrollTop() + 30  + dfN * 5 + 'px',
   left: 10 + dfN * 5 + 'px'
 })
  .click( function(e){ //close popup when clicking on edges and and caption
    if( /df-(popup|caption)/.test(e.target.className) ) popupClose(this)
    else $(this).addClass('persistent')
  })
  .click(dfClick)
// .mouseleave( function(e){
//    if( ! /persistent/.test(this.className) ) popupClose(this) 
//  })

  //create 'closing' square on mouse position
 var dfCloser = $('<div class=df-closer title=close>&nbsp;</div>')
 .css({top: e.pageY-10, left: e.pageX-10})
 .mouseleave( function(){ $(this).remove() })
 .click( function(){ popupClose(this) } )

 $('<div class=df-instance />') //container for popup and closer
 .append(dfPopup, dfCloser)
 
 // if (isIE) hideAllSelectElements(true) // !!!
 return dfPopup

} 
 


function popupClose(el){
 $(el).closest('.df-instance').remove()
}



//******************************************************************************************

function cursorWait(isWait){
 if( window.dfNoWaitCursor ) return
 document.body.style.cursor = isWait ? 'wait' : ''
}


function markClickedLink(lnk){ //and mark link as "clicked"
 $('a.df-clicked-last').removeClass('df-clicked-last') //rm class from previos click
 lnk.addClass('df-clicked df-clicked-last')
 if( /Watchlist|Recentchanges/.test(wgCanonicalSpecialPageName) )
   lnk.closest('li').add(lnk.closest('tr')).addClass('df-clicked')
}

var dfHighlightSheet, dfImprovementSheet
function  addDiffTableCSS(){
 if( dfImprovementSheet ) return

 dfImprovementSheet = mw.util.addCSS('\
td.diff-addedline, td.diff-deletedline {font-size:100%}\
table.diff {border-spacing:1px}\
table.diff td {vertical-align:top}\
table.diff {width:99%}\
body table.diff, td.diff-otitle, td.diff-ntitle {background:#FBFBFB}\
table.diff td.diff-lineno {border-top: 25px solid #FBFBFB}\
tr.df-deleted td {background-color:#FEC}\
table.diff td div {min-height:1em}\
td.df-deletedwords, td.df-addedwords\
 {background:white; border:1px dotted gray; padding:2px}\
td.df-deletedwords span.diffchange {background-color:#FFA}\
td.df-addedwords span.diffchange {background-color:#CFC; color:black; font-weight:normal}\
tr.odd td.diff-addedline {background-color:#BEB}\
span.sig {border:1px dotted gray; border-bottom:none; font-family:cursive; font-size:90%}\
td.df-header {font-weight:bold; font-size:120%; padding-top:15px}\
tr.df-change td {font-size:100%}\
tr.df-added ins.diffchange {color:inherit; font-weight:normal; border:none}\
div.df-toolbar span.df-improve-btn {border:1px inset #EEEEEE}\
.df-btn {padding:2px; border:1px solid gray; margin-right:2px; cursor:pointer}\
table.diff td {cursor:help}\
table.diff td div, table.diff td.diff-multi {margin:0 8px 0 2px; cursor:default}'
+ (window.dfDiffTableCSS || '')) //user CSS

//cursor stuff shows that TD is clickable (sticking out from under DIV inside)

//padding: 0 8px 0 2px

//different approach to make cells clickable
//+ 'table.diff {border-spacing:0} table.diff td {border-top:4px solid #FBFBFB} table.diff td.diff-deletedline {border-right: 6px solid #FBFBFB}'
}






//==============================================================================



function improveTable($tbl){
 if (window.dfMaxImproveSize && $tbl.html().length>dfMaxImproveSize) return
 //improve rows
 //curTitle = $tbl.parent()[0].diffTitle //needed in improveCell() for relative links
 curTitle = getTitleFromURL( $tbl.parent().attr('dfURL') )
 curStripes = false
 addDiffTableCSS()
 $tbl.find('tr').each(improveRow)
 $tbl.click(tableOnclick)
}


function dfAddToolbar($tbl, where){
 //return 
 $('<div class=df-toolbar style="float:right" />')
 .append(
   //btn(changeTable, '¤', 'Enable/disable improvements'),
   btn(diffJSEngine, 'js', 'Javascript diff engine')
 )
 .prependTo(where)
 
 function changeTable(){alert(11)}
 function btn(func, txt, tip){ //creates <span> button
   return $('<span class=df-btn title="' + tip + '">' + txt + '</span>')
          .click( { dTable: $tbl }, func )
 } 
}









function improveRow(){

 var tr = this, tds = $(this).find('td'), td


 if (tds.length <= 2) return // 'diff info' or 'intermediate revisions' or 'Line xx:'
   //  case 'diff-otitle': case 'diff-multi': case 'diff-lineno':
  
 if( tds.length == 3 ){
   if( tds[1].className == 'diff-deletedline' ){
     tr.className += ' df-deleted' //new class, means the line was simply deleted, has pink background
     if( tds[1].innerHTML.length==0 ) tds[1].innerHTML = '<br />'
     expandCell(tds[1]) 
     return
   }else if( tds[2].className == 'diff-addedline' ){
     tr.className += ' df-added'
     improveCell(tds[2])
     htm = tds[2].innerHTML
     if( !htm.length ) tds[2].innerHTML = '<br />'
     if( curStripes ) tr.className += ' odd'
     if( /<span class="sig">/i.test(htm) ) curStripes = !curStripes
     expandCell(tds[2])
     return
   }
 }else if (tds[1].className == 'diff-context'){
   tr.className = 'df-context'
   if (window.dfParseContext) improveCell(tds[1])
   expandCell(tds[1])
   curStripes = false
   return
 }else{ //normal yellow/green rows with 4 cells
   tr.className = 'df-change'
   tds[1].colSpan = tds[3].colSpan = 2
   tr.removeChild(tds[2]); tr.removeChild(tds[0])
 }
 //if( window.dfImproveAdvanced ) improveRowMore(tr)
 return 





 
 
 function expandCell(td, clss){
 /*
  while (td.nextSibling) tr.removeChild(td.nextSibling)
  while (td.previousSibling) tr.removeChild(td.previousSibling)
  td.colSpan = 4
  if( clss ) td.className = clss
  */
  tr.innerHTML = '<td colspan=4 class="' + td.className + (clss?' ' + clss:'') + '">'
   + td.innerHTML + '</td>'
 }


 function splitRowsUp(tdGoesUp){
  tds[0].colSpan = 4
  tds[1].colSpan = 4
  //tr.removeChild(tds[2])
  //tr.removeChild(tds[0])
  var trnew = document.createElement('tr')
  trnew.className = 'df-change'
  trnew.appendChild(tdGoesUp)
  tr.parentNode.insertBefore(trnew, tr)
 }

 

 
} //improveRow()









function improveCell(cell){
 if (window.dfNoWikiParsing) return

 cell = $(cell)
 var htm = cell.html()
 if (htm.length == 0) return  //cell.innerHTML = '&nbsp;'

 cell.data('origHTML', htm)
 if (/^==.*== *$/i.test(cell.text())) cell.addClass('df-header') 
       

 htm = htm.replace(/\u00A0/g, '<b>\u00B7</b>')
 htm = htm.replace(/({\{u(?:ser(?:links)?)?\|)([^}]+)}\}/g, function(str,tmpl,user){
  return tmpl + outputLink2('special:contributions/'+user,'',user) + '}}' })

 //mark signatures
 htm = htm.replace(/(\[\[[^\[]{4,65})?\d\d:\d\d, \d\d? \S{3,9} 20\d\d \(UTC\)/g, '<span class="sig">$&</span>')
 htm = htm.replace(/\{\{unsigned[^\}]\}\}/i, '<span class="sig">$&</span>')

 //[[link]]
 var CatOrFileRegExp = RegExp('^('+wgFormattedNamespaces[6]+'|'
  +wgFormattedNamespaces[14]+'|category|image|file):|\.(jpg|png|svg|gif)$','i')
 htm = htm.replace(/\[\[([^\]><}{|]+)\|?([^\]><]*)?\]\]/g,
 function(wikicode,page,name){
  if (/http:\/\//i.test(page)) return wikicode //user made a mistake
  if (CatOrFileRegExp.test(page)) name = page+(name?'|'+name:'') //file or category, show in full
  else if (!name) name = page
  if (/^[#\/]/.test(page)) page = curTitle + page //relative link
  else if (/^[a-z]{2,7}:/.test(page)) page = 'Special:Search/'+page //possible interproject link, some are not "local"
  return outputLink2(page, '', name, wikicode)
 })

 // [http://...]
 htm = htm.replace(/\[(https?:\/\/[^ \]><]*)( [^\]]*)?\]/g, //
 function  (str,link,name){
  var output = '<a href=' + link, title, tip, nameWas = name
  if (link.indexOf(wgServer+wgScript) == 0){ //local link
    tip = tryDecodeURI(link.substring((wgServer+wgScript).length+1))
    if (!name){
      name = getTitleFromURL(link) || tip
      if (/diff=/.test(link)) name = 'diff: ' + name
      else if (tip.match(/action=history/)) name = 'hist: ' + name
      else if (tip.match(/oldid=/)) name = 'oldid: ' + name
      else name = 'wiki: ' + name
    }
  } else { //ext link
    tip = tryDecodeURI(link.substring(7))
    output += ' class="external text"'
    if (!name) name = tip
  }
  if (!nameWas && (name.length > 70)) name = name.substring(0,60) + '… …'
  return output + ' title="' + tip + '">[' + name + ']</a>'
 })

 cell.html(htm)

function tryDecodeURI(s){ try{s=decodeURIComponent(s)}catch (e){}; return s }

}




function outputLink2(page, params, name, tooltip){
 name = name || page
 page = page.replace(/&amp;/gi,'&').replace(/#.+$/, calcAnchor)
 return '<a href="'+ wgArticlePath.replace(/\$1/,'')
  + encodeURI(page).replace(/\?/g,'%3F') 
  + (params||'')
  + '" title="' + (tooltip||name).replace(/"/g,'&quot;') + '">' + name + '</a>' //'
}


function calcAnchor(txt){ //try to create href anchor similar to Parser.php::guessSectionNameFromWikiText() 
 txt = $.trim(txt).replace(/#/g,'')
      .replace(/\[\[([^|]+\|)?([^\]]+)\]\]/g, '$2') //[[foo|bar]] -> bar
      .replace(/<.*?>/g, '').replace(/ /g,'_')
       // (we skip step "HTML entities are turned into their proper characters")
 return '#' + encodeURIComponent(txt).replace('%3A', ':').replace(/%([0-9A-F][0-9A-F])/g, '.$1')
 //maybe encodeURI(p1.replace(/\?/g,'%3F').replace(/&/g,'%26'))  ?
}


function getTitleFromURL(url){
 var tt = /title=([^&>"]+)/.exec(url) //"
 if( tt ) return decodeURIComponent(tt[1]).replace(/_/g,' ')
 else return ''
}


function tableOnclick(e){
 var trg = e.target
 if( trg.className ) switch ( trg.className ){
  //case 'diff-lineno': changeBlock(trg.parentNode); return
  //case 'diff-otitle': case 'diff-ntitle': return
  case 'diff-addedline': case 'diff-deletedline': case 'diff-context':
   //if( trg.nodeName != 'TD' || $(trg).parents('table.diff').length == 0 ) break 
   //parse wikicode in already improved row when clicked on white border above row
   var orig = $(trg).data('origHTML')
   if( orig ) $(trg).html(orig).data('origHTML','')
   else improveCell(trg)
   return
 }
}


function changeBlockXXX(row){ //switch improvement level for this part of diff table
 var dTbody = row.parentNode, rowIdx = 1, isImproved
 //find clicked row number
 while (rowIdx < dTbody.rows.length && dTbody.rows[rowIdx] != row) rowIdx++
 if (dTbody.rows[rowIdx] != row) return
 //check if rows are improved or not
 if (row.className == 'df-lineno'){
   isImproved = true
   var origTable = createTableFromHTML(requestedPages[dTbody.parentNode.parentNode.dfURL])
 }else
   dfImprovementSheet.disabled = false
 //improve / de-improve rows
 do{
   if (isImproved) dTbody.replaceChild(origTable.rows[rowIdx].cloneNode(true), row)
   else improveRow(row)
 }while((row=dTbody.rows[++rowIdx]) && row.cells[0].className != 'diff-lineno')

}















// *** JS Diff Engine ***
function diffJSEngine(e){
 var $tbl = e.data.dTable
 var htm = $tbl.data('origHTML')
 
 //call and run JS diff engine
 if( window.WDiffString ) diffJSGo()
 else importScriptAndRun('http://en.wikipedia.org/w/index.php?title=User:Cacycle/diff.js', diffJSGo)

 function diffJSGo(){
  cursorWait(true)
  //var
  var oldVer = '', newVer = '', txt, marker
  $tbl.find('td').each(function(){
    txt = $(this).data('origHTML') || this.innerHTML
    txt = txt.replace(/<.+?>/g,'') + '\n'
    switch( this.className ){
    case 'diff-context':
      marker = '\x03' + txt + '\x04\n'
      oldVer += marker
      newVer += marker
      i += 2 //skip other context cell
      break
    case 'diff-lineno':
      //oldVer += '\n\n\n\n\n\n'
      //newVer += '\n\n\n\n\n\n'
      break  // !!!
    case 'diff-deletedline':
      oldVer += txt
      break
    case 'diff-addedline':
      newVer += txt
      break
    }
  })
  //compare and display
  txt = WDiffString(oldVer, newVer)
  //txt = txt.replace(/\x03.*?\x04/g, '<br><br><hr><br><br>')
  txt = txt.replace(/\x03|\x04/g, '')
  txt = WDiffShortenOutput(txt)
  //txt = txt.replace(/¶/g,'<br>')
  txt = txt.replace(/&amp;/g,'&')
  //txt = txt.replace(/&lt;/g,'<').replace(/&gt;/g, '>')
  $('<div style="padding:2px"><br><br><h3>JS Engine diff</h3><hr style="height:5px" />'
     + txt + '</div>')
   .insertAfter($tbl)[0].scrollIntoView()  
  cursorWait()
 }


}



function importScriptAndRun(url, func) {
 var s = document.createElement('script')
 s.type = 'text/javascript'
 s.src = url + '&action=raw&ctype=text/javascript'
 if( $.client.profile().name == 'msie') 
   s.onreadystatechange = function(){ if( /loaded|complete/.test(this.readyState) ) func() }
 else 
   s.onload = func
 document.getElementsByTagName('head')[0].appendChild(s)
}





})

//</pre>