User:Splarka/scapmap.js

/* Scap roadmap viewer, version [0.0.6a] Originally from: http://www.mediawiki.org/wiki/User:Splarka/scapmap.js

Notes:
 * Loads on, for example: http://www.mediawiki.org/wiki/Special:Code/MediaWiki
 * Click [overview] to generate map.
 * Text in the "path" input box is stripped from the path line in the summary.
 * Clicking a colored box takes you to that relevant line, and a backlink is created in the id column on focus.
 * Hovering over a colored box pops up a little info packet box.

var overviewTimeoutObj; var overviewPopupData = []; function reviewOverview { // check if we're on a page with a useful list of revisions var path = document.getElementById('path'); var table = getElementsByClassName(document,'table','TablePager'); if(!path || table.length == 0) return; addPortletLink('p-cactions','javascript:reviewOverviewDisplay;','Overview','ca-defrag','Show a graphical overview of this list.','1'); }

function reviewOverviewDisplay { //doublecheck that they're there and we can use them var table = getElementsByClassName(document,'table','TablePager'); var above = document.forms[0] //stick above the first form, no IDs on the forms currently! table = table[0]; var tr = table.getElementsByTagName('tr'); if(tr.length < 2 || document.getElementById('overviewmap')) return

appendCSS(   '#overviewmap {border:1px solid black;margin:.5em;padding:2px;position:relative;margin-right:16em;} '  + '#overviewmap #overviewpop {padding:3px;border:1px solid black;position:absolute;height:6.5em;width:16em;display:none;'  + ' background-color:#ffffdd;font-size:80%;line-height:100%;overflow:hidden;white-space:pre;} '  + '#overviewmap .box-overview {display:block;border:1px solid black;float:left;width:1.5em;height:1.5em;margin:1px;overflow:hidden;} '  + '#overviewmap .box-overview:target {border-style:dashed !important} #overviewmap .summary {clear:both;} '  + '.box-status-new {background: #ffffc0 !important;} .box-status-new:hover {background: #dfdfa0 !important;} '  + '.box-status-fixme {background: #ff9999 !important;} .box-status-fixme:hover {background: #df0000 !important;} '  + '.box-status-resolved {background: #b0eeb0 !important;} .box-status-resolved:hover {background: #80ff80 !important;} ' + '.box-status-reverted {background: #bbddee !important;} .box-status-reverted:hover {background: #66bbff !important;} ' + '.box-status-deferred {background: #dddddd !important;} .box-status-deferred:hover {background: #aaaaaa !important;} ' + '.box-live-live {border:1px solid #00ff00 !important;} ' + 'tr:target {font-weight:bold;} .overview-backlink {margin-left:1em;display:none;} tr:target .overview-backlink {1em;display:inline;}' ); var output = document.createElement('div');  output.setAttribute('id','overviewmap');  addHandler(document,'mousemove',mouseMoveBox);  var vpath = document.getElementById('path').value;  var totals = {};  for(var i=0;i<tr.length;i++) {    var live = (tr[i].className.indexOf('mw-codereview-notlive') != -1) ? 'notlive' : 'live'    var td = tr[i].getElementsByTagName('td');    if(!td) continue    overviewPopupData[i] = {};

var status = tdGetByClass(tr[i],'TablePager_col_cr_status',true); if(!status) continue overviewPopupData[i]['status'] = status; var rev = tdGetByClass(tr[i],'TablePager_col_cr_id',true); overviewPopupData[i]['rev'] = rev; overviewPopupData[i]['notes'] = tdGetByClass(tr[i],'TablePager_col_comments',true); var path = tdGetByClass(tr[i],'TablePager_col_cr_path',true); if(path && path.indexOf(vpath) == 0 && path != vpath && vpath != '') path = '\u2026' + path.substring(vpath.length) overviewPopupData[i]['path'] = path; overviewPopupData[i]['author'] = tdGetByClass(tr[i],'TablePager_col_cr_author',true); overviewPopupData[i]['live'] = live; if(!totals[status]) totals[status] = 0 if(!totals[live]) totals[live] = 0 totals[status]++; totals[live]++;

tr[i].setAttribute('id','TablePager-row-' + rev); var revtd = tdGetByClass(tr[i],'TablePager_col_cr_id'); if(revtd) { var top = document.createElement('a'); top.appendChild(document.createTextNode('^')); top.setAttribute('class','overview-backlink'); top.setAttribute('href','#box-' + i); revtd.appendChild(top); }

var box = document.createElement('a'); box.setAttribute('href','#TablePager-row-' + rev); box.setAttribute('class','box-overview box-status-' + status + ' box-live-' + live); box.setAttribute('id','box-' + i ); //box.appendChild(document.createTextNode(live)); output.appendChild(box); }

var summary = document.createElement('div'); summary.setAttribute('class','summary'); var sumtext = []; for(var i in totals) { if(typeof i != 'string' || typeof totals[i] != 'number') continue sumtext.push(i + ': ' + totals[i]); } sumtext.sort; summary.appendChild(document.createTextNode('Total revisions: ' + (tr.length-1) + '. [' + sumtext.join(', ') + ']')); output.appendChild(summary); var opop = document.createElement('div'); opop.setAttribute('id','overviewpop'); output.appendChild(opop); above.style.clear = 'both'; above.parentNode.insertBefore(output,above); } if(wgNamespaceNumber == -1 && wgCanonicalSpecialPageName == 'Code') addOnloadHook(reviewOverview)

function tdGetByClass(obj,classy,textonly) { var td = obj.getElementsByTagName('td'); if(!td) return for(var i=0;i<td.length;i++) { if(td[i].getAttribute('class') == classy) { if(textonly) { return getInnerText(td[i]); } else { return td[i]; }   }   }  return false; }

function mouseMoveBox(e) { //document.onmousemove sure is spooky! Lets be super extra paranoid and error check everything. try { if(overviewTimeoutObj != null) { clearTimeout(overviewTimeoutObj); overviewTimeoutObj = null; }   var e = window.event || e;    if(!e) return var target = e.target || e.srcElement; if(!target) return if(target.id == 'overviewpop') return var opop = document.getElementById('overviewpop'); if(!opop) return if(target.tagName == 'A' && target.className.indexOf('box-overview') == 0) { if(opop.getAttribute('for') == target.getAttribute('id')) return overviewTimeoutObj = setTimeout(function { showOverviewPopupBox(target,opop); }, 400); } else { opop.style.display = '' } } catch (e) { return; } }

function showOverviewPopupBox(target,opop) { if(!opop || !target) return var left = target.offsetLeft + target.offsetWidth -10; var top = target.offsetTop + target.offsetHeight -10; while(opop.firstChild) opop.removeChild(opop.firstChild) var id = parseInt(target.id.replace(/box\-/i,'')); var txt = 'Rev: r' + overviewPopupData[id]['rev'] + '\nStatus: ' + overviewPopupData[id]['status'] + '\nNumber of notes: ' + overviewPopupData[id]['notes'] + '\nPath: ' + overviewPopupData[id]['path'] + '\nAuthor: ' + overviewPopupData[id]['author'] + '\nLive: ' + overviewPopupData[id]['live']; opop.appendChild(document.createTextNode(txt)); opop.style.left = left + 'px'; opop.style.top = top + 'px'; opop.style.display = 'block'; opop.setAttribute('for','box-' + id); }