User:Microchip08/uberdiff.js

From Simple English Wikipedia, the free encyclopedia

Note: After publishing, you may have to bypass your browser's cache to see the changes.

  • Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
  • Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
  • Internet Explorer / Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5
  • Opera: Press Ctrl-F5.
/*
This script is not supported by Microchip08
See [[:en:User:Js/diff]] for directions

http://en.wikipedia.org/w/index.php?title=User:Js/diffs.js&oldid=279812200

Parameters:
 
These parameters can be set to true to override standard behaviour
------------------------------
dfNoPopups: no popups
dfNoAjaxDiff: no quick next/prev loading on usual diff pages
dfNoArrowKeys : disable keyboard shortcuts (left/right arrow keys)  for  next/prev diff
dfNoWikiParsing : completely disable wikicode parsing in diffs
dfParseContext : also parse gray columns
 
dfHighlightOn : turn diff highlighting (red borders) on by default
dfNoWaitCursor : set to true to disable cursor changing to "wait"
wikEdFullDiff: do not shorten JS Diff Engine output (pretty much useless)
 
dfDiffLinksCSS: set this to CSS string to replace default  "{font-style:italic}" for all diff links
dfDiffTableCSS: extra CSS for diff table
 
dfImproveAdvanced :  imrove diffs even more (make simple diffs as one column)
dfOneColumn : convert all diffs to one column view
 
-----------------
dfMaxImproveSize : diffs over this size (in Kb) will not be improved automatically
*/
 
 
 
 
ffNoPopups=true
 
var diffScript = new function(){ //wrapper
 
var dfNoWikiParsing = window.dfNoWikiParsing, dfNoPopups = window.dfNoPopups
var curTitle, tempDiv, curStripes
var requestedPages = {} //aray of retreived diffs, used as cache
var isIE = navigator.userAgent.indexOf('MSIE') != -1
var popupCount = 0 //, popupArray = []
var articlePath = wgArticlePath.replace('$1', '')
var clickedLinkLast
 
this.start = function(){
 
 addHandler(document, 'click', onClick)
 if (!window.dfNoArrowKeys) addHandler(document, 'keyup', onKeyUp)
 if (!dfNoPopups) appendCSS('a[href^="'+wgServer+'/w/index.php"][href*="diff="],\
  a[href^="/w/index.php"][href*="diff="]' + (window.dfDiffLinksCSS || '{font-style:italic}'))
 //if (isIE &&  isIE6) //no CSS3 support in IE6, should make links italic manually
 
 if (document.URL.indexOf('diff=') != -1){ //this is a diff page
   //find diff table
   var content = document.getElementById('content') || document.getElementById('mw_content') || document
   var curTable = findDiffTable(content)
   if (!curTable) return
   var parent = curTable.parentNode
   //remember url and title, and cache
   parent.diffURL = document.URL
   parent.diffTitle = wgPageName
   requestedPages[document.URL] = '<table class=diff>' + curTable.innerHTML + '</table>'
   //improve diff Table
   improveTable(curTable)
   parent.insertBefore(createToolbar(parent), parent.firstChild)
 }
 
}
 
 
 
function onClick(e){
 cursorWait() //cancel waiting indicator if something went wrong
 
 //find event and click target
 e = e || window.event
 if (e.shiftKey || e.button == 2) return // shift key or right click
 if ((isIE && e.button == 4) || (!isIE && e.button == 1)) return //middle click
 var targ = e.target || e.srcElement
 //log(targ)
 if (!targ) return
 
 //clicked on diff table
 // ...
 
 //clicked on diff popup
 if (targ.className)
 switch (targ.className){
  case 'df-popup': closePopup(targ); return
  case 'df-caption': closePopup(targ.parentNode); return
  case 'diff-lineno': changeBlock(targ.parentNode); return
  case 'diff-addedline': case 'diff-deletedline': case 'diff-context': processCell(targ); return
 }
/*
 if (!dfNoPopups && targ.className){
   if (targ.className=='df-popup') return closePopup(targ)
   if (targ.className=='df-caption') return closePopup(targ.parentNode)
 }
 if (targ.className == 'diff-lineno') return changeBlock(targ.parentNode)
 //else if (targ.className == 'diff-marker') return changeRow(targ.parentNode)
 */
 
 //clicked on a diff link
 var url = targ.href
 if (!url || url.indexOf('diff=') == -1) return //not a diff
 if (url.indexOf(wgServer) != 0 && url.charAt(0) != '/') return //diff, but not to this server
 if (targ.parentNode.className == 't-print') return
 //check if it was nex/prev diff link
 var isClickIntercepted = true
 if (/differences-(prev|next)link/.test(targ.id)) isClickIntercepted = followNextLink(targ)
 else if (!dfNoPopups) createPopup(targ)
 else isClickIntercepted = false
 //do not follow the link
 if (isClickIntercepted){
   if (e.preventDefault) e.preventDefault(); else e.returnValue = false
   return false
 }else
   return true
}
 
 
 
 
 
function improveTable(dTable){
 if (window.dfMaxImproveSize && dTable.innerHTML.length>dfMaxImproveSize) return
 //remove diff marker colums
 //var cols = dTable.getElementsByTagName('col')
 //var col
 //while(col=dTable.getElementsByTagName('col')[0]) col.parentNode.removeChild(col)
 //improve rows
 var trs = dTable.getElementsByTagName('tr')
 curTitle = dTable.parentNode.diffTitle //needee in processHTML() for relative links
 curStripes = false
 for (var i=1; i<trs.length; i++) improveRow(trs[i])
 //add CSS
 addDiffTableCSS()
}
 
 
 
function improveRow(tr){
 
 var tds = tr.getElementsByTagName('td'), td
 tr.className = 'df-change' //by default, as most common case
 
 if (tds.length == 1){  // 'One intermediate revision not shown'
   tr.className = 'df-message'
   return //plus maybe 
 
 }else if (tds.length == 2){ // "Line xx:"
   tr.className = 'df-lineno'
   return
 
 }else if (tds.length == 3 && tds[1].className == 'diff-deletedline'){
   tr.className += ' df-deleted'
   if (tds[1].innerHTML.length==0) tds[1].innerHTML = '<div>&nbsp;</div>'
   expandCell(tds[1]) //new class, means the line was simply deleted, has pink background
   return
 
 }else if (tds.length == 3 && tds[2].className == 'diff-addedline'){
   tr.className += ' df-added'
   processHTML(tds[2])
   htm = tds[2].innerHTML
   if (htm.length==0) tds[2].innerHTML = '<div>&nbsp;</div>'
   if (curStripes) tr.className += ' odd'
   if (/<span class="?sig"?>/i.test(htm)) curStripes = !curStripes
   if (/^<div>==.*== *<\/div>$/i.test(htm))
      tds[2].firstChild.style.cssText = 'font-weight:bold; font-size:120%; padding-top:15px'
   expandCell(tds[2])
   return
 
 }else if (tds[1].className == 'diff-context') {
   tr.className = 'df-context'
   if (window.dfParseContext) processHTML(tds[1])
   expandCell(tds[1])
   curStripes = false
   return
 }
 
 //from here we're left with normal yellow/green rows with 4 cells
 tds[1].colSpan = tds[3].colSpan = 2
 tr.removeChild(tds[2]); tr.removeChild(tds[0])
 if (!window.dfImproveAdvanced) return
 
 
 tds = tr.getElementsByTagName('td')
 var oldline = tds[0].innerHTML
 var newline = tds[1].innerHTML
 
 //check for simple  diffs
 if (oldline.length < 90 && oldline.replace(/<.+?>| |\n/g,'') == ''){ //old empty
   tds[1].className = 'diff-addedline'
   tds[1].innerHTML = newline.replace(/<span class="diffchange">/i,'').replace(/<\/span>/i,'')
   processHTML(tds[1])
   splitRowsUp(tds[0])
 
 }else if (newline.length < 90 && newline.replace(/<.+?>| |\n/g,'') == ''){ //new empty
   tds[0].className = 'df-deletedline' // !!! replace wih tr-deleted
   tds[0].innerHTML = oldline.replace(/<span class="diffchange">/i,'').replace(/<\/span>/i,'')
   splitRowsUp(tds[1])
 
 }else if (!/<span/i.test(newline)){ //simple change: something removed
   processHTML(tds[0])
   expandCell(tds[0], 'df-deletedwords')
 
 }else if (!/<span/i.test(oldline)){ //simple change: something added
   processHTML(tds[1])
   expandCell(tds[1], 'df-addedwords')
 
  }else{ //complex case
   //processHTML(tds[1])
   //processHTML(tds[3])
   if (window.dfOneColumn){ // separate into different rows anyway
    tds[0].firstChild.style.borderTop = '10px solid #FBFBFB'
    tds[1].firstChild.style.borderBottom = '10px solid #FBFBFB'
    splitRowsUp(tds[0])
   }else{
    //remove + / - markers ?
   }
  }
 
 
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
}
 
 
 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 changeTable(e){ //switch between original diff table and improved
 e = e || window.event
 var butt = e.target || e.srcElement
 var curTable = getClickedTable(e)
 if (dfImprovementSheet.disabled) improveTable(curTable)
 else replaceTable(curTable, requestedPages[curTable.parentNode.diffURL])
 dfImprovementSheet.disabled = !dfImprovementSheet.disabled
}
 
 
function changeBlock(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.diffURL])
 }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')
 
}
 
 
function processCell(cell){ //parse wikicode in already improved row when clicked on white border above row
 if (cell.origHTML){ //restore
   cell.innerHTML = cell.origHTML
   cell.origHTML = null
 }else{
   processHTML(cell)
 }
}
 
 
// NOT USED
function changeRow(row){ //switch one rowl improvement level when clicked on +- marker on the left
 var dTbody = row.parentNode, rowIdx = 1
 //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.indexOf('df-change') != -1){
   var origTable = createTableFromHTML(requestedPages[dTbody.parentNode.parentNode.diffURL])
   dTbody.replaceChild(origTable.rows[rowIdx].cloneNode(true), row)
 }else{
   dfImprovementSheet.disabled = false
   improveRow(row)
   var tds = row.cells
   processHTML(tds[1])
   processHTML(tds[3])
 }  
}
 
 
function createToolbar(parent){
 var dToolbar = document.createElement('div')
 dToolbar.tableParent = parent //reference so we can find table later
 dToolbar.className = 'df-toolbar'
 dToolbar.appendChild(btn(changeTable, '¤', 'Enable/disable improvements', 'df-improve-btn')) //÷
 dToolbar.appendChild(btn(highlightDiffs, 'π', 'Highlight differences with red border', 'df-highlight-btn')) 
 dToolbar.appendChild(btn(diffJSEngine, 'Δ', 'Javascript diff engine'))
 //references back and forth
 return dToolbar
}
 
function btn(func, htm, tooltip, clss){ //creates <span> button
 var bt = document.createElement('span')
 bt.innerHTML = htm
 bt.onclick = func
 bt.title = tooltip
 bt.className = clss || 'df-btn'
 return bt
}
 
 
 
function getClickedTable(e){
 e = e || window.event
 var button = e.target || e.srcElement
 return button.parentNode.tableParent.getElementsByTagName('table')[0]
}
 
 
 
 
 
 
 
 
function processHTML(elem){
 
 if (dfNoWikiParsing) return
 
 var html = elem.innerHTML
 elem.origHTML = html
 if (html.length == 0) return  //elem.innerHTML = '&nbsp;'
 
 html = html.replace(/({\{userlinks\|)([^}]+)}\}/, function(str,tmpl,user){
  return tmpl + outputLink('special:contributions/'+user,'',user) + '}}' })
 
 //mark signatures
 html = html.replace(/(\[\[[^\[]{4,65})?\d\d:\d\d, \d\d? \S{3,9} 20\d\d \(UTC\)/g, '<span class=sig>$&</span>')
 html = html.replace(/\{\{unsigned[^\}]\}\}/i, '<span class=sig>$&</span>')
 
 //[[link]]
 html = html.replace(/\[\[([^\]><}{|]+)\|?([^\]><]*)?\]\]/g,
 function(wikicode,page,name){
  if (/http:\/\//i.test(page)) return wikicode //user made a mistake
  if (/^image:|\.(jpg|png|svg|gif)$/i.test(page) && name)  name = page + name  //display full image link, including "image:"
  if (!name) name = page
  if (page.substring(0,1)=='#' || page.substring(0,1)=='/') {
    page = curTitle + page //relative link
  }
  if (/^[a-z]{2,7}:/.test(page)) //possible interproject link, and some are not "local"
     page = 'Special:Search/'+page 
  return outputLink(page, '', name, wikicode)
 })
 
 // [http://...]
 html = html.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>'
 })
 
 elem.innerHTML = html
 
function tryDecodeURI(s){ try{s=decodeURIComponent(s)}catch (e){}; return s }
 
}
 
 
 
function followNextLink(clickedLink){ //loads next/prev diff using next/prev diff link
 //find old table
 var el = clickedLink
 while (el && el.nodeName != 'TABLE') el = el.parentNode
 if (!el || el.className != 'diff') return false
 var oldTable = el
 if (oldTable.parentNode.className != 'df-popup'){ //normal diff page, not a popup
   if (window.dfNoAjaxDiff) return false
   if (el=document.getElementById('t-print')) el.style.display = 'none' //hide "printable" link which becomes outdated
 }
 //replace diff with new table
 loadDiff(clickedLink, oldTable)
 return true
}
 
 
 
function replaceTable(oldTable, html){
 //append new table
 var newTable = createTableFromHTML(html)
 oldTable.parentNode.insertBefore(newTable, oldTable)
 //remove everything below new table: old table, (now outdated) prevew, js engine diff
 var el
 while ((el=newTable.nextSibling) && !/visualClear|df-caption/.test(el.className))
   el.parentNode.removeChild(el)
 return newTable
}
 
 
function createTableFromHTML(html){
 if (!tempDiv) tempDiv = document.createElement('div')
 tempDiv.innerHTML = html
 return findDiffTable(tempDiv)
}
 
 
function findDiffTable(el){
 var i = 0, tables = el.getElementsByTagName('table')
 while (i < tables.length && tables[i].className != 'diff') i++
 if (i < tables.length) return tables[i]; else return null //then it's  div.firstrevisionheader
} 
 
 
// *** POPUP ***
 
 
function createPopup(clickedLink){
 //initialize
 if (clickedLinkLast) 
   changeClass(clickedLinkLast, 'df-clicked-last', 'df-clicked')
 clickedLinkLast = clickedLink
 changeClass(clickedLinkLast, 'df-clicked', 'df-clicked-last')
 addDiffPopupCSS()
 if (isIE) hideAllSelectElements(true)
 //create popup
 popupCount++
 var pop = document.createElement('div')
 pop.className = 'df-popup'
 pop.style.top = windowScrolled() + 30  + popupCount*10 + 'px'
 pop.style.left = 10 + popupCount*10 + 'px'
 //load diff
 var oldTable = document.createElement('table')
 pop.appendChild(oldTable)
 document.body.appendChild(pop) //have to append now, otherwise table is broken in Safari 3 
 loadDiff(clickedLink, oldTable, showPopup)
 if (window.dfHighlightOn) highlightDiffs()
}
 
 
function showPopup(clickedLink, diffTable){
 //clickedLink.style.backgroundColor = '#DDDDFF'
 var pop = diffTable.parentNode
 pop.appendChild(createCaption())
 pop.insertBefore(createCaption(), diffTable)
 pop.style.visibility = 'visible'
 return true
 
 function createCaption(){
  var dCaption = document.createElement('div')
  dCaption.className = 'df-caption'
  //on special pages
  if (wgNamespaceNumber == -1){
   dCaption.appendChild( btn(function(e){neighborDiff(e,clickedLink,  1)},
     '↓', 'Open next diff link on that page'))
   dCaption.appendChild( btn(function(e){neighborDiff(e,clickedLink, -1)},
     '↑', 'Open previous diff link on that page'))
  }
  //add page title
  var sp = document.createElement('span')
  var dTitle = diffTable.parentNode.diffTitle
  sp.innerHTML = '<b>'+outputLink(dTitle)+'</b>'
   + ' (' + outputLink(dTitle, '?action=history', 'h') + ')'
  dCaption.appendChild(sp)
  //add toolbar
  dCaption.insertBefore(createToolbar(pop), dCaption.firstChild)
  return dCaption
 }
}
 
 
function closePopup(div){
 div.style.display = 'none'
 //purge(div)
 div.parentNode.removeChild(div)
 popupCount--
 if (isIE && (popupCount==0)) hideAllSelectElements() //IE  select zIndex bug
}
 
function onKeyUp(e){
 e = e || window.event
 var lnk
 if (e.keyCode == 37) lnk = document.getElementById('differences-prevlink')
 else if (e.keyCode == 39) lnk = document.getElementById('differences-nextlink')
 if (!lnk) return
 if (!followNextLink(lnk)) document.location.href = lnk.href
}
 
 
 
function hideAllSelectElements(isHide){ //workaround for IE  <select> zIndex bug
 var sels = document.getElementsByTagName('select')
 for (var i=0; i<sels.length; i++)
   sels[i].style.visibility = isHide ?  'hidden' : 'visible'
}
 
function neighborDiff(e, lnk, dir){
 //close old popup
 e = e || window.event
 var el = e.target || e.srcElement
 closePopup (el.parentNode.parentNode)
 //try to find diff in neghbor TR (this happens inside expanded  section of enhanced RC/WL)
 if ((el=findParentWithTag(lnk,/TR/)) && (el=findNeighborBlock(el)) && (el=findDiffIn(el)))
   createPopup(el)
 //try to find diff in neghbor LI (on contrib page and simple RC)  or TABLE (on enhanced RC and WL)
 else if ((el=findParentWithTag(lnk,/LI|TABLE/)) && (el=findNeighborBlock(el)) && (el=findDiffIn(el)))
   createPopup(el)
 //functions
 function findParentWithTag(el, regexp){
   while ((el=el.parentNode) && !regexp.test(el.nodeName));
   return el
 }
 function findNeighborBlock(el){ //looks for next/prev block with the same tag
   var tag = el.nodeName
   do{ el = (dir == -1) ?  el.previousSibling : el.nextSibling } while (el && el.nodeName != tag)
   return el
 }
 function findDiffIn(block){
   var aa = block.getElementsByTagName('a')
   for (var i=0; i<aa.length; i++)
     if (/diff=/.test(aa[i].href)) return aa[i]
 }
}
 
 
 
 
 
 
// *** JS Diff Engine ***
function diffJSEngine(e){
 //create temporary table with original diff
 var dTable = getClickedTable(e)
 var curTitle = dTable.parentNode.diffTitle
 var tempTable = createTableFromHTML(requestedPages[dTable.parentNode.diffURL])
 //create "full comparison" button
 var btFull = document.createElement('input');  btFull.type = 'button'
 btFull.value = 'Perform full comparison'
 btFull.title = 'Compare full revisions, in case MediaWiki diff engine is wrong'
 btFull.onclick = diffJSFull
 
 //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
  oldVer = newVer = ''
  tds = tempTable.getElementsByTagName('td')
  var txt, isContent
  for (var i=1; i<tds.length; i++){
    txt = tds[i].innerHTML.replace(/<.+?>/g,'') + '\n'
    switch(tds[i].className){
    case 'diff-context':
      marker = '\x03' + txt + '\x04\n'
      oldVer += marker
      newVer += marker
      isContent = false
      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':
      isContent = true
      oldVer += txt
      break
    case 'diff-addedline':
      isContent = true
      newVer +=  txt
      break
    }
   }
  difDiv = document.createElement('div')
  difDiv.style.cssText = 'padding:2px'
  difDiv.innerHTML = '<br><br><h3>JS Engine diff</h3><hr style="height:5px" />'
  diffJSDisplay()
  difDiv.appendChild(document.createElement('hr'))
  difDiv.appendChild(btFull)
  dTable.parentNode.insertBefore(difDiv, dTable.nextSibling)
  scrollToElement(difDiv)
 }
 
 
 function diffJSFull(){
  btFull.parentNode.removeChild(btFull)
  //get versions Ids
  var ma, newId, oldId
  ma = tempTable.rows[0].cells[0].innerHTML.match(/oldid=(\d+)/)
  if (ma) oldId = ma[1]; else { difDiv.innerHTML += '<p class=error>Could not find oldid</p>'; return }
  ma = tempTable.rows[0].cells[1].innerHTML.match(/oldid=(\d+)/)
  if (ma) newId = ma[1]; else newId = ''
  //request versions
  difDiv.innerHTML += '<br><br><h3>Full revisions comparison</h3><hr style="height:5px" />'
  cursorWait(true)
  oldVer = newVer = null
  var url = mw.config.get('wgServer') + mw.config.get('wgScript') + '?action=raw&maxage=0&title=' + encodeURIComponent(curTitle)
  requestPage(url + '&oldid=' + oldId, function(txt) {
    oldVer = txt
    if (newVer) diffJSDisplay()
  })
  requestPage(url + '&oldid=' + newId, function(txt) {
	  newVer = txt
	  if (oldVer) diffJSDisplay()
  })
 }
 
 function diffJSDisplay(){
  var txt = WDiffString(oldVer, newVer)
  //txt = txt.replace(/\x03.*?\x04/g, '<br><br><hr><br><br>')
  txt = txt.replace(/\x03|\x04/g, '')
  if (!window.wikEdFullDiff ) txt = WDiffShortenOutput(txt)
  //txt = txt.replace(/¶/g,'<br>')
  txt = txt.replace(/&amp;/g,'&')
  //txt = txt.replace(/&lt;/g,'<').replace(/&gt;/g, '>')
  difDiv.innerHTML += txt
  cursorWait()
 }
 
}//diffJSEngine
 
 
 
 
 
 
// *** COMMON ***
 
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
}
 
function scrollToElement (el){
 var yy = el.offsetTop
 while (el = el.offsetParent) yy += el.offsetTop
 scrollTo(0, yy)
}
 
function getTitleFromURL(url){
 var tt = url.match(/title=([^&>"]+)/) //"
 if (!tt) return ''
 else return decodeURIComponent(tt[1]).replace(/_/g,' ')
}
 
function outputLink(page, params, name, tooltip){
 if (!name) name = page
 if (!tooltip) tooltip = name //.replace(/'/g,'`')
 params = params || ''
 page = page.replace(/&amp;/gi,'&')
 var k = page.indexOf('#')
 if (k != -1) page = page.substring(0,k) + '#' + guessSectionName(page.substring(k+1))
 return '<a href="'+ articlePath + encodeURI(page).replace(/\?/g,'%3F') + params
    +'" title="' + tooltip.replace(/"/g,'&quot;') + '">' + name + '</a>' //'
}
 
function guessTOCName(txt){ //make header into TOC item, will not work 100%
 txt = txt.replace(/^ */,'').replace(/ *$/,'') //trim spaces
 txt = txt.replace(/\[\[[^|]+\|([^\]]+)\]\]/g, '$1') //[[foo|bar]] -> bar
 txt = txt.replace(/\[\[([^\]]+)\]\]/g, '$1') //[[bar]] -> bar
 txt = txt.replace(/<.*?>/g, '').replace(/ /g,'_') //strip tags, spaces -> _
 return txt
}
 
function guessSectionName(txt){ //make header into URL anchor, will not work 100%
 //should behave like like Parser.php::guessSectionNameFromWikiText() and Sanitizer.php
 txt = guessTOCName(txt)
 //... skipping step "HTML entities are turned into their proper characters"
 txt = encodeURIComponent(txt)  //maybe encodeURI(p1.replace(/\?/g,'%3F').replace(/&/g,'%26'))
 txt = txt.replace('%3A', ':').replace(/%([0-9A-F][0-9A-F])/g, '.$1')
 return txt
}
 
function cursorWait(isWait){
 if (window.dfNoWaitCursor) return
 document.body.style.cursor = isWait ? 'wait' : ''
}
 
 
// *** CSS/JS ***
var dfHighlightSheet, dfImprovementSheet, dfPopupSheet
 
function  addDiffTableCSS(){
 if (dfImprovementSheet) return
 appendCSS('\
div.df-toolbar {float:right; margin-left:10px}\
div.df-toolbar span\
 {cursor:pointer; padding:0 3px 0 3px; margin:0 3px 0 3px; border:1px solid #EEEEEE}\
')
 dfImprovementSheet = addCSS('\
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%}\
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}\
table.diff td {cursor:help}\
table.diff td div, table.diff td.diff-multi {margin:0 8px 0 2px; cursor:default}'
+ (window.dfDiffTableCSS ? 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 addDiffPopupCSS(){
 if (dfPopupSheet) return
 if (document.URL.indexOf('&diff=') == -1) importStylesheetURI('/skins-1.5/common/diff.css')
 dfPopupSheet = addCSS('\
div.df-popup{position:absolute; margin-right:15px; border:1px solid #000033; z-index:50; \
 font-size:130%; background-color:white; visibility:hidden; min-width:90%}\
div.df-popup div.df-caption{float:none; background:#F0F0FF; font-size:120%;\
 border:1px outset gray; padding:2px}\
div.df-popup table.diff {width:97%; margin:0 1% 0 1% }\
a.df-clicked {background-color:#E5E5E5}\
a.df-clicked-last {background-color:#FFDDDD}\
')
}
// min-width was added for Safari
 
function highlightDiffs(e){
 if (!dfHighlightSheet)
   dfHighlightSheet = addCSS('.diffchange-inline, span.diffchange {border:1px solid red}\
 div.df-toolbar span.df-highlight-btn {border:1px inset #EEEEEE}')
 else dfHighlightSheet.disabled = !dfHighlightSheet.disabled
}
 
 
function addCSS(text){
 var s = appendCSS(text) //from wikibits
 return s.sheet || s //Safari compat
}
 
function importScriptAndRun(url, func) {
 var s = document.createElement('script')
 s.type = 'text/javascript'
 s.src = url + '&action=raw&ctype=text/javascript'
 if (isIE) s.onreadystatechange = function(){
     if (this.readyState == 'loaded' || this.readyState == 'complete') func()
   }
 else s.onload = func
 document.getElementsByTagName('head')[0].appendChild(s)
}
 
 
 
// *** AJAX ***
function requestPage(url, func){
 if (requestedPages[url]) {func(requestedPages[url]); return }
 var aj = sajax_init_object()
 aj.open('GET', url, true)
 aj.onreadystatechange=function() {
   if (aj.readyState != 4) return
   if (aj.status == 200) {
      requestedPages[url] = aj.responseText
      func(aj.responseText)
   }else func(null)
 }
 aj.send(null)
}
 
 
 
function loadDiff(clickedLink, diffTable, func){
 diffTable.style.opacity = '0.5'
 cursorWait(true)
 var url = clickedLink.href + '&action=render&diffonly=yes'
 requestPage(url, loadDiff2)
 function loadDiff2(html){
  diffTable = replaceTable(diffTable, html)
  //remember diff url and title
  diffTable.parentNode.diffURL = url
  var td = getElementsByClassName(diffTable, 'td', 'diff-ntitle')[0]
  diffTable.parentNode.diffTitle = td ? getTitleFromURL(td.getElementsByTagName('a')[1].href) : ''
  //insert permalink to this diff
  var dv = document.createElement('span')
  dv.innerHTML = '<a href="'+clickedLink.href+'" title="direct link to this diff" style="font-style:normal">[]</a>'
  dv.style.cssText = 'float:right; font-size:smaller'
  td = getElementsByClassName(diffTable, 'td', 'diff-otitle')[0]
  if (td) td.firstChild.insertBefore(dv, td.firstChild.firstChild)
  //td.lastChild.insertBefore(dv,td.lastChild.firstChild)
 
  //improve
  improveTable(diffTable)
  cursorWait()
  if (func) func(clickedLink, diffTable)
 }
}
 
function changeClass(el, oldC, newC){
 el.className = el.className.replace(oldC, '').replace(/ +/g,' ') + ' ' + newC
}
 
} //wrapper
 
 
 
$(diffScript.start)