MediaWiki:Gadget-diffpopups.js

Материал из свободной русской энциклопедии «Традиция»
Перейти к навигации Перейти к поиску

Замечание: Чтобы после сохранения вступили в силу изменения стилей, перезагрузите файл //traditio.wiki/w/load.php?debug=false&lang=ru&modules=site&only=styles&skin=vector&*, если используете скин Vector, или //traditio.wiki/w/load.php?debug=false&lang=ru&modules=site&only=styles&skin=common&*, если используете скин Common.

Чтобы вступили в силу изменения скриптов, перезагрузите файл //traditio.wiki/w/load.php?debug=false&lang=ru&modules=site&only=scripts&skin=vector&*, если используете скин Vector, или //traditio.wiki/w/load.php?debug=false&lang=ru&modules=site&only=scripts&skin=common&*, если используете скин Common.

Гаджеты и импортируемые скрипты загружаются отдельными файлами.

var popIdx = 0;
var gotPages = {}; //aray of retreived pages
var html;

var needCSSImported = true;


$(function(){
var body = document.getElementById('bodyContent');
if (!body) return;

document.write('<style>\
 table.diff td div {overflow-x: auto !important; overflow-y:hidden !important;} \
 span.sig { border:1px dotted gray; border-bottom:none;\
   font-family:cursive; font-size:90%;}\
 td.diff-addedline, diff-deletedline {font-size:100%}\
 </style>');
// text-decoration:underline; 
// white-space:nowrap

//if (document.URL.match('diff='))  processRows(body);
markDiffLinks(body);
});



function markDiffLinks(el){
 addEvent(el, 'click', diffPopup);
 var links = el.getElementsByTagName('a');
 for (var i=0; i<links.length; i++)
   if (links[i].href.indexOf('diff=') >= 0)
     links[i].style.fontStyle='italic';
    //links[i].onclick=diffPopup;    //addEvent(links[i], 'click', diffPopup);
}




function diffPopup(e){

 //check if click was on a diff link
 var targ;
 if (!e) var e = window.event;
 if (e.target) targ = e.target;
 else if (e.srcElement) targ = e.srcElement;
 if (e.shiftKey) return;
 if (!targ.href || targ.href.indexOf('diff=')<0) return;

 if (needCSSImported) importDiffCSS();

 //prevent browser from followint the link
 if (e.preventDefault) e.preventDefault()
 else e.returnValue = false;

 if(wgCanonicalNamespace == 'Special' || !wgCanonicalSpecialPageName) // watchlist/recent and history
   targ.style.textDecoration='underline'; 

 //workaround for image diffs: doesn't work with &action=render
 if (targ.href.match(/title=%D0%98%D0%B7%D0%BE%D0%B1%D1%80%D0%B0%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5%3A/) ||
  targ.href.match(/title=Image:/)) 
  return false

 //get and process html code
 var url = targ.href + '&diffonly=yes&action=render';
 html = getPage(url);
 var j = html.indexOf('</tr>');
 var header = html.substring(0,j+5); //info about diffs
 html = html.substring(j+6); //diffs

 processHTML();

 //create popup box
 if (targ.id != 'differences-prevlink' && targ.id != 'differences-nextlink' )
   pop = createPopup();

 pop['url'] =  url;


 
 var caption = '<div style="background:#F0F0F0;font-size:120%;border:2px outset gray;padding:2px;cursor:pointer" class=caption></div>'
 pop.innerHTML = caption + '<div>' + header + html + '</div>' + caption ;
 

 var title = header.match(/title=[^&>"]+/);
 if (title){
  title = title[0].split('=')[1];
  pop['caption'] = title;//!!!
  title = '<a href='+wgServer+'/wiki/'+title+'>'+decodeURIComponent(title).replace(/_/g,' ')+'</a>'+
   ' <a href='+wgServer+'/wiki/'+title+'?action=history>(h)</a>'
 } else title = '---';
 //title += '<a href=javascript:showRaw()>¶</a>';
 title = '<b>'+title+'</b>';
 //title += '<div style="background:yellow;width:auto"></div>'
 var td1 = pop.getElementsByTagName('td')[1];
 if (td1 && td1.className == 'diff-ntitle'){
   var el, time;
   if ((el=td1.childNodes[2]) && el.href){    //make last author bold
     el.style.border='2px solid green';  el.style.fontWeight = 'bold';  el.style.padding='1px';
   }
   if (time = td1.innerHTML.match(/\d\d:\d\d, \d\d? [^ ]+ \d\d\d\d/))  //get "time ago"
     if (time = timeAgo(time[0])) title += ': ' + time + ' ago'; 
 }
 pop.firstChild.innerHTML = '<span></span>&nbsp' + title;
 pop.firstChild.onclick = closePopup;
 //pop.lastChild.innerHTML = title;

 if (html.length < 30000) processRows()
 else  setTimeout(processRows, 1000);

 markDiffLinks(pop);

 //if it's too wide
 //if (elementWidth(pop) +10 > windowWidth()) scrollBy(elementWidth(pop), 0);
 
 return false;
}

function closePopup(e){
 var targ;
 if (!e) var e = window.event;
 if (e.target) targ = e.target;
 else if (e.srcElement) targ = e.srcElement;
 if (targ && targ.className && targ.className=='caption'){
   targ.parentNode.style.display='none'; 
   popIdx--;
 }
}

function showRaw(){
 html = getPage(pop['url']);
 //pop.childNodes[1].innerHTML = 
}


function processHTML(){
 var ss='';
 //disabled: breaks real link too
 //text = text.replace(/http:\/\/ru\.wikipedia\.org\/w\/index\.php\?title=/g,'вики:');
 var alink = '<a href='+wgServer+'/wiki/';
 

 //выделить подпись
 html = html.replace(/(\[\[|\{\{)[^\[\{]{4,55} \d\d:\d\d, \d\d? \S{3,9} 20\d\d \(UTC\)/g, '<span class=sig>$&</span>');

 html = html.replace(/\[\[([^\]><}{|]+)\|?([^\]><]*)?\]\]/g, //[[link]]
 function(str,p1,p2){
  if (p1.match(/^(Изображение|Image):/)) p2=p1+(p2?p2:'');
  if (p1.match(/http:\/\//)) return str; //user made mistake
  if (!p2) p2=p1; //empty link name
  var firstChar = p1.substring(0,1);
  //need this!!! //if (firstChar=='#' || firstChar=='/') p1 = pop['caption'] + p1;
  return alink + encodeURI(p1)+' + title=\'' + str + '\'>' + p2 + '</a>';
 });


 html = html.replace(/\{\{(Участник:|User:)([^\}]*)\}\}/g, //{{User:subpage}}, usually this is sig
 function (str,p1,p2){
   return alink + encodeURI(p1+p2)+'>' + str + '</a>'; //title=\''+str+'\'
 });



 html = html.replace(/\[(https?:\/\/[^ \]><]*)( [^\]]*)?\]/g, //[http://...]
 function  (str,p1,p2){
  var link = '<a href=' + p1;
  var name = p2;
  var t, d; 
  var tip = tryDecodeURI(p1); //tooltip
  if (p1.substring(0,36) == (wgServer+'/w/index.php?')){//local link
    tip = tip.substring(36);
    if (!p2){
      t = tip.match(/title=[^&]+/);
      t = t ? '::'+t[0].split('=')[1].replace('_',' ') : '';
      if (d=tip.match(/diff=[^&]+/)) name = d[0] + t 
      else if (tip.match(/action=history/)) name = 'hist: ' + t
      else name = 'wiki: ' + tip;
    }
  } else { //ext link
    tip = tip.substring(7);
    link += ' class="external text"';
    if (!p2) name = tip;
  }
  if (!p2 && (name.length > 70)) name = name.substring(0,60) + '… …'
  return link + ' title="' + tip + '">[' + name + ']</a>';
 });

//html = html.replace(/\http:\/\/.*\]/g, function (str) //decode % sequences in URLS to avoid very wide table
 //{ try{str=decodeURIComponent(str)}catch (e){}; }); 
}

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




function processRows(){
var container = pop;
var table = container.getElementsByTagName('table')[0];
if (!table) return;
table.style.fontSize = '110%';

var cntAdded = 0; var cntRemoved = 0;
var tds, td, tr, html;
var stripes = false;
var firstColWidthSet = false;
//var 
trs = table.getElementsByTagName('tr');

for (var i=1; i<trs.length; i++){
 tr = trs[i];
 tds = tr.getElementsByTagName('td');
 if (tds.length == 1)
   tr.className = 'message'
 else if (tds.length == 2){ // "Line xx"
   tr.className = 'line';
   tr.style.fontSize='90%';
 }else if (tds.length == 3 && tds[1].className == 'diff-deletedline'){ //line removed
   tr.className = 'change';
   tds[1].style.backgroundColor = '#FFEECC'; //make it pink
   if (tds[1].innerHTML.length==0) tds[1].innerHTML='&nbsp' 
   else if (tds[1].innerHTML.match(/^===?.*===?$/)) tds[1].style.fontWeight = 'bold';
   tds[1].colSpan = 4; 
   tr.removeChild(tds[2]); tr.removeChild(tds[0]); 
 }else if (tds.length == 3 && tds[2].className == 'diff-addedline'){ //line added
   tr.className = 'change';
   if (stripes) tds[2].style.backgroundColor = '#beb';
   if (tds[2].innerHTML.length==0) tds[1].innerHTML='&nbsp'
   else if (tds[2].innerHTML.match(/^===?.*===?$/)) tds[2].style.fontWeight = 'bold'
   else if (tds[2].innerHTML.match(/\d\d:\d\d, \d\d? \S{3,9} 20\d\d \(UTC\)/)) stripes = !stripes; //sig found 
   tds[2].colSpan = 4; 
   tr.removeChild(tds[1]); tr.removeChild(tds[0]); 

 // rows with 4 cells
 }else if (tds[1].className == 'diff-context') {
   tr.className = 'context';
   stripes = false;
   tds[1].style.fontSize = '90%';
   tds[1].colSpan = 4; 
   tr.removeChild(tds[3]); tr.removeChild(tds[2]); tr.removeChild(tds[0]);
 }else{  
   tr.className = 'change';
   if (!firstColWidthSet) {tds[0].width = '5px'; tds[2].width = '5px'; firstColWidthSet = true; }
   if (tds[1].innerHTML.replace(/<span class="diffchange">&nbsp;<\/span>/g,' ')==tds[3].innerHTML){
     tr.className = 'nobr';  
     cntRemoved++;
     tr.style.display='none';
   }else if (tds[1].innerHTML==tds[3].innerHTML.replace(/<span class="diffchange">&nbsp;<\/span>/g,' ')){
     tr.className = 'nobr';  
     cntAdded++;
     tr.style.display='none';
   }
 }
}

if (cntRemoved>0 || cntAdded>0){
  //hide context rows that are not needed anymore
 for (var i=1; i<trs.length-1; i++)
  if (tr.className.match(/context|line/)
    && !trs[i-1].className.match(/change/) && !trs[i+1].className.match(/change/))
    tr.style.display='none';

 //add notice that 0x0A changes are hidden
 var newtd = document.createElement('td');
 newtd.colSpan=4;  newtd.style.textAlign='center'; newtd.style.fontWeight = 'bold';
 var notice = (cntRemoved>0)?' задушено: '+cntRemoved:'';
 notice += (cntAdded>0)?' вставлено: '+cntAdded:'';
 newtd.innerHTML = '<span style="border:2px solid orange; padding:2px">Неразрывных пробелов' + notice + '</span>';
 trs[1].parentNode.insertBefore(newtd, trs[1]);
}

}







function expandCell(td, style){
 var tr = td.parentNode;
 while (td.nextSibling) tr.removeChild(td.nextSibling); //remove all behind
 while (td.previousSibling) tr.removeChild(td.previousSibling); //remove all in front
 td.colSpan = 4;
 if (td.innerHTML.match(/^===?.*===?$/)){ //header
   td.style.fontSize = '100%';   td.style.fontWeight = 'bold';
 } 
 return;
}



function getStyle(el, cssRule){
 if(document.defaultView && document.defaultView.getComputedStyle) 
  var value = document.defaultView.getComputedStyle(el, '').getPropertyValue( 
      cssRule.replace( /[A-Z]/g, function(char) {return "-" + char.toLowerCase();} ));
 else if (el.currentStyle) 
  var value = el.currentStyle[cssRule];
 else
   var value = false;
 return value;
}


// Get the computed css property
function getStyle1( element, cssRule )
{
  if( document.defaultView && document.defaultView.getComputedStyle )
  {
    var value = document.defaultView.getComputedStyle( element, '' ).getPropertyValue( 
      cssRule.replace( /[A-Z]/g, function( match, char ) 
      { 
        return "-" + char.toLowerCase(); 
      } ) 
    );
  }
  else if ( element.currentStyle ) var value = element.currentStyle[ cssRule ];
  else                             var value = false;
  return value;
}



//var trs = pop.getElementsByTagName('tr');
//var tds  = trs[4].getElementsByTagName('td');
//tds[3].style.display='none';
//trs[4].removeChild(tds[2]);
//tds[1].colSpan = 3
//tds[1].style.paddingLeft = '10%';
// && trs[i-1].className != 'change'    && i+1<trs.length && trs[i+1].className != 'change')







function timeAgo(ss){ //accepts '05:53, 7 марта 2007', returns 'xx days, xx hours, xx mins'
 var s = ss.split(' ');
 var curTime = new Date();
 var diffTime = new Date();
 diffTime.setYear(s[3]);
 var month_name = s[2].substring(0,3).toLowerCase();
 var month = 'янвфевмарапрмаяиюниюлавгсеноктноядек'.indexOf(month_name);
 if (month == -1) month = 'janfebmaraprmayjunjulaugsepoctnovdec'.indexOf(month_name);
 if (month == -1) return null;
 diffTime.setMonth(month/3);
 diffTime.setDate(s[1]);
 diffTime.setHours(s[0].substring(0,2));
 diffTime.setMinutes(s[0].substring(3,5));
 var mins = (curTime - diffTime)/60000;
 var hours = Math.floor (mins/60);
 mins = Math.floor(mins - hours * 60);
 var days = Math.floor (hours/24)
 hours = hours - days * 24;
 var result = mins + ' min';
 if (hours) result = hours + ' hrs ' + result;
 if (days) result = days + ' days, ' + result;
 return result;
}


function createPopup(){
 var pop = document.createElement('div');
 document.body.appendChild(pop);
 pop.style.position = 'absolute';
 pop.style.border = '3px outset yellow';
 
 pop.style.top = windowScrolled() + 10 + 'px';
 pop.style.backgroundColor = 'white';
 pop.style.zIndex = 100;
 pop.style.fontSize = '10pt';
 //pop.onclick = function(){this.style.display='none'}
 var offset = 20 + (popIdx++) * 10;
 pop.style.left = offset + 'px';
 pop.style.width = windowWidth() - (50 + offset) + 'px';
 return (pop);
}



function importDiffCSS(){
 needCSSImported = false;
 var styleElem = document.createElement('style');
 styleElem.setAttribute('type', 'text/css' );
 styleElem.appendChild(document.createTextNode('@import "/skins-1.5/common/diff.css";' ));
 document.getElementsByTagName('head')[0].appendChild(styleElem);
}



function getPage(url){
 if (!gotPages[url]) {
   var a = sajax_init_object();
   if (a.overrideMimeType) a.overrideMimeType('text/html');
   a.open('GET', url, false);
   a.send(null);
   gotPages[url] = a.responseText;
 }
 return(gotPages[url]);
}


function addEvent(obj, event, func) {
 if (obj.addEventListener) obj.addEventListener( event, func, false );
 else if (obj.attachEvent) obj.attachEvent ('on'+event, func)
} 



function elementWidth(el){
 return Math.max(el.scrollWidth, el.offsetWidth);
}

function windowWidth(){
if (self.innerWidth) // all except Explorer
 return self.innerWidth
else if (document.documentElement && document.documentElement.clientWidth)// Explorer 6 Strict Mode
 return document.documentElement.clientWidth
else if (document.body) // other Explorers
 return document.body.clientWidth;
else return 0;
}


function windowScrolled(){
if (self.pageYOffset) // all except Explorer
 return self.pageYOffset;
else if (document.documentElement && document.documentElement.scrollTop)	// Explorer 6 Strict
 return document.documentElement.scrollTop;
else if (document.body) // all other Explorers
 return document.body.scrollTop;
}