Note: After saving, you have to bypass your browser's cache to see the changes. Google Chrome, Firefox, Microsoft Edge and Safari: Hold down the ⇧ Shift key and click the Reload toolbar button. For details and instructions about other browsers, see Wikipedia:Bypass your cache.
// vim: ts=4 sw=4 et ai
( function () {
var wikitextCache = {};
function getWikitext( pageName, revision ) {
if( wikitextCache[ revision ] ) {
return $.when( wikitextCache[ revision ] );
}
return $.getJSON(
mw.config.get( 'wgScriptPath' ) + '/api.php',
{
format: "json",
action: "query",
prop: "revisions",
rvprop: "content",
rvslots: "main",
rvlimit: 1,
rvstartid: revision,
titles: pageName,
formatversion: 2,
}
).then( function ( data ) {
var revObj = data.query.pages[ Object.keys( data.query.pages )[0] ].revisions[0];
var wikitext = revObj.slots.main.content;
wikitextCache[ revision ] = wikitext;
return wikitext;
} );
}
function lineNumFromLineNumCell( cell ) {
return parseInt( cell.textContent.replace( /,/g, "" ).match( /Line (\d+):/ )[1] );
}
function findLineNumberRowIdx( diffTable, direction, rowIdx ) {
var rows = Array.prototype.slice.call( diffTable.rows );
var searchRows;
if( direction === "next" ) {
searchRows = rows.slice( rowIdx );
} else {
searchRows = rows.slice( 0, rowIdx );
searchRows.reverse();
}
return searchRows.find( function ( row ) {
return row.cells[0].className === "diff-lineno";
} );
}
// I'm probably gonna keep finding off-by-one errors in this code until the heat death of the universe
function showMore( revision, pageName, direction, rowWithButton, numRowsToShow, targetRow, diffTable ) {
var rows = Array.prototype.slice.call( diffTable.rows );
var buttonRowIdx = rows.indexOf( rowWithButton );
if( direction === "next" ) {
targetRow = findLineNumberRowIdx( diffTable, "previous", buttonRowIdx );
}
var currLineNum = lineNumFromLineNumCell( targetRow.cells[1] );
var targetRowIdx = Array.prototype.indexOf.call( diffTable.rows, targetRow );
var currRowIdx = direction === "next" ? buttonRowIdx - 1 : targetRowIdx + 1;
if( direction === "next" ) {
currLineNum += buttonRowIdx - rows.indexOf( targetRow ) - 2;
}
return getWikitext( pageName, revision ).then( function ( wikitext ) {
var lines = wikitext.split( "\n" );
var startLineIdx, endLineIdx;
switch( direction ) {
case "next":
startLineIdx = currLineNum + 1;
endLineIdx = currLineNum + numRowsToShow + 1;
var nextLineNumberRow = findLineNumberRowIdx( diffTable, "next", buttonRowIdx );
if( nextLineNumberRow ) {
var limitLineNum = lineNumFromLineNumCell( nextLineNumberRow.cells[1] ) - 1;
endLineIdx = Math.min( endLineIdx, limitLineNum );
}
break;
case "previous":
startLineIdx = currLineNum - numRowsToShow - 1;
endLineIdx = currLineNum - 1;
var prevLineNumberRow = findLineNumberRowIdx( diffTable, "previous", buttonRowIdx );
if( prevLineNumberRow ) {
var prevLineNumberRowIdx = rows.indexOf( prevLineNumberRow );
var limitLineNum = lineNumFromLineNumCell( prevLineNumberRow.cells[1] ) + ( buttonRowIdx - prevLineNumberRowIdx ) - 2;
startLineIdx = Math.max( startLineIdx, limitLineNum );
}
break;
}
startLineIdx = Math.max( 0, startLineIdx );
endLineIdx = Math.min( lines.length - 1, endLineIdx );
if( endLineIdx - startLineIdx === 0 ) {
return true; // no more work can be done
}
var actualNumLines = endLineIdx - startLineIdx;
var linesToShow = lines.slice( startLineIdx, endLineIdx );
if( direction === "previous" ) {
linesToShow.reverse();
}
var insertionRow = currRowIdx + +( direction === "next" );
for( var lineCounter = 0; lineCounter < actualNumLines; lineCounter++ ) {
var currLine = "<div>" + linesToShow[ lineCounter ].replace( /</g, "<" ) + "</div>";
var newRow = diffTable.insertRow( insertionRow );
newRow.insertCell( 0 ).appendChild( document.createTextNode( "." ) );
var newCell = newRow.insertCell( 1 );
newCell.className = "diff-context";
newCell.innerHTML = currLine;
newRow.insertCell( 2 ).appendChild( document.createTextNode( "." ) );
var newCell2 = newRow.insertCell( 3 );
newCell2.className = "diff-context";
newCell2.innerHTML = currLine;
}
if( direction === "previous" ) {
targetRow.cells[0].textContent = "Line " + ( currLineNum - actualNumLines ) + ":";
targetRow.cells[1].textContent = "Line " + ( currLineNum - actualNumLines ) + ":";
}
mw.hook( "diff-update" ).fire( diffTable );
if( actualNumLines < numRowsToShow ) {
return true; // we're done
}
return false;
} );
}
function makeDropdown() {
var sel = document.createElement( "select" );
function add( num ) {
var opt = document.createElement( "option" );
opt.value = num;
opt.textContent = num;
sel.appendChild( opt );
}
add( 1 );
add( 10 );
add( 50 );
add( 100 );
//add( "all" );
return sel;
}
function addLinks( diffTable ) {
if( !diffTable.querySelector ) {
// Assume it's a jquery object
diffTable = diffTable.get( 0 );
}
if( diffTable.getElementsByClassName( "diff-context-container" ).length > 0 ) {
// We already ran on this diff
return;
}
function makeRow( index, direction, targetRow ) {
var newRow = diffTable.insertRow( index );
newRow.className = "context " + direction;
var newCell = newRow.insertCell( 0 );
newCell.setAttribute( "colspan", "4" );
var container = document.createElement( "div" );
container.className = "diff-context-container";
container.appendChild( document.createTextNode( "Show " + direction + " " ) );
var dropdown = makeDropdown();
container.appendChild( dropdown );
container.appendChild( document.createTextNode( " lines: " ) );
var go = document.createElement( "button" );
go.textContent = "Go";
var revision = mw.config.get( "wgDiffNewId" );
var pageName = mw.config.get( "wgPageName" );
if( diffTable.parentNode && diffTable.parentNode.dataset.mwRevid ) {
// User contribs page or normal watchlist or history page
revision = diffTable.parentNode.dataset.mwRevid;
if( pageName.indexOf( "Special:Contributions" ) === 0 ) {
pageName = diffTable.parentNode.querySelector( "a.mw-contributions-title" ).textContent;
}
} else if( diffTable.parentNode && diffTable.parentNode.className === "mw-enhanced-rc-nested" ) {
// Enhanced ("show all changes") watchlist, when multiple revisions are shown for one page
revision = diffTable.parentNode.parentNode.dataset.mwRevid;
pageName = diffTable.parentNode.dataset.targetPage;
} else if( diffTable.id.substring( diffTable.id.length - 7 ) === "display" && diffTable.previousElementSibling.dataset.mwRevid ) {
// Enhanced watchlist, only one revision shown for a page
revision = diffTable.previousElementSibling.dataset.mwRevid;
pageName = diffTable.previousElementSibling.getElementsByClassName( "mw-changeslist-line-inner" )[0].dataset.targetPage;
}
go.addEventListener( "click", function ( evt ) {
var numRowsToShow = parseInt( dropdown.value );
showMore( revision, pageName, direction, newRow, numRowsToShow, targetRow, diffTable ).then( function ( done ) {
if( done ) {
this.disabled = true;
}
}.bind( this ) );
evt.preventDefault();
}, true );
container.appendChild( go );
newCell.appendChild( container );
}
var firstTime = true;
for( var rowIdx = 0, rowCount = diffTable.rows.length; rowIdx < rowCount; rowIdx++ ) {
var row = diffTable.rows[rowIdx];
if( row.cells[0].className !== "diff-lineno" ) continue;
if( !firstTime ) {
makeRow( rowIdx, "next", row );
rowIdx++;
} else {
firstTime = false;
}
makeRow( rowIdx, "previous", row );
rowIdx++;
}
var lineNumCells = diffTable.querySelectorAll( "td.diff-lineno" );
if( lineNumCells.length ) {
var lastLineNumRow = Array.prototype.slice.call( lineNumCells, -1 )[0].parentNode;
makeRow( -1, "next", lastLineNumRow );
}
}
$( function () {
var diffTable = document.querySelector( "table.diff" );
if( mw.config.get( "wgDiffNewId" ) && diffTable && diffTable.rows.length > 2 ) {
mw.loader.addStyleTag( "tr.context td { text-align: center; }" );
mw.loader.addStyleTag( "tr.context td div.diff-context-container { display: inline-block; border: thin solid #ddd; padding: 0.1em 0.5em; }" );
addLinks( diffTable );
}
mw.hook( "wikipage.diff" ).add( addLinks );
mw.hook( "new-diff-table" ).add( addLinks );
} );
} )();