Jump to content

User:Cacycle/wikEdDiff.js

From Wikipedia, the free encyclopedia
This is an old revision of this page, as edited by Cacycle (talk | contribs) at 02:41, 15 April 2007 (0.9.1). The present address (URL) is a permanent link to this revision, which may differ significantly from the current revision.
(diff) ← Previous revision | Latest revision (diff) | Newer revision → (diff)
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.
/* {{en:User:Cacycle/wikEd_template}} <pre clear="all"><nowiki> */

// version info
var wikEdDiffProgramVersion = '0.9.1';
var wikEdDiffProgramDate    = 'April 14, 2007';

/*

== wikEdDiff ==

wikEdDiff provides enhanced diff view for comparing different versions of MediaWiki articles

Features:
* Optimized for MediaWiki source texts
* Additions and deletions are highlighted by color in a single article text
* Block moves are detected and indicated by color
* Unchanged parts are omitted from the output

wikEdDiff uses the diff.js tool [[en:User:Cacycle/diff]] and is also an integrated part of wikEd,
the full-featured JavaScript in-browser editor (http://en.wikipedia.org/wiki/User:Cacycle/wikEd)

Homepage: http://en.wikipedia.org/wiki/User:Cacycle/wikEdDiff
Author:   Cacycle (http://en.wikipedia.org/wiki/User:Cacycle)
License:  This code has been released into the public domain

== Installation ==

* Copy the following short block of code to [[User:YOURUSERNAME/monobook.js]]
* Press SHIFT-Reload to update to the newest version
* PLEASE DO NOT COPY THE WHOLE PROGRAM
* See http://en.wikipedia.org/wiki/User:Cacycle/wikEdDiff for detailed instructions
* Users of wikEd do not have to install wikEdDiff

// ---- START INSTALLATION CODE ----

// install [[User:Cacycle/wikEdDiff]] enhanced diff view using ajax
document.write('<script type="text/javascript" src="'
+ 'http://en.wikipedia.org/w/index.php?title=User:Cacycle/wikEdDiff.js'
+ '&action=raw&ctype=text/javascript&dontcountme=s"></script>');

// ---- END INSTALLATION CODE ----

*/


//
// user configurable variables
//

// wikEdDiff script URL, also defined in wikEd.js
var wikEdDiffScriptSrc = wikEdDiffScriptSrc || 'http://en.wikipedia.org/w/index.php?title=User:Cacycle/diff.js&action=raw&ctype=text/javascript&dontcountme=s';

// allow ajax requests from local copy for testing, also defined in wikEd.js
var wikEdAllowLocalAjax = wikEdAllowLocalAjax || false;

// wikEdDiff css rules
var wikEdDiffCSS = wikEdDiffCSS || [];

WikEdDiffInitObject(wikEdDiffCSS, {
	'.wikEdDiffWrapper':        'margin: 0 0 1em 0;',
	'.wikEdDiffButtonWrapper':  'text-align: center;',
	'.wikEdDiffButton':         'padding: 0; margin: 0.2em 0 0.33em 0;',
	'.wikEdDiffDiv':            'background: #faf8f6; padding: 0.5em; border: 1px solid; border-color: #808080;'
});

// path to local images for testing, also defined in wikEd.js
var wikEdImagePathLocal = wikEdImagePathLocal || 'file:///D:/wikEd/images/';

// path to images, also defined in wikEd.js
var wikEdImagePath = wikEdImagePath || '/media/wikipedia/commons/';

// image filenames, also defined in wikEd.js
var wikEdImage = wikEdImage || [];

WikEdDiffInitImage(wikEdImage, {
	'wikEdDiff': '0/00/WikEdDiff.png'
});

// user readable texts, copy changes to http://en.wikipedia.org/wiki/User:Cacycle/wikEd_international_en.js
var wikEdText = wikEdText || [];

WikEdDiffInitObject(wikEdText, {
	'wikEdDiffButtonImg alt':      'wikEdDiff',
	'wikEdDiffButton title':       'Show enhanced diff view',
	'wikEdDiffLoading':            '...'
});

//
// end of user configurable variables
//


// global dom elements
var wikEdDiffWrapper;
var wikEdDiffButtonWrapper;
var wikEdDiffDiv;
var wikEdDiffButton;

// hash of loaded scripts, also defined in wikEd.js
var wikEdExternalScripts = wikEdExternalScripts || [];

// diff table element, also defined in wikEd.js
var wikEdDiffTable = wikEdDiffTable || [];

// call the setup routine
if (typeof(doneOnloadHook) == 'boolean') {
	if (doneOnloadHook == true) {
		WikEdDiffSetup();
	}
	else {
		if (typeof(addOnloadHook) == 'function') {
			addOnloadHook(WikEdDiffSetup);
		}
	}
}
else {
	window.onload = WikEdDiffSetup;
}


//
// WikEdDiffSetup: create wikEdDiff elements
//

function WikEdDiffSetup() {

// run only once
	if (wikEdDiffWrapper != null) {
		return;
	}

// detect diff table
	var table = document.getElementsByTagName('TABLE');
	for (var i = 0; i < table.length; i ++) {
		if (table[i].className == 'diff') {
			wikEdDiffTable = table[i];
		}
	}

// check if this is a diff page
	if (wikEdDiffTable == null) {
		return;
	}

// detect already loaded external scripts
	if (wikEdExternalScripts == null) {
		var pageScripts = document.getElementsByTagName('script');
		for (var i = 0; i < pageScripts.length; i ++) {
			var nameMatch = pageScripts[i].src.match(/\/([^\/]*?)($|\?)/);
			if (nameMatch != null) {
				var scriptName = nameMatch[1];
				if (scriptName != '') {
					wikEdExternalScripts[scriptName] = true;
				}
			}
		}
	}

// load the external diff script
	if (wikEdExternalScripts['diff.js'] == null) {
		var head =	document.getElementsByTagName('head')[0];
		var script = document.createElement('script');
		script.type = 'text/javascript';
		script.src  = wikEdDiffScriptSrc;
		head.appendChild(script);
		wikEdExternalScripts['diff.js'] = true;
	}

// add stylesheet definitions (slow method for IE compatibility)
	var diffStyle = new WikEdDiffStyleSheet();
	var rules = '';
	for (var ruleName in wikEdDiffCSS) {
		var ruleStyle = wikEdDiffCSS[ruleName];
		ruleStyle = ruleStyle.replace(/\{wikEdGrip\}/g, wikEdImage['grip']);
		diffStyle.addRule(ruleName, ruleStyle);
	}

// create wikEdDiff wrapper
	wikEdDiffWrapper = document.createElement('div');
	wikEdDiffWrapper.id = 'wikEdDiffWrapper';
	wikEdDiffWrapper.className = 'wikEdDiffWrapper';

// create wikEdDiff button wrapper
	wikEdDiffButtonWrapper = document.createElement('div');
	wikEdDiffButtonWrapper.id = 'wikEdDiffButtonWrapper';
	wikEdDiffButtonWrapper.className = 'wikEdDiffButtonWrapper';
	wikEdDiffWrapper.appendChild(wikEdDiffButtonWrapper);

// create wikEdDiff button
	wikEdDiffButton = document.createElement('button');
	wikEdDiffButton.id = 'wikEdDiffButton';
	wikEdDiffButton.title = wikEdText['wikEdDiffButton title'];
	wikEdDiffButton.className = 'wikEdDiffButton';
	wikEdDiffButtonWrapper.appendChild(wikEdDiffButton);

// add button image
	var diffImg = document.createElement('img');
	diffImg.id = 'wikEdDiffButtonImg';
	diffImg.src = wikEdImage['wikEdDiff'];
	diffImg.title = wikEdText['wikEdDiffButton title'];
	diffImg.alt = wikEdText['wikEdDiffButtonImg alt'];
	wikEdDiffButton.appendChild(diffImg);

	wikEdDiffDiv = document.createElement('div');
	wikEdDiffDiv.id = 'wikEdDiffDiv';
	wikEdDiffDiv.className = 'wikEdDiffDiv';
	wikEdDiffDiv.style.display = 'none';

// add wrapper after diff table
	wikEdDiffWrapper.appendChild(wikEdDiffDiv);
	if (wikEdDiffTable.nextSibling != null) {
		wikEdDiffTable.parentNode.insertBefore(wikEdDiffWrapper, wikEdDiffTable.nextSibling);
	}
	else {
		wikEdDiffTable.parentNode.appendChild(wikEdDiffWrapper);
	}

// add event listener to button
	wikEdDiffButton.onclick = WikEdDiff;

// run WikEdDiff if enabled in wikEd
	if (typeof(wikEdDiff) == 'boolean') {
		if (wikEdDiff == true) {
			WikEdDiff();
			window.scroll(0, WikEdDiffGetOffsetTop(wikEdDiffDiv));
		}
	}

	return;
}


//
// WikEdDiff: fetch the old versions using ajax to display a diff
//

function WikEdDiff() {

// check if set tup
	if (wikEdDiffDiv == null) {
		return;
	}

// display diff
	wikEdDiffDiv.style.display = 'block';

// fetch only once
	if (wikEdDiffDiv.innerHTML.length > 0) {
		return;
	}

// check if this is a diff page
	if (wikEdDiffTable == null) {
		return;
	}

// display div
	if (wikEdDiffDiv.innerHTML.length == 0) {
		wikEdDiffDiv.innerHTML = wikEdText['wikEdDiffLoading'];
	}

// generate request url from MediaWiki variables or from location url
	var url;
	if (typeof(wgScriptPath) == 'string') {
		url = wgScriptPath + '/index.php';
	}
	else {
		url = window.location.protocol + '//' + window.location.hostname + '/' + window.location.pathname;
	}
	var article;
	if (typeof(wgTitle) == 'string') {
		article = wgTitle;
	}
	else {
		var articleMatch = window.location.search.match(/(\?|&)title=([^&#]+)/);
 		article = articleMatch[2];
 	}
	url += '?title=' + encodeURIComponent(article) + '&action=raw&dontcountme=s&maxage=0';

// get diff table and version link cells
	var tdArray = document.getElementsByTagName('TD');
	var tdOld;
	var tdNew;
	for (var i = 0; i < tdArray.length; i ++) {
		if (tdArray[i].className == 'diff-otitle') {
			tdOld = tdArray[i];
		}
		else if (tdArray[i].className == 'diff-ntitle') {
			tdNew = tdArray[i];
			break;
		}
	}
	if ( (tdOld == null) || (tdNew == null) ) {
		return;
	}

	var oldVersion = null;
	var newVersion = null;

	var oldUrl;
	var newUrl;

// preview pages use latest article version and textarea
	if (/(\?|&)action=submit\b/.test(window.location.search) == true) {
		var textarea = document.getElementsByName('wpTextbox1')[0];
		if (textarea == null) {
			return;
		}
		newVersion = textarea.value;
		if (typeof(wgCurRevisionId) == 'string') {
			oldUrl = url + '&oldid=' + wgCurRevisionId;
		}
		else {
			oldUrl = url;
		}
	}

// diff pages use two different old versions
	else {

// get revision id numbers from links in table cells
		var versionMatchOld = tdOld.innerHTML.match(/(\?|&amp;)oldid=(\d+)/);
		var versionMatchNew = tdNew.innerHTML.match(/(\?|&amp;)oldid=(\d+)/);
		if ( (versionMatchOld == null) && (versionMatchNew == null) ) {
			return;
		}
		oldUrl = url + '&oldid=' + versionMatchOld[2];
		newUrl = url + '&oldid=' + versionMatchNew[2];
	}

// allow ajax request from local copy for testing
	if (wikEdAllowLocalAjax == true) {
		if (typeof(netscape) == 'object') {
			netscape.security.PrivilegeManager.enablePrivilege('UniversalBrowserRead');
		}
	}

// get the old version using ajax
	var ajaxOld = WikEdDiffAjaxInitObject();
	if (ajaxOld == null) {
		return;
	}
	ajaxOld.open('GET', oldUrl, true);
	ajaxOld.send(null);

// ajax response handler for old version
	ajaxOld.onreadystatechange = function() {
		if (ajaxOld.readyState != 4) {
			return;
		}
		oldVersion = ajaxOld.responseText;
		if (newVersion != null) {

			WikEdDiffResponse(oldVersion, newVersion);
		}
		return;
	}

// get the new version using ajax
	if (newUrl != null) {
		var ajaxNew = WikEdDiffAjaxInitObject();
		if (ajaxNew == null) {
			return;
		}
		ajaxNew.open('GET', newUrl, true);
		ajaxNew.send(null);

// ajax response handler for new version
		ajaxNew.onreadystatechange = function() {
			if (ajaxNew.readyState != 4) {
				return;
			}
			newVersion = ajaxNew.responseText;
			if (oldVersion != null) {
				WikEdDiffResponse(oldVersion, newVersion);
			}
			return;
		}
	}
}


//
// WikEdDiffResponse: calculate and display the diff between two versions
//

function WikEdDiffResponse(oldVersion, newVersion) {

// call external diff program
	var diffText = WDiffString(oldVersion, newVersion);
	if (wikEdFullDiff != true) {
		diffText = WDiffShortenOutput(diffText);
	}
	wikEdDiffDiv.innerHTML = diffText;
	wikEdDiffDiv.style.display = 'block';

	return;
}


//
// WikEdDiffInitObject: initialize object, keep pre-defined values
//

function WikEdDiffInitObject(array, preset) {

	for (var key in preset) {
		if (array[key] == null) {
			array[key] = preset[key];
		}
	}
	return;
}


//
// WikEdDiffInitImage: initialize images, keep pre-defined values
//

function WikEdDiffInitImage(array, preset) {

	for (var key in preset) {
		if (array[key] == null) {

// remove MediaWiki path prefixes and add local path
			if (wikEdUseLocalImages == true) {
				array[key] = wikEdImagePathLocal + preset[key].replace(/^[0-9a-f]+\/[0-9a-f]+\//, '');
			}

// add path
			else {
				array[key] = wikEdImagePath + preset[key];
			}
		}
	}
	return;
}


//
// WikEdDiffStyleSheet: create a new style sheet object, also defined in wikEdDiff.js
//

function WikEdDiffStyleSheet(documentObject) {

	this.styleElement = null;
	if (documentObject == null) {
		documentObject = document;
	}

// IE
	if (documentObject.createStyleSheet) {
		this.styleElement = documentObject.createStyleSheet();
	}

// standards compliant browsers
	else {
		this.styleElement = documentObject.createElement('style');
		this.styleElement.from = 'text/css';
		var insert = documentObject.getElementsByTagName('head')[0];
		if (insert != null) {
			insert.appendChild(this.styleElement);
		}
	}

// addRule: add one rule at the time using DOM method, very slow

// IE
	this.addRule = function(selector, declaration) {
		if (this.styleElement.addRule) {
			this.styleElement.addRule(selector, declaration);
		}

// standards compliant browsers
		else {
			if (this.styleElement.sheet != null) {
				if (this.styleElement.sheet.insertRule != null) {
					this.styleElement.sheet.insertRule(selector + ' { ' + declaration + ' } ', 0);
				}
			}
		}
	};

// addRules: add all rules at once, much faster
	this.addRules = function(rules) {
		this.styleElement.innerHTML = rules;
		return;
	}
}


//
// WikEdDiffAjaxInitObject: cross browser wrapper for creating new XMLHttpRequest object
//

function WikEdDiffAjaxInitObject() {

	var ajax;

// current browsers
	try {
		ajax = new XMLHttpRequest();
	}
	catch (e) {

// IE 6
		try {
			ajax = new ActiveXObject('Microsoft.XMLHTTP');
		}
		catch (e) {

// IE 5.5
			try {
				ajax = new ActiveXObject('Msxml2.XMLHTTP');
			}
			catch (e) { }
		}
	}
	return(ajax);
}


//
// WikEdDiffGetOffsetTop: get element offset relative to window top
//

function WikEdDiffGetOffsetTop(element) {
	var offset = 0;
	do {
		offset += element.offsetTop;
	} while ( (element = element.offsetParent) != null );
	return(offset);
}


/* </nowiki></pre> */