Benutzer:ExURLBot/Diffbaustelle.js

aus Wikipedia, der freien Enzyklopädie
Zur Navigation springen Zur Suche springen

Hinweis: Leere nach dem Veröffentlichen den Browser-Cache, um die Änderungen sehen zu können.

  • Firefox/Safari: Umschalttaste drücken und gleichzeitig Aktualisieren anklicken oder entweder Strg+F5 oder Strg+R (⌘+R auf dem Mac) drücken
  • Google Chrome: Umschalttaste+Strg+R (⌘+Umschalttaste+R auf dem Mac) drücken
  • Edge: Strg+F5 drücken oder Strg drücken und gleichzeitig Aktualisieren anklicken
//Copy für Testzwecke von Benutzer:Schnark/js/diff.js <nowiki>

/*global mediaWiki, ve*/
(function ($, mw, libs) {
"use strict";
var l10n = {
	en: {
		'schnark-diff-button': 'Δ',
		'schnark-diff-button-tooltip': 'improved diff',
		'schnark-diff-tab-normal': 'D',
		'schnark-diff-tab-normal-tooltip': 'normal diff',
		'schnark-diff-tab-improved': 'Δ',
		'schnark-diff-tab-improved-tooltip': 'improved diff',
		'schnark-diff-tab-config': '⌨',
		'schnark-diff-tab-config-tooltip': 'settings',
		'schnark-diff-config-moves': 'Show moved blocks: ',
		'schnark-diff-config-moves-normal': 'normal',
		'schnark-diff-config-moves-nested': 'nested',
		'schnark-diff-config-moves-none': 'no',
		'schnark-diff-config-moves-simple': 'simple',
		'schnark-diff-config-char-diff': 'Number of rounds for diff on character level: ',
		'schnark-diff-config-word-diff-qual': 'Quality of diffs on character level (0–100): ',
		'schnark-diff-config-recursion': 'Number of recursions: ',
		'schnark-diff-config-too-short': 'Length of a short word: ',
		'schnark-diff-config-small-region': 'Length of a small region: ',
		'schnark-diff-config-min-moved-length': 'Minimal length for a moved block: ',
		'schnark-diff-config-color-scheme': 'Color scheme: ',
		'schnark-diff-config-color-scheme-classic': 'Classic (red/green)',
		'schnark-diff-config-color-scheme-modern': 'Modern (yellow/blue)',
		'schnark-diff-config-color-scheme-wiked': 'wikEd (yellow/blue, moves in gray)',
		'schnark-diff-config-save': 'Save settings',
		'schnark-diff-config-reset': 'Use defaults',
		'schnark-diff-version': 'Version: $1/$2'
	},
	'en-gb': {
		'schnark-diff-config-color-scheme': 'Colour scheme: ',
		'schnark-diff-config-color-scheme-wiked': 'wikEd (yellow/blue, moves in grey)'
	},
	de: {
		'schnark-diff-button-tooltip': 'Verbesserter Diff',
		'schnark-diff-tab-normal-tooltip': 'Normaler Diff',
		'schnark-diff-tab-improved-tooltip': 'Verbesserter Diff',
		'schnark-diff-tab-config-tooltip': 'Einstellungen',
		'schnark-diff-config-moves': 'Anzeige von Verschiebungen: ',
		'schnark-diff-config-moves-nested': 'verschachtelt',
		'schnark-diff-config-moves-none': 'gar nicht',
		'schnark-diff-config-moves-simple': 'einfach',
		'schnark-diff-config-char-diff': 'Anzahl der Durchgänge für Diff auf Zeichenebene: ',
		'schnark-diff-config-word-diff-qual': 'Qualität des Diffs auf Zeichenebene (0–100): ',
		'schnark-diff-config-recursion': 'Anzahl der Rekursionen: ',
		'schnark-diff-config-too-short': 'Länge eines kurzen Worts: ',
		'schnark-diff-config-small-region': 'Größe eines kleinen Bereichs: ',
		'schnark-diff-config-min-moved-length': 'Minimale Läge eines verschobenen Blocks: ',
		'schnark-diff-config-color-scheme': 'Farbschema: ',
		'schnark-diff-config-color-scheme-classic': 'Klassisch (rot/grün)',
		'schnark-diff-config-color-scheme-modern': 'Modern (gelb/blau)',
		'schnark-diff-config-color-scheme-wiked': 'wikEd (gelb/blau, Verschiebungen grau)',
		'schnark-diff-config-save': 'Einstellungen speichern',
		'schnark-diff-config-reset': 'Standardwerte verwenden'
	},
	'de-ch': {
		'schnark-diff-config-small-region': 'Grösse eines kleinen Bereichs: '
	}
}, config = {
	version: 5.1,
	css: '.schnark-diff-button {padding: 0.2em 0.5em; margin: -1px 0.4em; display: inline-block;' +
			'border: 1px solid #aaa; background-color:#fbfbfb; cursor: pointer;}' +
		'.schnark-diff-buttons-top .schnark-diff-button {border-bottom-color: #a7d7f9;}' +
		'.schnark-diff-buttons-bottom .schnark-diff-button {border-top-color: #a7d7f9;}' +
		'.schnark-diff-button-selected {border-color: #a7d7f9; background-color: #fff;}' +
		'.schnark-diff-buttons-top .schnark-diff-button-selected {border-bottom-color: #fff;}' +
		'.schnark-diff-buttons-bottom .schnark-diff-button-selected {border-top-color: #fff;}' +
		'.schnark-diff-div {padding: 0.5em; border: 1px solid #a7d7f9; background-color: #fff;}' +
		'.schnark-diff-container {margin-top: 1em; margin-bottom: 1em;}',
	cssSkin: {
		monobook: '.schnark-diff-buttons-top .schnark-diff-button {border-bottom-color: #aaa;}' +
			'.schnark-diff-buttons-bottom .schnark-diff-button {border-top-color: #aaa;}' +
			'.schnark-diff-button-selected {border-color: #fabd23;}' +
			'.schnark-diff-buttons-top .schnark-diff-button-selected {border-bottom-color: #fff;}' +
			'.schnark-diff-buttons-bottom .schnark-diff-button-selected {border-top-color: #fff;}' +
			'.schnark-diff-div {border-color: #aaa;}'
	},
	alwaysOnEdit: true,
	instances: 0
}, colorSchemes = {
	classic: {},
	modern: {
		ins: 'text-decoration: none; color: black; background-color: #a3d3ff;',
		del: 'text-decoration: none; color: black; background-color: #ffe49c;',
		movedIns: 'text-decoration: none; color: black; background-color: #e1ebf5;',
		movedDel: 'text-decoration: none; color: black; background-color: #f2ead7;'
	},
	wiked: {
		ins: 'text-decoration: none; color: black; background-color: #a3d3ff;',
		del: 'text-decoration: none; color: black; background-color: #ffe49c;',
		movedIns: 'text-decoration: none; color: black; background-color: #e1ebf5;',
		movedDel: 'text-decoration: none; color: black; background-color: #f2ead7;',
		movedFrom: 'color: #000; text-decoration: none; font-weight: bold; background-color: #ffe49c;',
		movedTo: '#e8e8e8',
		movedHover: 'color: #fff !important; background-color: #777 !important;',
		blocks: [],
		additional: '.enhanced-diff-moved-hover .enhanced-diff-equal {color: #fff; background-color: #777;}'
	}
}, currentColorScheme, hasOwn = Object.prototype.hasOwnProperty;

function initL10N (l10n) {
	var i, chain = mw.language.getFallbackLanguageChain();
	for (i = chain.length - 1; i >= 0; i--) {
		if (chain[i] in l10n) {
			mw.messages.set(l10n[chain[i]]);
		}
	}
}

function loadDiffJs (callback) {
	var load = true;
	function callback2 (/*schnarkDiff*/) {
		load = false;
		mw.hook('userjs.load-script.diff-core').remove(callback2);
		libs.schnarkDiff.config.set(
			$('body').is('.rtl') ? {
				movedLeft: '\u25b6',
				movedRight: '\u25c0'
			} : {
				movedLeft: '\u25c0',
				movedRight: '\u25b6'
			}
		);
		callback(/*schnarkDiff*/);
	}
	mw.hook('userjs.load-script.diff-core').add(callback2);
	if (load) {
		//</nowiki>[[Benutzer:Schnark/js/diff.js/core.js]]<nowiki>
		mw.loader.load('//de.wikipedia.org/w/index.php?title=Benutzer:Schnark/js/diff.js/core.js' +
			'&action=raw&ctype=text/javascript');
	}
}

function formatVersion (v) {
	if (typeof v === 'number' && Math.floor(v) === v) {
		return String(v) + '.0';
	} else {
		return String(v);
	}
}

function enableColorScheme (n) {
	var backup;
	if (n === currentColorScheme) {
		return;
	}
	if (currentColorScheme) {
		colorSchemes[currentColorScheme].disabled = true;
	}
	currentColorScheme = n;
	if ($.isPlainObject(colorSchemes[n])) {
		backup = libs.schnarkDiff.style.get();
		libs.schnarkDiff.style.set(colorSchemes[n]);
		colorSchemes[n] = mw.util.addCSS(libs.schnarkDiff.getCSS());
		libs.schnarkDiff.style.set(backup);
	} else {
		colorSchemes[n].disabled = false;
	}
}

function getRevisionId ($a) {
	var id = null;
	$a.each(function () {
		if (id === null) {
			id = mw.util.getParamValue('oldid', $(this).attr('href'));
		}
	});
	return id;
}

function getRevision (id, section, callback) {
	if (callback === undefined) {
		callback = section;
		section = null;
	}
	if (!id) {
		callback('');
		return;
	}
	var data = {action: 'query', prop: 'revisions', revids: id, rvprop: 'content', indexpageids: '', format: 'json'};
	if (section !== null) {
		data.rvsection = section;
	}
	$.getJSON(mw.util.wikiScript('api'), data).always(function (json) {
		try {
			callback(json.query.pages[json.query.pageids[0]].revisions[0]['*']);
		} catch (e) {
			callback('');
		}
	});
}

function configHtml (idPrefix) {
	var html = '';

	html += mw.html.element('label', {'for': idPrefix + 'config-moves'}, mw.msg('schnark-diff-config-moves')) +
		mw.html.element('select', {id: idPrefix + 'config-moves'}, new mw.html.Raw(
			mw.html.element('option', {value: 1}, mw.msg('schnark-diff-config-moves-normal')) +
			mw.html.element('option', {value: -1}, mw.msg('schnark-diff-config-moves-nested')) +
			mw.html.element('option', {value: 0}, mw.msg('schnark-diff-config-moves-none')) +
			mw.html.element('option', {value: 2}, mw.msg('schnark-diff-config-moves-simple'))
		)) + '<br />';
	html += mw.html.element('label', {'for': idPrefix + 'config-char-diff'}, mw.msg('schnark-diff-config-char-diff')) +
		mw.html.element('input', {id: idPrefix + 'config-char-diff', size: 4, type: 'text'}) + '<br />';
	html += mw.html.element('label', {'for': idPrefix + 'config-word-diff-qual'},
			mw.msg('schnark-diff-config-word-diff-qual')) +
		mw.html.element('input', {id: idPrefix + 'config-word-diff-qual', size: 4, type: 'text'}) + '<br />';
	html += mw.html.element('label', {'for': idPrefix + 'config-recursion'}, mw.msg('schnark-diff-config-recursion')) +
		mw.html.element('input', {id: idPrefix + 'config-recursion', size: 4, type: 'text'}) + '<br />';
	html += mw.html.element('label', {'for': idPrefix + 'config-too-short'}, mw.msg('schnark-diff-config-too-short')) +
		mw.html.element('input', {id: idPrefix + 'config-too-short', size: 4, type: 'text'}) + '<br />';
	html += mw.html.element('label', {'for': idPrefix + 'config-small-region'},
			mw.msg('schnark-diff-config-small-region')) +
		mw.html.element('input', {id: idPrefix + 'config-small-region', size: 4, type: 'text'}) + '<br />';
	html += mw.html.element('label', {'for': idPrefix + 'config-min-moved-length'},
			mw.msg('schnark-diff-config-min-moved-length')) +
		mw.html.element('input', {id: idPrefix + 'config-min-moved-length', size: 4, type: 'text'}) + '<br />';
	html += mw.html.element('label', {'for': idPrefix + 'config-color-scheme'}, mw.msg('schnark-diff-config-color-scheme')) +
		mw.html.element('select', {id: idPrefix + 'config-color-scheme'}, new mw.html.Raw(
			mw.html.element('option', {value: 'classic'}, mw.msg('schnark-diff-config-color-scheme-classic')) +
			mw.html.element('option', {value: 'modern'}, mw.msg('schnark-diff-config-color-scheme-modern')) +
			mw.html.element('option', {value: 'wiked'}, mw.msg('schnark-diff-config-color-scheme-wiked'))
		)) + '<br /><br />';
	html += mw.html.element('button', {id: idPrefix + 'config-save'}, mw.msg('schnark-diff-config-save')) + ' ';
	html += mw.html.element('button', {id: idPrefix + 'config-reset'}, mw.msg('schnark-diff-config-reset'));
	html += mw.html.element('span', {style: 'float:right;'},
		mw.msg('schnark-diff-version', formatVersion(config.version), formatVersion(libs.schnarkDiff.version)));
	return html;
}

function EnhancedDiff (oldid, newid, $standardDiff, editData) {
	config.instances++;
	this.optionsPrefix = 'userjs-schnark-diff-';
	this.oldid = oldid;
	this.oldText = false;
	this.newid = newid;
	this.newText = false;
	this.$standardDiff = $standardDiff;
	this.idPrefix = 'schnark-diff-' + config.instances + '-';
	if (editData) {
		this.$container = editData.$container;
		this.section = editData.section;
		this.$textbox = editData.$textbox;
	}
}

EnhancedDiff.prototype = {
	getOldText: function (callback) {
		var self = this;
		if (this.oldText !== false) {
			callback(this.oldText);
			return;
		}
		if (this.oldid === 'conflict') {
			mw.loader.using('jquery.textSelection', function () {
				var text = $('#wpTextbox2').textSelection('getContents').replace(/\s+$/, '');
				self.oldtext = text;
				callback(text);
			});
			return;
		}
		if (this.newid === 'edit' || this.newid === 've') {
			if (this.section === 'new' || this.oldid === 0) {
				this.oldText = '';
				callback('');
				return;
			}
		}
		getRevision(this.oldid, this.section || null, function (text) {
			text = text.replace(/\s+$/, '');
			self.oldText = text;
			callback(text);
		});
	},
	getNewText: function (callback) {
		var self = this;
		if (this.newid === 'edit') {
			mw.loader.using('jquery.textSelection', function () {
				callback(self.$textbox.textSelection('getContents').replace(/\s+$/, ''));
			});
			return;
		}
		if (this.newid === 've') {
			ve.init.target.serialize(ve.init.target.getSurface().getDom(), function (wikitext) {
				callback(wikitext);
			});
			return;
		}
		if (this.newText !== false) {
			callback(this.newText);
			return;
		}
		getRevision(this.newid, function (text) {
			text = text.replace(/\s+$/, '');
			self.newText = text;
			callback(text);
		});
	},
	getConfigDefault: function () {
		var config = libs.schnarkDiff.config.get(['charDiff', 'wordDiffQual',
			'recursion', 'tooShort', 'smallRegion', 'minMovedLength']);
		config.indicateMoves = 1;
		config.nested = true;
		config.colorScheme = 'classic';
		return config;
	},
	getConfigInterface: function () {
		return {
			charDiff: Number($('#' + this.idPrefix + 'config-char-diff').val()),
			wordDiffQual: Number($('#' + this.idPrefix + 'config-word-diff-qual').val()) / 100,
			recursion: Number($('#' + this.idPrefix + 'config-recursion').val()),
			tooShort: Number($('#' + this.idPrefix + 'config-too-short').val()),
			smallRegion: Number($('#' + this.idPrefix + 'config-small-region').val()),
			minMovedLength: Number($('#' + this.idPrefix + 'config-min-moved-length').val()),
			indicateMoves: Math.abs($('#' + this.idPrefix + 'config-moves').val()),
			nested: $('#' + this.idPrefix + 'config-moves').val() < 0,
			colorScheme: $('#' + this.idPrefix + 'config-color-scheme').val()
		};
	},
	getConfig: function () {
		var key, val, config = {}, defaults = this.getConfigDefault();
		for (key in defaults) {
			if (hasOwn.call(defaults, key)) {
				val = mw.user.options.get(this.optionsPrefix + key);
				if (val === null) {
					val = defaults[key];
				} else {
					switch (typeof defaults[key]) {
					case 'number':
						val = Number(val);
						if (isNaN(val)) {
							val = defaults[key];
						}
						break;
					case 'boolean':
						val = val === 'true';
						break;
					}
				}
				config[key] = val;
			}
		}
		return config;
	},
	setConfig: function (config) {
		var moves;
		$('#' + this.idPrefix + 'config-char-diff').val(config.charDiff);
		$('#' + this.idPrefix + 'config-word-diff-qual').val(Math.round(config.wordDiffQual * 100));
		$('#' + this.idPrefix + 'config-recursion').val(config.recursion);
		$('#' + this.idPrefix + 'config-too-short').val(config.tooShort);
		$('#' + this.idPrefix + 'config-small-region').val(config.smallRegion);
		$('#' + this.idPrefix + 'config-min-moved-length').val(config.minMovedLength);
		if (config.nested) {
			moves = -1;
		} else {
			moves = config.indicateMoves;
		}
		$('#' + this.idPrefix + 'config-moves').val(moves);
		$('#' + this.idPrefix + 'config-color-scheme').val(config.colorScheme);
	},
	applyConfig: function (config) {
		this.configNested = config.nested;
		enableColorScheme(config.colorScheme);
		delete config.nested;
		delete config.colorScheme;
		libs.schnarkDiff.config.set(config);
	},
	saveConfig: function (config) {
		var options = [], key, current = this.getConfig(), defaults = this.getConfigDefault();
		for (key in config) {
			if (hasOwn.call(config, key)) {
				if (config[key] === current[key]) {
					continue;
				}
				if (config[key] === defaults[key]) {
					options.push(this.optionsPrefix + key);
				} else {
					options.push(this.optionsPrefix + key + '=' + config[key]);
				}
			}
		}
		if (options.length) {
			$.post(mw.util.wikiScript('api'), {
				action: 'options',
				change: options.join('|'),
				token: mw.user.tokens.get('csrfToken'),
				format: 'json'
			});
		}
	},
	getDiff: function (callback) {
		var self = this;
		self.getOldText(function (oldText) {
			self.getNewText(function (newText) {
				var config = self.getConfigInterface(), defConf = libs.schnarkDiff.config.get();
				self.applyConfig(config);
				callback(libs.schnarkDiff.htmlDiff(oldText, newText, self.configNested));
				libs.schnarkDiff.config.set(defConf);
			});
		});
	},

	buildInterface: function () {
		var $enhancedDiff, $buttonBarTop, $panelContainer, $buttonBarBottom,
			$panels, $panelOld, $panelNew, $panelConfig, $buttons, self = this;

		$enhancedDiff = $(mw.html.element('div', {'class': 'schnark-diff-container'}));
		$buttonBarTop = $('<div>').addClass('schnark-diff-buttons-top');
		$panelContainer = $('<div>');

		if (this.$standardDiff && this.$standardDiff.length === 1) {
			this.$container = this.$standardDiff.wrap('<div>').parent();
			$panelOld = $('<div>').addClass('schnark-diff-div').append(this.$standardDiff);
			$panelContainer.append($panelOld);
			$buttonBarTop.append(
				$(mw.html.element('span', {
					'class': 'schnark-diff-button', style: 'font-weight:bold;',
					title: mw.msg('schnark-diff-tab-normal-tooltip')
				}, mw.msg('schnark-diff-tab-normal')
				)).click(function () {
					$buttons.removeClass('schnark-diff-button-selected');
					$(this).addClass('schnark-diff-button-selected');
					$panels.hide();
					$panelOld.show();
				})
			);
		}

		$panelNew = $(mw.html.element('div', {'class': 'schnark-diff-div'}, ''));
		$panelNew.append($.createSpinner({size: 'large', type: 'block'}));
		$panelContainer.append($panelNew);
		$buttonBarTop.append($(mw.html.element('span', {
				'class': 'schnark-diff-button schnark-diff-button-new', style: 'font-weight:bold;color:green;',
				title: mw.msg('schnark-diff-tab-improved-tooltip')
			}, mw.msg('schnark-diff-tab-improved'))
		).click(function () {
			$buttons.removeClass('schnark-diff-button-selected');
			$(this).addClass('schnark-diff-button-selected');
			$panels.hide();
			$panelNew.show();
			self.getDiff(function (html) {
				$panelNew.html(html);
				libs.schnarkDiff.addEvents($panelNew);
			});
		}));

		$panelConfig = $('<div>').html(configHtml(this.idPrefix)).addClass('schnark-diff-div');
		$panelContainer.append($panelConfig);
		$buttonBarTop.append($(mw.html.element('span', {
			'class': 'schnark-diff-button', style: 'font-weight:bold;',
			title: mw.msg('schnark-diff-tab-config-tooltip')}, mw.msg('schnark-diff-tab-config'))
		).click(function () {
			$buttons.removeClass('schnark-diff-button-selected');
			$(this).addClass('schnark-diff-button-selected');
			$panels.hide();
			$panelConfig.show();
		}));

		$panels = $panelContainer.find('.schnark-diff-div');
		$buttons = $buttonBarTop.find('.schnark-diff-button');
		$buttonBarBottom = $buttonBarTop
			.clone(true)
			.removeClass('schnark-diff-buttons-top')
			.addClass('schnark-diff-buttons-bottom');
		$buttons = $buttons.add($buttonBarBottom.find('.schnark-diff-button'));

		$enhancedDiff.append($buttonBarTop)
			.append($panelContainer)
			.append($buttonBarBottom);
		this.$firstButton = $buttons.first();
		this.$enhancedDiff = $enhancedDiff;
		this.$firstButton.click();

		this.$container.append($enhancedDiff);
		this.setConfig(this.getConfig());
		$panelConfig.find('#' + this.idPrefix + 'config-save').click(function () {
			self.saveConfig(self.getConfigInterface());
		});
		$panelConfig.find('#' + this.idPrefix + 'config-reset').click(function () {
			self.setConfig(self.getConfigDefault());
		});
	},

	showNew: function () {
		var self = this, div;
		if (this.$firstButton) {
			this.$firstButton.click();
			div = this.$enhancedDiff[0];
			if (div.scrollIntoView) {
				div.scrollIntoView();
			}
		} else {
			loadDiffJs(function () {
				self.buildInterface();
			});
		}
	}
};

function getEnhancedDiffForDiff ($diff) {
	if ($diff.hasClass('schnark-diff-wrapped-around')) {
		return;
	}
	$diff.addClass('schnark-diff-wrapped-around');
	var $old = $diff.find('#mw-diff-otitle1 a'),
		$new = $diff.find('#mw-diff-ntitle1 a'),
		$revdel = $diff.find('#mw-rev-suppressed-no-diff, #mw-rev-deleted-no-diff,' +
			'#mw-rev-suppressed-unhide-diff, #mw-rev-deleted-unhide-diff'),
		$textbox;
	if ($new.length >= 1) {
		if ($old.length === 0 || $revdel.length) { //no real diff shown
			return;
		}
		return new EnhancedDiff(getRevisionId($old), getRevisionId($new), $diff);
	}
	$textbox = $('#wpTextbox1');
	if ($textbox.length === 1) {
		if ($('#wpTextbox2').length === 1) {
			return new EnhancedDiff('conflict', 'edit', $diff, {$textbox: $textbox});
		}
		return new EnhancedDiff(mw.config.get('wgCurRevisionId'), 'edit', $diff, {
			section: $('input[name="wpSection"]').val(),
			$textbox: $textbox
		});
	}
	if (window.ve) {
		return new EnhancedDiff(mw.config.get('wgCurRevisionId'), 've', $diff);
	}
}

function getEnhancedDiffWithoutDiff ($editform) {
	if ($editform.hasClass('schnark-diff-added-to')) {
		return;
	}
	$editform.addClass('schnark-diff-added-to');
	var $div = $('<div>');
	$editform.before($div);

	return new EnhancedDiff(mw.config.get('wgCurRevisionId'), 'edit', false, {
		$container: $div,
		section: $('input[name="wpSection"]').val(),
		$textbox: $('#wpTextbox1')
	});
}

function getEnhancedDiff ($content, force) {
	var $diff = $content.is('table.diff') ? $content : $content.find('table.diff'), $editform;
	if ($diff.length === 1) {
		return getEnhancedDiffForDiff($diff);
	}
	$editform = $content.find('#editform');
	if ($editform.length === 1 && force) {
		return getEnhancedDiffWithoutDiff($editform);
	}
}

function run ($content) {
	var enhancedDiff = getEnhancedDiff($content,
		$.inArray(mw.config.get('wgAction'), ['edit', 'submit']) > -1 &&
		config.alwaysOnEdit
	), $diffButton;
	if (!enhancedDiff) {
		return;
	}

	if (!enhancedDiff.$standardDiff || enhancedDiff.$standardDiff.length === 0) {
		$diffButton = $(mw.html.element('input', {
				id: 'enhanced-diff-live-button', type: 'button',
				value: mw.msg('schnark-diff-button'), title: mw.msg('schnark-diff-button-tooltip')
			})
		).click(function () {
			enhancedDiff.showNew();
		});
		$('#wpDiff').after($diffButton);
	} else {
		loadDiffJs(function () {
			enhancedDiff.buildInterface();
		});
	}
}

function init () {
	initL10N(l10n);
	mw.util.addCSS(config.css + (config.cssSkin[mw.config.get('skin')] || ''));
	mw.hook('wikipage.diff').add(run);
	//TODO aufräumen
	mw.hook('wikipage.content').add(run);
	mw.hook('wikipage.editform').add(function () {
		run($(document));
	});
	mw.hook('ve.saveDialog.stateChanged').add(function () {
		run($(document));
	});
}

mw.hook('userjs.load-script.diff').fire(config);

mw.loader.using(['mediawiki.util', 'mediawiki.language', 'user.options', 'jquery.spinner'], init);

})(jQuery, mediaWiki, mediaWiki.libs);
//</nowki>