MediaWiki:Bandersnatch.js

Aus Fahrradmonteur
Zur Navigation springenZur Suche springen

Hinweis: Leere nach dem Speichern 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
  • Internet Explorer: Strg+F5 drücken oder Strg drücken und gleichzeitig Aktualisieren anklicken
  • Opera: Gehe zu Menü → Einstellungen (Opera → Einstellungen auf dem Mac) und dann auf Datenschutz & Sicherheit → Browserdaten löschen → Gespeicherte Bilder und Dateien.
//Dokumentation unter [[Benutzer:Schnark/js/bandersnatch]] <nowiki>
/*global mediaWiki*/
(function($,mw,libs){
"use strict";

var global = {}, l10n = {
	en: {
		'diff': 'diff',
		'minoreditletter': 'm',
		'boteditletter': 'b',
		'article': 'Content page',
		'pagehist': 'Page history',

		'schnark-bandersnatch-error-abort': 'abort',
		'schnark-bandersnatch-error-editconflict': 'edit conflict',
		'schnark-bandersnatch-error-lostlogin': 'login got lost',
		'schnark-bandersnatch-error-maxlag': 'database lag too big',
		'schnark-bandersnatch-error-noedit': 'no edit necessary',
		'schnark-bandersnatch-error-notverified': 'discarded',
		'schnark-bandersnatch-error-server': 'server error',
		'schnark-bandersnatch-error-spam': 'detected as spam',
		'schnark-bandersnatch-error-unknown': 'unknown error',
		'schnark-bandersnatch-error-preview': 'Preview failed!',
		'schnark-bandersnatch-diff-show': 'show diff',
		'schnark-bandersnatch-diff-hide': 'hide diff',
		'schnark-bandersnatch-preview-wait': 'Preview is being generated',

		'schnark-bandersnatch-batch-summary': 'Edit summary',
		'schnark-bandersnatch-batch-minor': 'minor edit',
		'schnark-bandersnatch-batch-bot': 'bot edit',
		'schnark-bandersnatch-batch-preview': 'Preview',
		'schnark-bandersnatch-batch-diff': 'Diff',
		'schnark-bandersnatch-batch-revert': 'Discard change',
		'schnark-bandersnatch-batch-skip': 'Skip',
		'schnark-bandersnatch-batch-save': 'Save',
		'schnark-bandersnatch-check-no': 'Discard change',
		'schnark-bandersnatch-check-ok': 'Accept change',
		'schnark-bandersnatch-abort': 'Abort',
		'schnark-bandersnatch-step-continue': 'Continue',
		'schnark-bandersnatch-step-back': 'Back',
		'schnark-bandersnatch-step-go': 'Go!',
		'schnark-bandersnatch-step-1-head': 'Pages',
		'schnark-bandersnatch-step-1-search-simple': 'In a first step you must specify which pages should be edited. Enter one title per line to do so. If you use my script search++, you\'ll have a way to use complex queries to find pages.',
		'schnark-bandersnatch-step-1-search-complex': 'In a first step you must specify which pages should be edited. Enter one title per line to do so. You can also use the search.',
		'schnark-bandersnatch-step-1-search-query': 'Search query:',
		'schnark-bandersnatch-step-1-search-submit': 'Search',
		'schnark-bandersnatch-step-1-search-error': 'Error: $1',
		'schnark-bandersnatch-step-1-pages': 'Pages:',
		'schnark-bandersnatch-step-1-xml': 'You also can $1.',
		'schnark-bandersnatch-step-1-xml-read': 'upload an XML dump',
		'schnark-bandersnatch-step-2-head': 'Code',
		'schnark-bandersnatch-step-2-text': 'In a second step you must enter the JavaScript code that should be used to edit the pages. Enter the body of a function with parameters title for the title, and oldText for the old text of the page, which returns an object with properties text (the new text or false to skip), summary (optional for an edit summary, otherwise the default summary will be used), minor (true or false to flag the edit as minor, optional), and bot (likewise).',
		'schnark-bandersnatch-step-2-code': 'Code for edit function',
		'schnark-bandersnatch-step-2-tools': 'Tools',
		'schnark-bandersnatch-step-2-tools-tool': 'Tool',
		'schnark-bandersnatch-step-2-tools-use': 'Usage',
		'schnark-bandersnatch-step-2-tools-load': 'Load',
		'schnark-bandersnatch-tool-load': 'Load',
		'schnark-bandersnatch-tool-noload': 'not necessary',
		'schnark-bandersnatch-tool-replace': 'Simple replacement',
		'schnark-bandersnatch-tool-replace-code': 'newText = oldText.replace(/foo/g, \'bar\');',
		'schnark-bandersnatch-tool-wstm': 'WSTM<br>PerfektesChaos',
		'schnark-bandersnatch-tool-wstm-code': 'newText = mw.libs.doWSTM(oldText, title);',
		'schnark-bandersnatch-tool-template': 'Template<br>Schnark',
		'schnark-bandersnatch-tool-template-code': 'template = new mw.libs.Template(\'templateName\', oldText);\n//...e.g. template.insert(\'new parameter\', \'new value\');\nnewText = template.toString();',
		'schnark-bandersnatch-step-2-test': 'Test environment',
		'schnark-bandersnatch-step-2-test-title': 'Title: ',
		'schnark-bandersnatch-step-2-test-title-default': 'Test title',
		'schnark-bandersnatch-step-2-test-run': 'Run test',
		'schnark-bandersnatch-step-3-head': 'Parameter',
		'schnark-bandersnatch-step-3-text': 'As a last step now enter the default parameters for all edits and make sure that you know what you are doing before clicking "Go!"',
		'schnark-bandersnatch-step-3-summary': 'Edit summary',
		'schnark-bandersnatch-step-3-minor': 'minor edit',
		'schnark-bandersnatch-step-3-bot': 'bot edit',
		'schnark-bandersnatch-step-3-wait': 'Time between two edits (seconds): ',
		'schnark-bandersnatch-step-3-maxlag': 'Maxlag: ',
		'schnark-bandersnatch-step-3-maxlag-ignore': 'ignore',
		'schnark-bandersnatch-step-3-maxlag-5x5': '5 seconds, 5 tries',
		'schnark-bandersnatch-step-3-mode': 'Mode: ',
		'schnark-bandersnatch-step-3-mode-simulate': 'simulae',
		'schnark-bandersnatch-step-3-mode-batch': 'batch mode',
		'schnark-bandersnatch-step-3-mode-check': 'semi-automatic',
		'schnark-bandersnatch-step-3-mode-auto': 'automatic',
		'schnark-bandersnatch-title': 'Bandersnatch',
		'schnark-bandersnatch-version': 'Bandersnatch (version $1)'
	},
	de: {
		'diff': 'Unterschied',
		'minoreditletter': 'K',
		'boteditletter': 'B',
		'article': 'Seite',
		'pagehist': 'Versionsgeschichte',
		'schnark-bandersnatch-error-abort': 'Abbruch',
		'schnark-bandersnatch-error-editconflict': 'Bearbeitungskonflikt',
		'schnark-bandersnatch-error-lostlogin': 'Login verloren gegangen',
		'schnark-bandersnatch-error-maxlag': 'Datenbank-Lag zu groß',
		'schnark-bandersnatch-error-noedit': 'keine Bearbeitung nötig',
		'schnark-bandersnatch-error-notverified': 'verworfen',
		'schnark-bandersnatch-error-server': 'Serverfehler',
		'schnark-bandersnatch-error-spam': 'als Spam erkannt',
		'schnark-bandersnatch-error-unknown': 'unbekannter Fehler',
		'schnark-bandersnatch-error-preview': 'Vorschau fehlgeschlagen!',
		'schnark-bandersnatch-diff-show': 'Unterschied anzeigen',
		'schnark-bandersnatch-diff-hide': 'Unterschied verstecken',
		'schnark-bandersnatch-preview-wait': 'Vorschau wird ermittelt',
		'schnark-bandersnatch-batch-summary': 'Bearbeitungskommentar',
		'schnark-bandersnatch-batch-minor': 'kleine Änderung',
		'schnark-bandersnatch-batch-bot': 'Bot-Änderung',
		'schnark-bandersnatch-batch-preview': 'Vorschau',
		'schnark-bandersnatch-batch-diff': 'Unterschied',
		'schnark-bandersnatch-batch-revert': 'Änderung verwerfen',
		'schnark-bandersnatch-batch-skip': 'Ãœberspringen',
		'schnark-bandersnatch-batch-save': 'Speichern',
		'schnark-bandersnatch-check-no': 'Verwerfen',
		'schnark-bandersnatch-check-ok': 'Akzeptieren',
		'schnark-bandersnatch-abort': 'Abbrechen',
		'schnark-bandersnatch-step-continue': 'Weiter',
		'schnark-bandersnatch-step-back': 'Zurück',
		'schnark-bandersnatch-step-go': 'Los!',
		'schnark-bandersnatch-step-1-head': 'Seiten',
		'schnark-bandersnatch-step-1-search-simple': 'Als erstes musst du die Seiten angeben, die bearbeitet werden sollen. Schreibe dazu in jede Zeile genau einen Titel. Wenn du mein Skript search++ verwendest, hast du die Möglichkeit, komplexe Suchanfragen zu verwenden.',
		'schnark-bandersnatch-step-1-search-complex': 'Als erstes musst du die Seiten angeben, die bearbeitet werden sollen. Schreibe dazu in jede Zeile genau einen Titel. Du kannst dazu auch die Suchfunktion nutzen.',
		'schnark-bandersnatch-step-1-search-query': 'Suchanfrage:',
		'schnark-bandersnatch-step-1-search-submit': 'Suchen',
		'schnark-bandersnatch-step-1-search-error': 'Fehler: $1',
		'schnark-bandersnatch-step-1-pages': 'Seiten:',
		'schnark-bandersnatch-step-1-xml': 'Du kannst auch einen $1.',
		'schnark-bandersnatch-step-1-xml-read': 'XML-Dump einlesen',
		'schnark-bandersnatch-step-2-head': 'Code',
		'schnark-bandersnatch-step-2-text': 'Als nächstes musst du den JavaScript-Code angeben, der bei der Bearbeitung verwendet werden soll. Gib den Körper einer Funktion an, die die Parameter title für den Titel und oldText für den alten Text der Seite kennt und ein Objekt mit den Eigenschaften text (der neue Text oder false zum Überspringen), summary (optional als Zusammenfassung, es wird die Standard-Zusammenfassung verwendet, wenn die Eigenschaft fehlt), minor (true oder false zur Markierung als kleine Bearbeitung, optional) und bot (ebenso).',
		'schnark-bandersnatch-step-2-code': 'Code für Bearbeitungsfunktion',
		'schnark-bandersnatch-step-2-tools': 'Werkzeuge',
		'schnark-bandersnatch-step-2-tools-tool': 'Werkzeug',
		'schnark-bandersnatch-step-2-tools-use': 'Verwendung',
		'schnark-bandersnatch-step-2-tools-load': 'Laden',
		'schnark-bandersnatch-tool-load': 'Laden',
		'schnark-bandersnatch-tool-noload': 'nicht nötig',
		'schnark-bandersnatch-tool-replace': 'Einfache Ersetzung',
		'schnark-bandersnatch-tool-replace-code': 'neu = alt.replace(/foo/g, \'bar\');',
		'schnark-bandersnatch-tool-wstm': 'WSTM<br>PerfektesChaos',
		'schnark-bandersnatch-tool-wstm-code': 'neu = mw.libs.doWSTM(alt, title);',
		'schnark-bandersnatch-tool-template': 'Template<br>Schnark',
		'schnark-bandersnatch-tool-template-code': 'template = new mw.libs.Template(\'Vorlagenname\', alt);\n//...z. B. template.insert(\'neuer Parameter\', \'neuer Wert\');\nneu = template.toString();',
		'schnark-bandersnatch-step-2-test': 'Testumgebung',
		'schnark-bandersnatch-step-2-test-title': 'Titel: ',
		'schnark-bandersnatch-step-2-test-title-default': 'Testtitel',
		'schnark-bandersnatch-step-2-test-run': 'Testen',
		'schnark-bandersnatch-step-3-head': 'Parameter',
		'schnark-bandersnatch-step-3-text': 'Gib als letztes die Standard-Parameter für alle Bearbeitungen an und stelle sicher, dass du weißt, was du tust, bevor du auf „Los!“ klickst.',
		'schnark-bandersnatch-step-3-summary': 'Bearbeitungskommentar',
		'schnark-bandersnatch-step-3-minor': 'kleine Änderung',
		'schnark-bandersnatch-step-3-bot': 'Bot-Änderung',
		'schnark-bandersnatch-step-3-wait': 'Sekunden zwischen Bearbeitungen: ',
		'schnark-bandersnatch-step-3-maxlag': 'Maxlag: ',
		'schnark-bandersnatch-step-3-maxlag-ignore': 'Ignorieren',
		'schnark-bandersnatch-step-3-maxlag-5x5': '5 Sekunden, 5 Versuche',
		'schnark-bandersnatch-step-3-mode': 'Modus: ',
		'schnark-bandersnatch-step-3-mode-simulate': 'Simulation',
		'schnark-bandersnatch-step-3-mode-batch': 'Stapelverarbeitung',
		'schnark-bandersnatch-step-3-mode-check': 'halbautomatisch',
		'schnark-bandersnatch-step-3-mode-auto': 'automatisch',
		'schnark-bandersnatch-title': 'Bandersnatch',
		'schnark-bandersnatch-version': 'Bandersnatch (Version $1)'
	},
	'de-ch': {
		'schnark-bandersnatch-error-maxlag': 'Datenbank-Lag zu gross',
		'schnark-bandersnatch-step-3-text': 'Gib als letztes die Standard-Parameter für alle Bearbeitungen an und stelle sicher, dass du weisst, was du tust, bevor du auf «Los!» klickst.'
	},
	'de-formal': {
		'schnark-bandersnatch-step-1-search-simple': 'Als erstes müssen Sie die Seiten angeben, die bearbeitet werden sollen. Schreiben Sie dazu in jede Zeile genau einen Titel. Wenn Sie mein Skript search++ verwenden, haben Sie die Möglichkeit, komplexe Suchanfragen zu verwenden.',
		'schnark-bandersnatch-step-1-search-complex': 'Als erstes müssen Sie die Seiten angeben, die bearbeitet werden sollen. Schreiben Sie dazu in jede Zeile genau einen Titel. Sie können dazu auch die Suchfunktion nutzen.',
		'schnark-bandersnatch-step-1-xml': 'Sie können auch einen $1.',
		'schnark-bandersnatch-step-2-text': 'Als nächstes müssen Sie den JavaScript-Code angeben, der bei der Bearbeitung verwendet werden soll. Geben Sie den Körper einer Funktion an, die die Parameter title für den Titel und oldText für den alten Text der Seite kennt und ein Objekt mit den Eigenschaften text (der neue Text oder false zum Überspringen), summary (optional als Zusammenfassung, es wird die Standard-Zusammenfassung verwendet, wenn die Eigenschaft fehlt), minor (true oder false zur Markierung als kleine Bearbeitung, optional) und bot (ebenso).',
		'schnark-bandersnatch-step-3-text': 'Geben Sie als letztes die Standard-Parameter für alle Bearbeitungen an und stellen Sie sicher, dass Sie wissen, was Sie tun, bevor Sie auf „Los!“ klicken.'
	}
};

global.version = '1.4';

(function(){
//Backend

var	ABORT = 0,
	EDITCONFLICT = 1,
	LOSTLOGIN = 2,
	MAXLAG = 3,
	NOEDIT = 4,
	NOTVERIFIED = 5,
	SERVER = 6,
	SPAM = 7,
	UNKNOWN = 8;
global.error = {
	ABORT: ABORT,
	EDITCONFLICT: EDITCONFLICT,
	LOSTLOGIN: LOSTLOGIN,
	MAXLAG: MAXLAG,
	NOEDIT: NOEDIT,
	NOTVERIFIED: NOTVERIFIED,
	SERVER: SERVER,
	SPAM: SPAM,
	UNKNOWN: UNKNOWN
};

function makeParam (data, maxlag) {
	var param = {
		action: 'edit',
		title: data.title,
		text: data.text,
		summary: data.summary,
		basetimestamp: data.basetimestamp,
		starttimestamp: data.starttimestamp,
		token: data.token,
		format: 'json'
	};
	if (data.bot) {
		param.bot = '';
	}
	if (data.minor) {
		param.minor = '';
	} else {
		param.notminor = '';
	}
	if (maxlag !== false) {
		param.maxlag = maxlag;
	}
	return param;
}

function reallyEdit (data, maxlagF, onSuccess, onError, n) {
	n = n || 0;
	var maxlag = maxlagF(n);
	if (maxlag === true) {
		onError(MAXLAG);
		return;
	}
	$.post(mw.util.wikiScript('api'), makeParam(data, maxlag))
		.done(function(json) {
			if (json && json.edit && json.edit.result === 'Success') {
				onSuccess();
			} else if (json && json.error) {
				switch (json.error.code) {
				case 'maxlag':
					window.setTimeout(function () {
						reallyEdit(data, maxlagF, onSuccess, onError, n + 1);
					}, maxlagF(n, true) || 5000);
					break;
				case 'editconflict':
				case 'pagedeleted':
					onError(EDITCONFLICT);
					break;
				case 'spamdetected':
					onError(SPAM);
					break;
				default:
					onError(UNKNOWN);
				}
			} else {
				onError(SERVER);
			}
		})
		.fail(function() {
			onError(SERVER);
		});
}

function getData (title, onSuccess, onError) {
	$.getJSON(mw.util.wikiScript('api'), {
		action: 'query',
		prop: 'info|revisions',
		meta: 'tokens',
		titles: title,
		rvprop: 'timestamp|content',
		rvlimit: 1,
		indexpageids: '',
		format: 'json'
	}).done(function (json) {
		if (!json || !json.query || !json.query.pageids || !json.query.pages || !json.query.tokens) {
			onError(SERVER);
			return;
		}
		var page = json.query.pages[json.query.pageids[0]];
		if (!page) {
			onError(SERVER);
			return;
		}
		if (page.missing === '') {
			page.text = '';
			page.basetimestamp = page.starttimestamp;
		} else if (page.revisions && page.revisions[0]) {
			page.text = page.revisions[0]['*'];
			page.basetimestamp = page.revisions[0].timestamp;
		} else {
			onError(SERVER);
			return;
		}
		if (json.query.tokens.csrftoken === '\\+') {
			onError(LOSTLOGIN);
			return;
		}
		onSuccess({
			text: page.text,
			basetimestamp: page.basetimestamp,
			starttimestamp: page.starttimestamp,
			token: json.query.tokens.csrftoken
		});
	}).fail(function() {
		onError(SERVER);
	});
}

function editOne (title, timestamp, defaultParam, editF, verifyF, abortF, maxlagF, onSuccess, onError) {
	if (abortF()) {
		onError(ABORT);
		return;
	}
	getData(title, function (data) {
		if (abortF()) {
			onError(ABORT);
			return;
		}
		editF(title, data.text, function (ret) {
			var edit = $.extend({text: false}, defaultParam, ret || {text: false});
			if (edit.text === false || edit.text === data.text) {
				onError(NOEDIT);
				return;
			}
			if (abortF()) {
				onError(ABORT);
				return;
			}
			verifyF(title, data.text, edit, function () {
				if (abortF()) {
					onError(ABORT);
					return;
				}
				var wait = timestamp - $.now();
				if (wait < 0) {
					wait = 0;
				}
				window.setTimeout(function () {
					reallyEdit({
						title: title,
						text: edit.text,
						summary: edit.summary,
						minor: edit.minor,
						bot: edit.bot,
						basetimestamp: data.basetimestamp,
						starttimestamp: data.starttimestamp,
						token: data.token
					}, maxlagF, function () {
						onSuccess({
							oldText: data.text,
							newText: edit.text,
							summary: edit.summary,
							minor: edit.minor,
							bot: edit.bot
						});
					}, onError);
				}, wait);
			}, function () {
				onError(NOTVERIFIED);
			});
		});
	}, onError);
}

function editMany (titles, wait, defaultParam, editF, verifyF, abortF, maxlagF, onSuccess, onError, onFinish) {
	var i = -1, title = '', timestamp = 0;
	function successHandler (data) {
		timestamp = $.now();
		onSuccess(title, data);
		editNext();
	}
	function errorHandler (code) {
		onError(title, code);
		if (code === ABORT) {
			onFinish();
		} else {
			editNext();
		}
	}
	function editNext () {
		i++;
		if (i >= titles.length) {
			onFinish();
			return;
		}
		title = titles[i];
		editOne(title, timestamp + wait, defaultParam, editF, verifyF, abortF, maxlagF, successHandler, errorHandler);
	}
	editNext();
}

global.editMany = editMany;

})();

(function(){
//Verbindung Backend-Frontend

function showPreview (text, title, $area) {
	$.post(mw.util.wikiScript('api'), {
		action: 'parse',
		title: title,
		prop: 'text|categorieshtml|langlinks|modules',
		pst: '',
		disablepp: '',
		text: '__NOEDITSECTION__\n' + text,
		format: 'json'
	}).done(function (json) {
		if (!json || !json.parse || !json.parse.text || !json.parse.text['*']) {
			$area.html(mw.msg('schnark-bandersnatch-error-preview'));
			return;
		}
		var html = json.parse.text['*'], modules;
		if (json.parse.categorieshtml && json.parse.categorieshtml['*']) {
			html += json.parse.categorieshtml['*'];
		}
		if (json.parse.langlinks && json.parse.langlinks.length) {
			html += '<hr>' + $.map(json.parse.langlinks, function (ll) {
				return mw.html.element('a', {
					href: ll.url,
					title: ll.langname + ' – ' + ll['*']
				}, ll.autonym);
			}).join(', ');
		}
		$area.html(html);
		mw.hook('wikipage.content').fire($area);

		modules = json.parse.modules.concat(
			json.parse.modulescripts,
			json.parse.modulestyles,
			json.parse.modulemessages
		);
		mw.loader.load(modules);
	}).fail(function () {
		$area.html(mw.msg('schnark-bandersnatch-error-preview'));
	});
}

function getErrorDescription (code) {
	switch (code) {
	case global.error.ABORT: code = 'abort'; break;
	case global.error.EDITCONFLICT:  code = 'editconflict'; break;
	case global.error.LOSTLOGIN:  code = 'lostlogin'; break;
	case global.error.MAXLAG:  code = 'maxlag'; break;
	case global.error.NOEDIT:  code = 'noedit'; break;
	case global.error.NOTVERIFIED:  code = 'notverified'; break;
	case global.error.SERVER:  code = 'server'; break;
	case global.error.SPAM:  code = 'spam'; break;
	case global.error.UNKNOWN:  code = 'unknown'; break;
	}
	return mw.msg('schnark-bandersnatch-error-' + code);
}

function getEditFlags (minor, bot) {
	return (minor ? '<b>' + mw.msg('minoreditletter') + '</b>' : '&#160;') + ' ' + (bot ? '<b>' + mw.msg('boteditletter') + '</b>' : '&#160;');
}

function showEdit (title, edit, cssClass) {
	cssClass = cssClass || 'success';
	var diff = global.diff(edit.oldText, edit.newText),
		diffLink = ' (' +
			mw.html.element('a', {href: mw.util.wikiScript() + '?' + $.param({
				title: title,
				diff: 'curr'
			})}, mw.msg('diff')) +
			')',
		$li = $('<li>').addClass('autoedit-' + cssClass).html(
			mw.html.element('a', {href: mw.util.getUrl(title)}, title) +
			(cssClass !== 'check' && cssClass !== 'simulate' ? diffLink : '') +
			mw.html.element('br', {}) + getEditFlags(edit.minor, edit.bot) + ' ' +
			mw.html.element('code', {}, edit.summary) +
			mw.html.element('div', {
				'data-collapsetext': mw.msg('schnark-bandersnatch-diff-hide'),
				'data-expandtext': mw.msg('schnark-bandersnatch-diff-show')
			}, new mw.html.Raw(diff))
		);
	if (cssClass !== 'check') {
		$li.find('div').addClass('mw-collapsed').makeCollapsible();
	}
	global.$log.append($li);
}

function showError (title, code) {
	var $li = $('<li>').addClass('autoedit-error').html(
		mw.html.element('a', {href: mw.util.getUrl(title)}, title) +
		'&#160;– ' + getErrorDescription(code)
	);
	global.$log.append($li);
}

function verifySimulate (title, oldText, edit, doit, dontdoit) {
	showEdit(title, {
		oldText: oldText,
		newText: edit.text,
		summary: edit.summary,
		minor: edit.minor,
		bot: edit.bot
	}, 'simulate');
	dontdoit();
}

function errorSimulate (title, code) {
	if (code !== global.error.NOTVERIFIED) {
		showError(title, code);
	}
}

function verifyCheck (title, oldText, edit, doit, dontdoit) {
	showEdit(title, {
		oldText: oldText,
		newText: edit.text,
		summary: edit.summary,
		minor: edit.minor,
		bot: edit.bot
	}, 'check');
	global.check.$ok.off('click').click(function () {
		global.$log.find('li:last').remove();
		doit();
	});
	global.check.$no.off('click').click(function () {
		global.$log.find('li:last').remove();
		dontdoit();
	});
}

function verifyAuto (title, oldText, edit, doit /*, dontdoit*/) {
	doit();
}

function getHandlersFor (type) {
	switch (type) {
	case 'simulate':
		return [verifySimulate, $.noop, errorSimulate];
	case 'batch':
	case 'auto':
		return [verifyAuto, showEdit, showError];
	case 'check':
		return [verifyCheck, showEdit, showError];
	}
}

function batchEdit (title, edit, oldText, callback) {
	document.title = document.title.replace(/ –.*/, '') + ' – ' + title;
	global.batch.$title.text(title);
	global.batch.$information.html(
		mw.html.element('a', {href: mw.util.getUrl(title)}, mw.msg('article')) +
		' (' + mw.html.element('a', {href: mw.config.get('wgScript') + '?' + $.param({title: title, action: 'history'})}, mw.msg('pagehist')) + ')'
	);
	global.batch.$area.html(global.diff(oldText, edit.text));
	global.batch.$textbox.val(edit.text);
	global.batch.$summary.val(edit.summary);
	global.batch.$minor.prop('checked', edit.minor);
	global.batch.$bot.prop('checked', edit.bot);
	global.batch.$preview.off('click').click(function () {
		global.batch.$area.html(mw.msg('schnark-bandersnatch-preview-wait'));
		showPreview(global.batch.$textbox.val(), title, global.batch.$area);
	});
	global.batch.$diff.off('click').click(function () {
		global.batch.$area.html(global.diff(oldText, global.batch.$textbox.val()));
	});
	global.batch.$revert.off('click').click(function () {
		global.batch.$textbox.val(oldText);
	});
	global.batch.$skip.off('click').click(function () {
		callback({text: false});
	});
	global.batch.$save.off('click').click(function () {
		callback({
			text: global.batch.$textbox.val(),
			summary: global.batch.$summary.val(),
			minor: global.batch.$minor.prop('checked'),
			bot: global.batch.$bot.prop('checked')
		});
	});
}

function makeFunction (code) {
	/*jshint evil: true*/
	return new Function ('title', 'oldText', code);
}

function getEditFunction (code, type, defaultParam) {
	var f = makeFunction(code);
	if (type === 'batch') {
		return function (title, oldText, callback) {
			var edit = $.extend({text: false}, defaultParam, f(title, oldText) || {text: false});
			if (edit.text === false) {
				callback(edit);
			} else {
				batchEdit(title, edit, oldText, callback);
			}
		};
	} else {
		return function (title, oldText, callback) {
			callback(f(title, oldText));
		};
	}
}

function maxlagIgnore () {
	return false;
}

function maxlag5x5 (n) {
	if (n >= 5) {
		return true;
	}
	return 5;
}

function getMaxlagFunction (type) {
	switch (type) {
	case 'ignore': return maxlagIgnore;
	case 'default': return maxlag5x5;
	}
}

function editFromForm (titleList, defaultSummary, defaultMinor, defaultBot, waitSeconds, maxlagType, editCode, editType, onFinish) {
	var	abort = false,
		titles = titleList.replace(/\r\n/g, '\n').replace(/^\n+|\n+$/g, '').split('\n'),
		wait = Number(waitSeconds) * 1000,
		defaultParam = {
			summary: defaultSummary,
			minor: defaultMinor,
			bot: defaultBot
		},
		editF = getEditFunction(editCode, editType, defaultParam),
		funcs = getHandlersFor(editType),
		verifyF = funcs[0],
		abortF = function () {
			return abort;
		},
		maxlagF = getMaxlagFunction (maxlagType),
		onSuccess = funcs[1],
		onError = funcs[2];
	global.$abort.click(function () {
		abort = true;
	});
	global.editMany(titles, wait, defaultParam, editF, verifyF, abortF, maxlagF, onSuccess, onError, onFinish);
}

global.editFromForm = editFromForm;
global.makeFunction = makeFunction;

})();

(function(){
//Frontend

function isBot () {
	return $.inArray('bot', mw.config.get('wgUserGroups')) > -1;
}

function testCode ($code, $title, $test) {
	var f = global.makeFunction($code.val()), ret = f($title.val(), $test.val());
	if (ret) {
		$test.val(ret.text);
	}
}

function makeBatchInterface ($container) {
	var html = mw.html.element('h2', {id: 'batch-title'}, '') +
		mw.html.element('span', {id: 'batch-information'}, '') +
		mw.html.element('div', {id: 'batch-area', style: 'border: 1px dotted blue;'},
			new mw.html.Raw(mw.html.element('div', {id: 'mw-content-text', 'class': 'mw-content-ltr'}, '')) //FIXME: abhängig von Schreibrichtung des Wikis
		) +
		mw.html.element('textarea', {id: 'batch-textbox', rows: 25, cols: 80}, '') +
		mw.html.element('label', {'for': 'batch-summary'}, mw.msg('schnark-bandersnatch-batch-summary')) +
		mw.html.element('br', {}) +
		mw.html.element('input', {id: 'batch-summary', value: '', size: 200, style: 'width: 100%'}) +
		mw.html.element('br', {}) +
		mw.html.element('input', {id: 'batch-minor', type: 'checkbox'}) +
		mw.html.element('label', {'for': 'batch-minor'}, mw.msg('schnark-bandersnatch-batch-minor')) +
		' ' +
		mw.html.element('input', {id: 'batch-bot', type: 'checkbox'}) +
		mw.html.element('label', {'for': 'batch-bot'}, mw.msg('schnark-bandersnatch-batch-bot')) +
		mw.html.element('br', {}) +
		mw.html.element('button', {id: 'batch-preview'}, mw.msg('schnark-bandersnatch-batch-preview')) +
		mw.html.element('button', {id: 'batch-diff'}, mw.msg('schnark-bandersnatch-batch-diff')) +
		mw.html.element('button', {id: 'batch-revert'}, mw.msg('schnark-bandersnatch-batch-revert')) +
		mw.html.element('button', {id: 'batch-skip'}, mw.msg('schnark-bandersnatch-batch-skip')) +
		mw.html.element('button', {id: 'batch-save'}, mw.msg('schnark-bandersnatch-batch-save'));
	$container.html(html);
	global.batch = {
		$title: $container.find('#batch-title'),
		$information: $container.find('#batch-information'),
		$area: $container.find('#mw-content-text'),
		$textbox: $container.find('#batch-textbox'),
		$summary: $container.find('#batch-summary'),
		$minor: $container.find('#batch-minor'),
		$bot: $container.find('#batch-bot'),
		$preview: $container.find('#batch-preview'),
		$diff: $container.find('#batch-diff'),
		$revert: $container.find('#batch-revert'),
		$skip: $container.find('#batch-skip'),
		$save: $container.find('#batch-save')
	};
	if (!isBot()) {
		$container.find('#batch-bot, label[for="batch-bot"]').hide();
	}
	global.batch.$preview.button({icons: {secondary: 'ui-icon-document'}});
	global.batch.$diff.button({icons: {secondary: 'ui-icon-document-b'}});
	global.batch.$revert.button({icons: {secondary: 'ui-icon-arrowreturnthick-1-w'}}).addClass('ui-button-red');
	global.batch.$skip.button({icons: {secondary: 'ui-icon-close'}}).addClass('ui-button-red');
	global.batch.$save.button({icons: {secondary: 'ui-icon-check'}}).addClass('ui-button-green');
	global.$abort.click(function () {
		global.batch.$skip.click();
	});
}

function makeCheckInterface ($container) {
	var html = mw.html.element('button', {id: 'check-no'}, mw.msg('schnark-bandersnatch-check-no')) +
		mw.html.element('button', {id: 'check-ok'}, mw.msg('schnark-bandersnatch-check-ok'));
	$container.html(html);
	global.check = {
		$ok: $container.find('#check-ok'),
		$no: $container.find('#check-no')
	};
	global.check.$no.button({icons: {secondary: 'ui-icon-close'}}).addClass('ui-button-red');
	global.check.$ok.button({icons: {secondary: 'ui-icon-check'}}).addClass('ui-button-green');
	global.$abort.click(function () {
		global.check.$no.click();
	});
}

function makeAbortButton ($container) {
	var html = mw.html.element('button', {id: 'autoedit-abort'}, mw.msg('schnark-bandersnatch-abort'));
	$container.html(html);
	global.$abort = $container.find('#autoedit-abort');
	global.$abort.button({icons: {secondary: 'ui-icon-close'}}).addClass('ui-button-red');
}

function makeLog ($container) {
	var	ok = 'data:image/gif;base64,R0lGODlhEAAQAKECAAB3AAD/AP///////yH5BAEKAAIALAAAAAAQABAAAAInlI+pCrAcgnsHxEmtpPVyoWGIGEJTmWgbmkaS96hw7Ir09oE2txsFADs=',
		fail = 'data:image/gif;base64,R0lGODlhEAAQAKECAHcAAP8AAP///////yH5BAEKAAIALAAAAAAQABAAAAIyFC6peWAB3XoRwLjsPRfT/VVdIIUjOWlnma2TooJv3LHmWNJcbUp6zAKqbB9H48VAFAAAOw==',
		html = mw.html.element('ul', {}, '');
	$container.html(html);
	global.$log = $container.find('ul');
	mw.util.addCSS(
		'li.autoedit-success, li.autoedit-simulate {' +
			'list-style-image: url(' + ok + ');' +
		'}' +
		'li.autoedit-error {' +
			'list-style-image: url(' + fail + ');' +
		'}' +
		global.diffCSS()
	);
}

function makeInterface ($container, type) {
	$container.html('');
	var $div;
	if (type === 'batch') {
		$div = $('<div>').attr('id', 'autoedit-batch-container');
		makeBatchInterface($div);
		$container.append($div);
	}
	$div = $('<div>').attr('id', 'autoedit-log-container');
	makeLog($div);
	$container.append($div);
	if (type === 'check') {
		$div = $('<div>').attr('id', 'autoedit-check-container');
		makeCheckInterface($div);
		$container.append($div);
	}
}

function addTool ($table, title, desc, load) {
	var $tool, html, loadHtml;
	loadHtml = load ?
		mw.html.element('button', {}, mw.msg('schnark-bandersnatch-tool-load')) :
		mw.msg('schnark-bandersnatch-tool-noload');
	html = mw.html.element('td', {}, new mw.html.Raw(title)) +
		mw.html.element('td', {}, new mw.html.Raw(desc)) +
		mw.html.element('td', {}, new mw.html.Raw(loadHtml));
	$tool = $('<tr>' + html + '</tr>');
	if (load) {
		$tool.find('button').button({icons: {secondary: 'ui-icon-folder-open'}}).click(function () {
			$tool.find('button').remove();
			load();
		});
	}
	$table.append($tool);
}

function makeSearch ($area, $list) {
	if (!global.search) {
		return;
	}
	var html = '';
	html += mw.html.element('p', {}, mw.msg('schnark-bandersnatch-step-1-search-complex'));
	html += mw.html.element('div', {id: 'autoedit-search-help', 'class': 'mw-collapsed'}, new mw.html.Raw(global.searchHelp()));
	html += mw.html.element('label', {'for': 'autoedit-search'}, mw.msg('schnark-bandersnatch-step-1-search-query'));
	html += mw.html.element('textarea', {id: 'autoedit-search', rows: 3, cols: 80}, '');
	html += mw.html.element('button', {id: 'autoedit-search-submit'}, mw.msg('schnark-bandersnatch-step-1-search-submit'));
	$area.html(html);
	$('#autoedit-search-submit').button({icons: {primary: 'ui-icon-search'}}).click(function () {
		global.search($('#autoedit-search').val()).done(function (list) {
			$list.val($.trim(list.join('\n') + '\n' + $list.val()));
		}).fail(function (error) {
			$list.val(mw.msg('schnark-bandersnatch-step-1-search-error', error) + '\n\n' + $list.val());
		});
	});
}

function makeForm ($container) {
	var $arrowSteps, $tools,
		html =
		mw.html.element('ul', {id: 'autoedit-arrows'}, new mw.html.Raw(
			mw.html.element('li', {id: 'autoedit-page1-arrow'}, new mw.html.Raw('<div>' + mw.msg('schnark-bandersnatch-step-1-head') + '</div>')) +
			mw.html.element('li', {id: 'autoedit-page2-arrow'}, new mw.html.Raw('<div>' + mw.msg('schnark-bandersnatch-step-2-head') + '</div>')) +
			mw.html.element('li', {id: 'autoedit-page3-arrow'}, new mw.html.Raw('<div>' + mw.msg('schnark-bandersnatch-step-3-head') + '</div>'))
		)) +
		mw.html.element('div', {id: 'autoedit-pages'}, new mw.html.Raw(
			mw.html.element('div', {id: 'autoedit-page1'}, new mw.html.Raw(
				mw.html.element('div', {id: 'autoedit-search-area'}, new mw.html.Raw(
					mw.html.element('p', {}, mw.msg('schnark-bandersnatch-step-1-search-simple'))
				)) +
				(window.FileReader ?
					mw.html.element('p', {}, new mw.html.Raw(
						mw.msg('schnark-bandersnatch-step-1-xml',
							mw.html.element('a', {href: '#', id: 'autoedit-xml'}, mw.msg('schnark-bandersnatch-step-1-xml-read'))
						)
					)) : '') +
				mw.html.element('label', {'for': 'autoedit-titleList'}, mw.msg('schnark-bandersnatch-step-1-pages')) +
				mw.html.element('textarea', {id: 'autoedit-titleList', rows: 25, cols: 80}, '') +
				mw.html.element('button', {id: 'autoedit-page1-cont'}, mw.msg('schnark-bandersnatch-step-continue'))
			)) +
			mw.html.element('div', {id: 'autoedit-page2'}, new mw.html.Raw(
				mw.html.element('p', {}, mw.msg('schnark-bandersnatch-step-2-text')) +
				mw.html.element('label', {'for': 'autoedit-editCode'}, mw.msg('schnark-bandersnatch-step-2-code')) +
				mw.html.element('br', {}) +
				mw.html.element('code', {}, 'function (title, oldText) {') +
				mw.html.element('textarea', {id: 'autoedit-editCode', rows: 25, cols: 80}, 'return {text: oldText};') +
				mw.html.element('code', {}, '}') +
				mw.html.element('h3', {}, mw.msg('schnark-bandersnatch-step-2-tools')) +
				mw.html.element('table', {id: 'autoedit-tools'}, new mw.html.Raw(
					mw.html.element('hr', {}, new mw.html.Raw(
						'<th>' + mw.msg('schnark-bandersnatch-step-2-tools-tool') + '</th><th>' +
						mw.msg('schnark-bandersnatch-step-2-tools-use') + '</th><th>' +
						mw.msg('schnark-bandersnatch-step-2-tools-load') + '</th>')
					)
				)) +
				mw.html.element('h3', {}, mw.msg('schnark-bandersnatch-step-2-test')) +
				mw.html.element('div', {id: 'autoedit-test-container', 'class': 'mw-collapsed'}, new mw.html.Raw(
					mw.html.element('label', {'for': 'autoedit-test-title'}, mw.msg('schnark-bandersnatch-step-2-test-title')) +
					mw.html.element('input', {id: 'autoedit-test-title', size: 50, value: mw.msg('schnark-bandersnatch-step-2-test-title-default')}) +
					mw.html.element('br', {}) +
					mw.html.element('textarea', {id: 'autoedit-test-text', rows: 25, cols: 80}, '') +
					mw.html.element('button', {id: 'autoedit-test'}, mw.msg('schnark-bandersnatch-step-2-test-run'))
				)) +
				mw.html.element('button', {id: 'autoedit-page2-back'}, mw.msg('schnark-bandersnatch-step-back')) +
				mw.html.element('button', {id: 'autoedit-page2-cont'}, mw.msg('schnark-bandersnatch-step-continue'))
			)) +
			mw.html.element('div', {id: 'autoedit-page3'}, new mw.html.Raw(
				mw.html.element('p', {}, mw.msg('schnark-bandersnatch-step-3-text')) +
				mw.html.element('label', {'for': 'autoedit-defaultSummary'}, mw.msg('schnark-bandersnatch-step-3-summary')) +
				mw.html.element('br', {}) +
				mw.html.element('input', {id: 'autoedit-defaultSummary', size: 200, style: 'width: 100%'}) +
				mw.html.element('br', {}) +
				mw.html.element('input', {id: 'autoedit-defaultMinor', type: 'checkbox', checked: true}) +
				mw.html.element('label', {'for': 'autoedit-defaultMinor'}, mw.msg('schnark-bandersnatch-step-3-minor')) +
				' ' +
				mw.html.element('input', {id: 'autoedit-defaultBot', type: 'checkbox', checked: isBot()}) +
				mw.html.element('label', {'for': 'autoedit-defaultBot'}, mw.msg('schnark-bandersnatch-step-3-bot')) +
				mw.html.element('br', {}) +
				mw.html.element('label', {'for': 'autoedit-waitSeconds'}, mw.msg('schnark-bandersnatch-step-3-wait')) +
				mw.html.element('input', {id: 'autoedit-waitSeconds', value: 5, size: 2}) +
				mw.html.element('br', {}) +
				mw.html.element('label', {'for': 'autoedit-maxlagType'}, mw.msg('schnark-bandersnatch-step-3-maxlag')) +
				mw.html.element('select', {id: 'autoedit-maxlagType'}, new mw.html.Raw(
					mw.html.element('option', {value: 'ignore', selected: true}, mw.msg('schnark-bandersnatch-step-3-maxlag-ignore')) +
					mw.html.element('option', {value: 'default'}, mw.msg('schnark-bandersnatch-step-3-maxlag-5x5'))
				)) +
				mw.html.element('br', {}) +
				mw.html.element('label', {'for': 'autoedit-editType'}, mw.msg('schnark-bandersnatch-step-3-mode')) +
				mw.html.element('select', {id: 'autoedit-editType'}, new mw.html.Raw(
					mw.html.element('option', {value: 'simulate', selected: true}, mw.msg('schnark-bandersnatch-step-3-mode-simulate')) +
					mw.html.element('option', {value: 'batch'}, mw.msg('schnark-bandersnatch-step-3-mode-batch')) +
					mw.html.element('option', {value: 'check'}, mw.msg('schnark-bandersnatch-step-3-mode-check')) +
					mw.html.element('option', {value: 'auto'}, mw.msg('schnark-bandersnatch-step-3-mode-auto'))
				)) +
				mw.html.element('br', {}) +
				mw.html.element('button', {id: 'autoedit-page3-back'}, mw.msg('schnark-bandersnatch-step-back')) +
				mw.html.element('button', {id: 'autoedit-run'}, mw.msg('schnark-bandersnatch-step-go'))
			))
		));
	$container.html(html);
	if (!isBot()) {
		$container.find('#autoedit-defaultBot, label[for="autoedit-defaultBot"]').hide();
	}
	makeSearch($container.find('#autoedit-search-area'), $container.find('#autoedit-titleList'));
	$container.find('#autoedit-xml').click(function (e) {
		e.preventDefault();
		readXML($container.find('#autoedit-titleList'), $container.find('#autoedit-editCode'));
	});
	$container.find('#autoedit-page2-back').button({icons: {primary: 'ui-icon-triangle-1-w'}});
	$container.find('#autoedit-page3-back').button({icons: {primary: 'ui-icon-triangle-1-w'}});
	$container.find('#autoedit-page1-cont').button({icons: {secondary: 'ui-icon-triangle-1-e'}}).addClass('ui-button-green');
	$container.find('#autoedit-page2-cont').button({icons: {secondary: 'ui-icon-triangle-1-e'}}).addClass('ui-button-green');
	$container.find('#autoedit-run').button({icons: {secondary: 'ui-icon-check'}}).addClass('ui-button-green');
	$arrowSteps = $container.find('#autoedit-arrows').arrowSteps();
	$container.find('#autoedit-page2-back').click(function () {
		$container.find('#autoedit-pages > div').hide();
		$container.find('#autoedit-page1').show();
		$arrowSteps.arrowStepsHighlight('#autoedit-page1-arrow');
	}).click();
	$container.find('#autoedit-page1-cont, #autoedit-page3-back').click(function () {
		$container.find('#autoedit-pages > div').hide();
		$container.find('#autoedit-page2').show();
		$arrowSteps.arrowStepsHighlight('#autoedit-page2-arrow');
	});
	$container.find('#autoedit-page2-cont').click(function () {
		$container.find('#autoedit-pages > div').hide();
		$container.find('#autoedit-page3').show();
		$arrowSteps.arrowStepsHighlight('#autoedit-page3-arrow');
	});
	$tools = $container.find('#autoedit-tools');
	addTool($tools, mw.msg('schnark-bandersnatch-tool-replace'), mw.html.element('code', {}, mw.msg('schnark-bandersnatch-tool-replace-code')));
	addTool($tools, mw.msg('schnark-bandersnatch-tool-wstm'), mw.html.element('code', {}, mw.msg('schnark-bandersnatch-tool-wstm-code')), function () {
		var ready = false, config = {
			load: {
				inhibit: true,
				after: function () {
					libs.WikiSyntaxTextMod.api.load(function() {
						ready = true;
					});
				}
			}
		};
		$.extend(true, mw.libs, {WikiSyntaxTextMod: {config: config}});
		if (mw.libs.WikiSyntaxTextMod.api && mw.libs.WikiSyntaxTextMod.api.load) {
			config.load.after();
		} else {
			mw.loader.load('//en.wikipedia.org/w/index.php?title=User:PerfektesChaos/js/WikiSyntaxTextMod/r.js&action=raw&ctype=text/javascript&maxage=604800&smaxage=86400'); //[[Benutzer:PerfektesChaos/js/WikiSyntaxTextMod]]
		}
		mw.libs.doWSTM = function (alt, title) {
			if (ready) {
				mw.libs.WikiSyntaxTextMod.api.setContext(title); //FIXME Namensraum
				var neu = mw.libs.WikiSyntaxTextMod.api.textMod(alt); //evt. .api.edit ?
				if (neu) {
					alt = neu[0];
				}
			}
			return alt;
		};
	});
	addTool($tools, mw.msg('schnark-bandersnatch-tool-template'), mw.html.element('pre', {}, mw.msg('schnark-bandersnatch-tool-template-code')), function () {
		mw.loader.load('//de.wikipedia.org/w/index.php?title=Benutzer:Schnark/js/Template.js&action=raw&ctype=text/javascript&maxage=604800&smaxage=86400');
	});
	$container.find('#autoedit-test-container').makeCollapsible();
	$container.find('#autoedit-search-help').makeCollapsible();
	$container.find('#autoedit-test').button({icons: {secondary: 'ui-icon-gear'}}).click(function () {
		testCode($container.find('#autoedit-editCode'), $container.find('#autoedit-test-title'), $container.find('#autoedit-test-text'));
	});
}

function readXML ($titles, $code) {
	function fileOpen (callback) {
		var $input = $('<input type="file" />').hide().appendTo($('body'));
		$input.change(function () {
			var file = $input[0].files[0], reader = new FileReader();
			if (file) {
				reader.onload = function (e) {
					callback(e.target.result);
				};
				reader.readAsText(file, 'utf-8');
			}
			$input.remove();
		})[0].click();
	}
	function parseXML (content) {
		var $mediawiki = $($.parseXML(content)), titles = [];
		libs.xmldata = {};
		$mediawiki.find('page').each(function () {
			var $page = $(this), title, text;
			title = $page.find('title').text();
			text = $page.find('text').text();
			if (title) {
				libs.xmldata[title] = text;
				titles.push(title);
			}
		});
		$titles.val($.trim($titles.val() + '\n' + titles.join('\n')));
		$code.val('return {text: mw.libs.xmldata[title]};');
	}

	fileOpen(parseXML);
}

function initL10N (l10n, keep) {
	var i, chain = mw.language.getFallbackLanguageChain();
	keep = $.grep(mw.messages.get(keep), function (val) {
		return val !== null;
	});
	for (i = chain.length - 1; i >= 0; i--) {
		if (chain[i] in l10n) {
			mw.messages.set(l10n[chain[i]]);
		}
	}
	mw.messages.set(keep);
}

function init () {
	initL10N(l10n, ['diff', 'minoreditletter', 'boteditletter', 'article', 'pagehist']);

	global.diffCSS = libs.schnarkDiff.getCSS;
	global.diff = libs.schnarkDiff.htmlDiff;

	if (libs['search++']) {
		global.searchHelp = libs['search++'].getHelp;
		global.search = libs['search++'].queryByString;
	}

	document.title = mw.msg('schnark-bandersnatch-title');
	$('#firstHeading').text(mw.msg('schnark-bandersnatch-version', global.version));
	var $container = $('#bodyContent');
	makeForm($container);
	$('#autoedit-run').click(function () {
		var	titleList = $('#autoedit-titleList').val(),
			defaultSummary = $('#autoedit-defaultSummary').val(),
			defaultMinor = $('#autoedit-defaultMinor').prop('checked'),
			defaultBot = $('#autoedit-defaultBot').prop('checked'),
			waitSeconds = $('#autoedit-waitSeconds').val(),
			maxlagType = $('#autoedit-maxlagType :selected').val(),
			editCode = $('#autoedit-editCode').val(),
			editType = $('#autoedit-editType :selected').val(),
			$span = $('<span>').css('float', 'right');
		makeAbortButton($span);
		$('#firstHeading').before($span);
		makeInterface($container, editType);
		global.editFromForm (titleList, defaultSummary, defaultMinor, defaultBot, waitSeconds, maxlagType, editCode, editType, function () {
			$('#autoedit-batch-container, #autoedit-check-container').remove();
			global.$abort.remove();
		});
	});
}

global.init = init;

})();

if (mw.config.get('wgNamespaceNumber') === -1 && mw.config.get('wgTitle') === 'Bandersnatch') {
	mw.loader.using(['mediawiki.util', 'mediawiki.language', 'jquery.makeCollapsible', 'jquery.arrowSteps', 'jquery.ui.button'], function () {
		$(global.init);
	});
}

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