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.
/**<nowiki>
 *
 * This script is a fork of version 3.0.2 of JWB.js by Joeytje50, which is in turn
 * based on the downloadable AutoWikiBrowser.
 * 
 * IMPORTANT: this script will only run on the 'Project:AutoWikiBrowser/Script' page.
 * 
 * @licence
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 * http://www.gnu.org/copyleft/gpl.html
 */

/***** Start of the program *****/

// Comments are not part of the program itself, and are provided for clarification.
// Single-line comments are begun with double forward slashes (//), 
// but they don't have to begin at the start of a line.
// Multi-line comments are included between /* and */

/* 
I will use comments to help you more easily understand the program, even if you
are an absolute beginner. One problem with bare scripts is that they are in what
is essentially a cryptic foreign language, making it impossible to look up structures
made of symbols if you don't already know what they are called. Many of the comments 
in this program will identify programming structures by name, the first time they are
encountered, to assist you in looking them up to learn them. Other comments will 
explain what the code is doing and how.

Why? To help you become a (better) JavaScript programmer more easily, and with less 
frustration, so you can write new scripts and improve existing scripts (like this one) 
to make Wikipedia even better.

If you have any questions about this program, please post them on this script's talk
page; it is set up as a workshop, with sections for various purposes. The discussion
section is at the end of that page. Please post your questions in the discussion 
section there. Thank you.).

If you have questions about writing Wikipedia user scripts in general, please post them 
on my user talk page.  
*/

// Create global namespace called "AWE", the main global object for the script.
/*
Variables declared outside any functions are global variables, and are in the "global namespace"
(window.).  To avoid cluttering the default global namespace (window.) with this program's variables, 
we set them as properties of a single object (AWE). When an object is used to organize related 
variables in this manner, it is referred to as a "namespace", and if it is used to group the global 
variables in a program, it is that program's "global namespace". 

Objects are included between {} braces (though this is not the only use for braces). When there is 
nothing in there, it is an empty object. In this case, the empty object is assigned to the variable 
window.AWE, and AWE is referred to as an object from then on. We will be assigning properties to the 
object AWE, using dot notation, throughout the program. A "dot" is a period (.). An example of dot 
notation is "AWE.allowed" (read as "AWE dot allowed"), where the variable "allowed" is a property 
of the object AWE.

Statements, such as the one below, always must be ended with a semi-colon.

And this marks the end of the comment:
*/ 

window.AWE = {};

/***** User verification *****/

/* 
Below this comment is an anonymous IIFE (immediately invoked function expression). The body of a 
function is included within {} braces. "Function" is another name for "subroutine"; functions are 
essentially programs within a program. Named functions are used later in the program. Anonymous 
functions are unnamed.
*/

(function() {

	/*
	We are now inside a function. The statement below this long comment is an "if" statement,
	a type of conditional. If the condition within paretheses can be verified, then the 
	instructions within its braces (curly brackets) are executed.

	+, !==, ||, and ===, are operators. 

	+ (the plus sign) is the arithmetic operator used for addition, but when used with strings, 
	it is the string concatenation operator, for connecting strings together into one.

	Text strings are included within either quote marks or double quote marks, though, that is not the 
	only use for quote marks. 

	Text strings can also be stored inside variables, and raw text strings and variables can be 
	concatenated with raw text strings or other string variables, using the plus (+) sign.

	!== is the "Not strictly equal to" comparison operator.

	|| is the logical OR operator.

	=== is the "Strictly equal to" comparison operator.

	wgCanonicalNamespace is 

	wgTitle is 

	mw.config.get 

	Assuming you are in the English Wikipedia, the if statement below means "If the 
	namespace plus the page title of the current page is not 'Wikipedia:AutoWikiBrowser/Script', 
	or the variable AWE.allowed is set to 'false', or the user is not logged in, run the part 
	between the braces." That part means "set the variable AWE.allowed to 'false', and then return 
	(which in this case, XXXXXXends the programXXXXXXXX).

	And this marks the end of the comment:
	*/

	if (mw.config.get('wgCanonicalNamespace')+':'+mw.config.get('wgTitle') !== 'Project:AutoWikiBrowser/Script' || AWE.allowed === false || mw.config.get('wgUserName') === null) {
		AWE.allowed = false;
		return;
	}
	mw.loader.load('//en.wikipedia.org/w/index.php?title=User:The_Transhumanist/AWE.css&action=raw&ctype=text/css', 'text/css');
	mw.loader.load('mediawiki.action.history.diff');
	
	$.getScript('//en.wikipedia.org/w/index.php?title=User:The_Transhumanist/AWE.js/i18n.js&action=raw&ctype=text/javascript', function() {
		if (AWE.allowed === true) {
			AWE.init(); //init if verification has already returned true
		} else if (AWE.allowed === false) {
			alert(AWE.msg('not-on-list'));
		}
	});
	
	//RegEx Typo Fixing
	$.getScript('//en.wikipedia.org/w/index.php?title=User:The_Transhumanist/AWE.js/RETF.js&action=raw&ctype=text/javascript', function() {
			$('#refreshRETF').click(RETF.load);
	});

	(new mw.Api()).get({
		action: 'query',
		titles: 'Project:AutoWikiBrowser/CheckPage',
		prop: 'revisions',
		meta: 'userinfo|siteinfo',
		rvprop: 'content',
		rvlimit: 1,
		uiprop: 'groups',
		siprop: 'namespaces',
		indexpageids: true,
		format: 'json',
	}).done(function(response) {
		if (response.error) {
			alert('API error: ' + response.error.info);
			AWE = false; //preventing further access. No verification => no access.
			return;
		}
		AWE.ns = response.query.namespaces; //saving for later
		
		AWE.username = response.query.userinfo.name; //preventing any "hacks" that change wgUserName or mw.config.wgUserName
		var groups = response.query.userinfo.groups;
		var page = response.query.pages[response.query.pageids[0]];
		var users, bots;
		if (response.query.pageids[0] !== '-1' && /<!--\s*enabledusersbegins\s*-->/.test(page.revisions[0]['*'])) {
			var cont = page.revisions[0]['*'];
			users = cont.substring(
				cont.search(/<!--\s*enabledusersbegins\s*-->/),
				cont.search(/<!--\s*enabledusersends\s*-->/)
			).split('\n');
			if (/<!--\s*enabledbots\s*-->/.test(cont)) {
				bots = cont.substring(
					cont.search(/<!--\s*enabledbots\s*-->/),
					cont.search(/<!--\s*enabledbotsends\s*-->/)
				).split('\n');
			} else bots = [];
			var i=0;
			while (i<users.length) {
			    if (users[i].charAt(0) !== '*') {
			    	users.splice(i,1);
			    } else {
			    	users[i] = $.trim(users[i].substr(1));
			    	i++;
			    }
			}
			i=0;
			while (i<bots.length) {
			    if (bots[i].charAt(0) !== '*') {
			    	bots.splice(i,1);
			    } else {
			    	bots[i] = $.trim(bots[i].substr(1));
			    	i++;
			    }
			}
		} else {
			users = false; //fallback when page doesn't exist
		}
		AWE.bot = groups.indexOf('bot') !== -1 && (users === false || bots.indexOf(AWE.username) !== -1);
		AWE.sysop = groups.indexOf('sysop') !== -1;
		if (AWE.username === "Joeytje50" && response.query.userinfo.id === 13299994) {//TEMP: Dev full access to entire interface.
			AWE.bot = true;
			users.push("Joeytje50");
		}
		if (AWE.sysop || response.query.pageids[0] === '-1' || users.indexOf(AWE.username) !== -1 || users === false) {
			AWE.allowed = true;
			if (AWE.messages.en) AWE.init(); //init if messages have already loaded
		} else {
			if (AWE.messages.en) {
				//run this after messages have loaded, so the message that shows is in the user's language
				alert(AWE.msg('not-on-list'));
			}
			AWE = false; //prevent further access
		}
	}).fail(function(xhr, error) {
		alert(AWE.msg('verify-error') + '\n' + error);
		AWE = false; //preventing further access. No verification => no access.
	});
})();

/***** Global object/variables *****/

var objs = ['page', 'api', 'fn', 'pl', 'messages', 'setup', 'settings', 'ns'];
for (var i=0;i<objs.length;i++) {
	AWE[objs[i]] = {};
}
AWE.summarySuffix = ' (via AWE)';
if (document.location.hostname == 'en.wikipedia.org') AWE.summarySuffix = ' (via [[WP:AWE]])'
AWE.lang = mw.config.get('wgUserLanguage');
AWE.index_php = mw.config.get('wgScript');
AWE.isStopped = true;
AWE.tooltip = window.tooltipAccessKeyPrefix || '';
AWE.configext = 'js';
if (document.location.hostname.split('.').slice(-2).join('.') == 'wikia.com') {
	//it makes no sense, but Wikia does not allow users to create .js subpages of their userpage.
	//Because the settings should REALLY be protected from vandalism automatically, the backup is .css
	//even though this has nothing to do with CSS.
	AWE.configext = 'css';
}
AWE.settingspage = 'AWE';
if (window.hasOwnProperty('AWESETTINGS')) {
	AWE.settingspage = AWESETTINGS;
	delete window.AWESETTINGS; //clean up the global variable
}


/***** API functions *****/

//Main template for API calls
AWE.api.call = function(data, callback, onerror) {
	data.format = 'json';
	if (data.action !== 'query') data.bot = true;
	$.ajax({
		data: data,
		dataType: 'json',
		url: mw.config.get('wgScriptPath') + '/api.php',
		type: 'POST',
		success: function(response) {
			if (response.error) {
				alert('API error: ' + response.error.info);
				AWE.stop();
			} else {
				callback(response);
			}
		},
		error: function(xhr, error) {
			alert('AJAX error: ' + error);
			AWE.stop();
			if (onerror) onerror();
		}
	});
};

//Get page diff, and process it for more interactivity
AWE.api.diff = function(callback) {
	AWE.status('diff');
	var editBoxInput = $('#editBoxArea').val();
	var redirects = $('input.redirects:checked').val()==='follow'?'1':'0';
	var data = {
		'action': 'query',
		'prop': 'info|revisions',
		'indexpageids': true,
		'titles': AWE.page.name,
		'rvlimit': '1',
		'rvdifftotext': editBoxInput,
		'redirects': redirects
	};
	AWE.api.call(data, function(response) {
		var pageExists = response.query.pageids[0] !== '-1';
		var diff;
		if (pageExists) {
			var diffpage = response.query.pages[response.query.pageids[0]];
			diff = diffpage.revisions[0].diff['*'];
			if (diff === '') {
				diff = '<h2>'+AWE.msg('no-changes-made')+'</h2>';
			} else {
				diff = '<table class="diff">'+
					'<colgroup>'+
						'<col class="diff-marker">'+
						'<col class="diff-content">'+
						'<col class="diff-marker">'+
						'<col class="diff-content">'+
					'</colgroup>'+
					'<tbody>'+diff+'</tbody></table>';
			}
		} else {
			diff = '<span style="font-weight:bold;color:red;">'+AWE.msg('page-not-exists')+'</span>';
		}
		$('#resultWindow').html(diff);
		$('.diff-lineno').each(function() {
			$(this).parent().attr('data-line',parseInt($(this).html().match(/\d+/)[0])-1).addClass('lineheader');
		});
		$('table.diff tr').each(function() { //add data-line attribute to every line, relative to the previous one. Used for click event.
			if (!$(this).next().is('[data-line]') && !$(this).next().has('td.diff-deletedline + td.diff-empty')) {
				$(this).next().attr('data-line',parseInt($(this).data('line'))+1);
			} else if ($(this).next().has('td.diff-deletedline + td.diff-empty')) {
				$(this).next().attr('data-line',$(this).data('line')); //copy over current data-line for deleted lines to prevent them from messing up counting.
			}
		});
		AWE.status('done', true);
		if (typeof(callback) === 'function') {
			callback();
		}
	});
};

//Retrieve page contents/info, process them, and store information in AWE.page object.
AWE.api.get = function(pagename) {
	AWE.pageCount();
	if (!AWE.list[0] || AWE.isStopped) {
		return AWE.stop();
	}
	if (pagename === '#PRE-PARSE-STOP') {
		var curval = $('#articleList').val();
		$('#articleList').val(curval.substr(curval.indexOf('\n') + 1));
		$('#preparse').prop('checked', false);
		AWE.stop();
		return;
	}
	var redirect = $('input.redirects:checked').val();
	var data = {
		'action': 'query',
		'prop': 'info|revisions',
		'inprop': 'watched',
		'intoken': 'edit|delete|protect|move|watch',
		'titles': pagename,
		'rvprop': 'content|timestamp|ids',
		'rvlimit': '1',
		'indexpageids': true,
		'meta': 'userinfo',
		'uiprop': 'hasmsg'
	};
	if (redirect=='follow'||redirect=='skip') data.redirects = true;
	if (AWE.sysop) {
		data.list = 'deletedrevs';
		data.drprop = 'token';
	}
	AWE.status('load-page');
	AWE.api.call(data, function(response) {
		if (response.query.userinfo.hasOwnProperty('messages')) {
			var view = mw.config.get('wgScriptPath') + '?title=Special:MyTalk';
			var viewNew = view + '&diff=cur';
			AWE.status(
				'<span style="color:red;font-weight:bold;">'+
					AWE.msg('status-newmsg', 
						'<a href="'+view+'" target="_blank">'+AWE.msg('status-talklink')+'</a>',
						'<a href="'+viewNew+'" target="_blank">'+AWE.msg('status-difflink')+'</a>')+
				'</span>', true);
			alert(AWE.msg('new-message'));
			AWE.stop();
			return;
		}
		AWE.page = response.query.pages[response.query.pageids[0]];
		AWE.page.name = AWE.list[0].split('|')[0];
	 	var varOffset = AWE.list[0].indexOf('|') !== -1 ? AWE.list[0].indexOf('|') + 1 : 0;
	 	AWE.page.pagevar = AWE.list[0].substr(varOffset);
		AWE.page.content = AWE.page.revisions ? AWE.page.revisions[0]['*'] : '';
		AWE.page.exists = !response.query.pages["-1"];
		AWE.page.deletedrevs = response.query.deletedrevs;
		AWE.page.watched = AWE.page.hasOwnProperty('watched');
		if (response.query.redirects) {
			AWE.page.name = response.query.redirects[0].to;
		}
		var newContent = AWE.replace(AWE.page.content);
		if (AWE.stopped === true) return;
		AWE.status('done', true);
		var containRegex = $('#containRegex').prop('checked'), containFlags = $('#containFlags').val();
		var skipContains = containRegex ? new RegExp($('#skipContains').val(), containFlags) : $('#skipContains').val();
		var skipNotContains = containRegex ? new RegExp($('#skipNotContains').val(), containFlags) : $('#skipContains').val();
		if (
			($('#skipNoChange').prop('checked') && AWE.page.content === newContent) || //skip if no changes are made
			($('#skipContains').val() && AWE.page.content.match(skipContains)) ||
			($('#skipNotContains').val() && !AWE.page.content.match(skipNotContains)) ||
			($('#exists-no').prop('checked') && !AWE.page.exists) ||
			($('#exists-yes').prop('checked') && AWE.page.exists) ||
			(redirect==='skip' && response.query.redirects) // variable  redirect  is defined outside this callback function.
		) {
			AWE.log('skip', AWE.page.name);
			return AWE.next();
		} else {
			$('#editBoxArea').val(newContent);
			$('#currentpage').html(AWE.msg('editbox-currentpage', AWE.page.name, encodeURIComponent(AWE.page.name)));
			if ($('#preparse').prop('checked')) {
				$('#articleList').val($.trim($('#articleList').val()) + '\n' + AWE.list[0]); //move current page to the bottom
				AWE.next();
				return;
			} else if (AWE.bot && $('#autosave').prop('checked')) {
				AWE.api.diff(function() {
					//timeout will take #throttle's value * 1000, if it's a number above 0. Currently defaults to 0.
					setTimeout(AWE.api.submit, Math.max(+$('#throttle').val() || 0, 0) * 1000, AWE.page.name);
				});
			} else {
				AWE.api.diff();
			}
		}
		AWE.updateButtons();
	});
};

//Some functions with self-explanatory names:
AWE.api.submit = function(page) {
	AWE.status('submit');
	var summary = $('#summary').val();
	if ($('#summary').parent('label').hasClass('viaAWE')) summary += AWE.summarySuffix;
	if ((typeof page === 'text' && page !== AWE.page.name) || $('#currentpage a').html().replace(/&amp;/g, '&') !== AWE.page.name) {
		console.log(page, AWE.page.name, $('#currentpage a').html())
		AWE.stop();
		alert(AWE.msg('autosave-error', AWE.msg('tab-log')));
		$('#currentpage').html(AWE.msg('editbox-currentpage', ' ', ' '));
		return;
	}
	var data = {
		'title': AWE.page.name,
		'summary': summary,
		'action': 'edit',
		'basetimestamp': AWE.page.revisions ? AWE.page.revisions[0].timestamp : '',
		'token': AWE.page.edittoken,
		'text': $('#editBoxArea').val(),
		'watchlist': $('#watchPage').val()
	};
	if ($('#minorEdit').prop('checked')) data.minor = true;
	AWE.api.call(data, function(response) {
		AWE.log('edit', response.edit.title, response.edit.newrevid);
		AWE.status('done', true);
		AWE.next();
	});
};
AWE.api.preview = function() {
	AWE.status('preview');
	AWE.api.call({
		'title': AWE.page.name,
		'action': 'parse',
		'text': $('#editBoxArea').val()
	}, function(response) {
		$('#resultWindow').html(response.parse.text['*']);
		$('#resultWindow div.previewnote').remove();
		AWE.status('done', true);
	});
};
AWE.api.move = function() {
	AWE.status('move');
	var topage = $('#moveTo').val().replace(/\$x/gi, AWE.page.pagevar);
	var summary = $('#summary').val();
	if ($('#summary').parent('label').hasClass('viaAWE')) summary += AWE.summarySuffix;
	var data = {
		'action':'move',
		'from': AWE.page.name,
		'to': topage,
		'token': AWE.page.movetoken,
		'reason': summary,
		'ignorewarnings': 'yes'
	};
	if ($('#moveTalk').prop('checked')) data.movetalk = true;
	if ($('#moveSubpage').prop('checked')) data.movesubpages = true;
	if ($('#suppressRedir').prop('checked')) data.noredirect = true;
	AWE.api.call(data, function(response) {
		AWE.log('move', response.move.from, reponse.move.to);
		AWE.status('done', true);
		if (!$('#moveTo').val().match(/\$x/i)) $('#moveTo').val('')[0].focus(); //clear entered move-to pagename if it's not based on the pagevar
		AWE.next(topage);
	});
};
AWE.api.delete = function() {
	AWE.status(($('#deletePage').is('.undelete') ? 'un' : '') + 'delete');
	var summary = $('#summary').val();
	if ($('#summary').parent('label').hasClass('viaAWE')) summary += AWE.summarySuffix;
	var undeltoken = AWE.page.deletedrevs && AWE.page.deletedrevs[0] ? AWE.page.deletedrevs[0].token : '';
	AWE.api.call({
		'action': (!AWE.page.exists ? 'un' : '') + 'delete',
		'title': AWE.page.name,
		'token': AWE.page.exists ? AWE.page.deletetoken : undeltoken,
		'reason': summary
	}, function(response) {
		AWE.log((!AWE.page.exists ? 'un' : '') + 'delete', (response.delete||response.undelete).title);
		AWE.status('done', true);
		AWE.next(response.undelete && response.undelete.title);
	});
};
AWE.api.protect = function() {
	AWE.status('protect');
	var summary = $('#summary').val();
	if ($('#summary').parent('label').hasClass('viaAWE')) summary += AWE.summarySuffix;
	var editprot = $('#editProt').val();
	var moveprot = $('#moveProt').val();
	AWE.api.call({
		'action':'protect',
		'title': AWE.page.name,
		'token': AWE.page.protecttoken,
		'reason': summary,
		'expiry': $('#protectExpiry').val()!==''?$('#protectExpiry').val():'infinite',
		'protections': (AWE.page.exists?'edit='+editprot+'|move='+moveprot:'create='+editprot)
	}, function(response) {
		var protactions = '';
		var prots = response.protect.protections;
		for (var i=0;i<prots.length;i++) {
			if (typeof prots[i].edit == 'string') {
				protactions += ' edit: '+(prots[i].edit?prots[i].edit:'all');
			} else if (typeof prots[i].move == 'string') {
				protactions += ' move: '+(prots[i].move?prots[i].move:'all');
			} else if (typeof prots[i].create == 'string') {
				protactions += ' create: '+(prots[i].create?prots[i].create:'all');
			}
		}
		protactions += ' expires: '+prots[0].expiry;
		AWE.log('protect', response.protect.title, protactions);
		AWE.status('done', false);
		AWE.next(response.protect.title);
	});
};

AWE.api.watch = function() {
	AWE.status('watch');
	var data = {
		'action':'watch',
		'title':AWE.page.name,
		'token':AWE.page.watchtoken
	};
	if (AWE.page.watched) data.unwatch = true;
	AWE.api.call(data, function(response) {
		AWE.status('<span style="color:green;">'+
			AWE.msg('status-watch-'+(AWE.page.watched ? 'removed' : 'added'), "'"+AWE.page.name+"'")+
		'</span>', true);
		AWE.page.watched = !AWE.page.watched;
		$('#watchNow').html( AWE.msg('watch-' + (AWE.page.watched ? 'remove' : 'add')) );
	});
};

/***** Pagelist functions *****/

AWE.pl.list = [];
AWE.pl.iterations = 0;

AWE.pl.stop = function() {
	AWE.pl.iterations = 0;
	$('#pagelistPopup [disabled]:not(fieldset [disabled]), #pagelistPopup legend input').prop('disabled', false);
	$('#pagelistPopup legend input').trigger('change');
	$('#pagelistPopup button img').remove();
}

AWE.pl.getNSpaces = function() {
	var list = $('#pagelistPopup [name="namespace"]')[0];
	if (list.selectedOptions.length == list.options.length) {
		return ''; //return empty string if every namespace is selected; this will make the request default to having no filter
	} else {
		return $('#pagelistPopup [name="namespace"]').val().join('|'); //.val() returns an array of selected options.
	}
};

AWE.pl.getList = function(abbrs, lists, data) {
	$('#pagelistPopup button, #pagelistPopup input, #pagelistPopup select').prop('disabled', true);
	AWE.pl.iterations++;
	data.action = 'query';
	var nspaces = AWE.pl.getNSpaces();
	for (var i=0;i<abbrs.length;i++) {
		if (nspaces) data[abbrs[i]+'namespace'] = nspaces;
		data[abbrs[i]+'limit'] = 'max';
	}
	if (lists.indexOf('links') !== -1) {
		data.prop = 'links';
	}
	data.list = lists.join('|');
	AWE.api.call(data, function(response) {
		var maxiterate = 100; //allow up to 100 consecutive requests at a time to avoid overloading the server.
		if (!response.query) response.query = {};
		if (response.watchlistraw) response.query.watchlistraw = response.watchlistraw; //adding some consistency
		var plist = [];
		if (response.query.pages) {
			var links;
			for (var id in response.query.pages) {
				links = response.query.pages[id].links;
				for (var i=0;i<links.length;i++) {
					plist.push(links[i].title);
				}
			}
		}
		for (var l in response.query) {
			if (l === 'pages') continue;
			for (var i=0;i<response.query[l].length;i++) {
				plist.push(response.query[l][i].title);
			}
		}
		//add the result to the pagelist immediately, as opposed to saving it all up and adding in 1 go like AWB does
		$('#articleList').val($.trim($('#articleList').val()) + '\n' + plist.join('\n'));
		AWE.pageCount();
		var cont = response.continue;
		console.log("Continue",AWE.pl.iterations, cont);
		if (cont && AWE.pl.iterations <= maxiterate) {
			var lists = [];
			if (response.query) { //compatibility with the code I wrote for the old query-continue. TODO: make this unnecessary?
				for (var list in response.query) {
					lists.push(list); //add to the new array of &list= values
				}
			}
			var abbrs = [];
			for (var abbr in cont) {
				data[abbr] = cont[abbr]; //add the &xxcontinue= value to the data
				if (abbr != 'continue') {
					abbrs.push(abbr.replace('continue','')); //find out what xx is and add it to the list of abbrs
				}
			}
			AWE.pl.getList(abbrs, lists, data); //recursive function to get every page of a list
		} else {
			if (AWE.pl.iterations > maxiterate) {
				AWE.status('pl-over-lim', true);
			} else {
				AWE.status('done', true);
			}
			AWE.pl.stop();
		}
	}, function() { //on error, simply reset and let the user work with what he has
		AWE.status('done', true);
		AWE.pl.stop();
	});
};

//AWE.pl.getList(['wr'], ['watchlistraw'], {}) for watchlists
AWE.pl.generate = function() {
	var $fields = $('#pagelistPopup fieldset').not('[disabled]');
	var spinner = '<img src="//upload.wikimedia.org/wikipedia/commons/d/de/Ajax-loader.gif" width="15" height="15" alt="'+AWE.msg('status-alt')+'"/>';
	$('#pagelistPopup').find('button[type="submit"]').append(spinner);
	var abbrs = [], lists = [], data = {'continue': ''};
	$fields.each(function() {
		var list = $(this).find('legend input').attr('name');
		var abbr;
		if (list === 'linksto') { //Special case since this fieldset features 3 merged lists in 1 fieldset
			if (!$('[name="title"]').val()) return;
			$('[name="backlinks"], [name="embeddedin"], [name="imageusage"]').filter(':checked').each(function() {
				var val = this.value;
				abbrs.push(val);
				lists.push(this.name);
				data[val+'title'] = $('[name="title"]').val();
				data[val+'filterredir'] = $('[name="filterredir"]:checked').val();
				if ($('[name="redirect"]').prop('checked')) data[val+'redirect'] = true;
			});
		} else { //default input system
			abbr = $(this).find('legend input').val();
			lists.push(list);
			abbrs.push(abbr);
			$(this).find('input').not('legend input').each(function() {
				if ((this.type === 'checkbox' || this.type === 'radio') && this.checked === false) return;
				if ($(this).is('[name="cmtitle"]')) {
					//making sure every page has a Category: prefix, in case the user left it out
					var newval = $(this).val().replace(new RegExp(AWE.ns[14]['*']+':', 'gi'), '').split('|')[0];
					$(this).val(AWE.ns[14]['*']+':'+newval);
				}
				var name = this.name;
				var val = this.value;
				if (data.hasOwnProperty(name)) {
					data[name] += '|'+val;
				} else {
					data[name] = val;
				}
			});
			console.log(abbrs, lists, data);
		}
	});
	if (abbrs.length) AWE.pl.getList(abbrs, lists, data);
};

/***** Setup functions *****/

AWE.setup.save = function(name) {
	name = name || prompt(AWE.msg('setup-prompt', AWE.msg('setup-prompt-store')), $('#loadSettings').val());
	if (name === null) return;
	var self = AWE.settings[name] = {
		string: {},
		bool: {},
		replaces: []
	};
	//inputs with a text value
	$('textarea, input[type="text"], input[type="number"], select').not('.replaces input, #editBoxArea, #settings *').each(function() {
		if (typeof $(this).val() == 'string') { 
			self.string[this.id] = this.value.replace(/\n{2,}/g,'\n');
		} else {
			self.string[this.id] = $(this).val();
		}
	});
	self.replaces = [];
	$('.replaces').each(function() {
		if ($(this).find('.replaceText').val() || $(this).find('.replaceWith').val()) {
			self.replaces.push({
				replaceText: $(this).find('.replaceText').val(),
				replaceWith: $(this).find('.replaceWith').val(),
				useRegex: $(this).find('.useRegex').prop('checked'),
				regexFlags: $(this).find('.regexFlags').val(),
				ignoreNowiki: $(this).find('.ignoreNowiki').prop('checked')
			});
		}
	});
	$('input[type="radio"], input[type="checkbox"]').not('.replaces input').each(function() {
		self.bool[this.id] = this.checked;
	});
	if (!$('#loadSettings option[value="'+name+'"]').length) {
		$('#loadSettings').append('<option value="'+name+'">'+name+'</option>');
	}
	$('#loadSettings').val(name);
	console.log(self);
};

AWE.setup.apply = function(name) {
	name = name && AWE.settings[name] ? name : 'default';
	var self = AWE.settings[name];
	$('#loadSettings').val(name);
	$('.replaces + .replaces').remove(); //reset find&replace inputs
	$('.replaces input[type="text"]').val('');
	$('.useRegex').each(function() {this.checked = false;});
	$('#pagelistPopup legend input').trigger('change'); //fix checked state of pagelist generating inputs
	for (var a in self.string) {
		$('#'+a).val(self.string[a]);
	}
	for (var b in self.bool) {
		$('#'+b).prop('checked', self.bool[b]);
	}
	var cur;
	for (var c=0;c<self.replaces.length;c++) {
		if ($('.replaces').length <= c) $('#moreReplaces')[0].click();
		cur = self.replaces[c];
		for (var d in cur) {
			if (cur[d] === true || cur[d] === false) {
				$('.replaces').eq(c).find('.'+d).prop('checked', cur[d]);
			} else {
				$('.replaces').eq(c).find('.'+d).val(cur[d]);
			}
		}
	}
	$('.useRegex, #containRegex,'+
	  '#pagelistPopup legend input,'+
	  '#viaAWE').trigger('change'); //reset disabled inputs
};

AWE.setup.getObj = function() {
	var settings = [];
	for (var i in AWE.settings) {
		if (i != '_blank') {
			settings.push('"' + i + '": ' + JSON.stringify(AWE.settings[i]));
		}
	}
	return '{\n\t' + settings.join(',\n\t') + '\n}';
};

AWE.setup.submit = function() {
	var name = prompt(AWE.msg('setup-prompt', AWE.msg('setup-prompt-save')), $('#loadSettings').val());
	if (name === null) return;
	if ($.trim(name) === '') name = 'default';
	AWE.setup.save(name);
	AWE.status('setup-submit');
	AWE.api.call({
		'title': 'User:'+AWE.username+'/'+AWE.settingspage+'-settings.'+AWE.configext,
		'summary': AWE.msg(['setup-summary', mw.config.get('wgContentLanguage')]),
		'action': 'edit',
		'token': AWE.setup.edittoken,
		'text': AWE.setup.getObj(),
		'minor': true
	}, function(response) {
		AWE.status('done', true);
	});
};

//TODO: use blob uri
AWE.setup.download = function() {
	var name = prompt(AWE.msg('setup-prompt', AWE.msg('setup-prompt-save')), $('#loadSettings').val());
	if (name === null) return;
	if ($.trim(name) === '') name = 'default';
	AWE.setup.save(name);
	AWE.status('setup-dload');
	var url = 'data:application/json;base64,' + btoa(AWE.setup.getObj());
	var elem = $('#download-anchor')[0];
	if (elem.hasOwnProperty('download')) { //use download attribute when possible, for its ability to specify a filename
		elem.href = url;
		elem.click();
		setTimeout(function() {elem.removeAttribute('href');}, 2000);
	} else { //fallback to iframes for browsers with no support for download="" attributes
		elem = $('#download-iframe')[0];
		elem.src = url.replace('application/json', 'application/octet-stream');
		setTimeout(function() {elem.removeAttribute('src');}, 2000);
	}
	AWE.status('done', true);
};

AWE.setup.import = function(e) {
	e.preventDefault();
	file = (e.dataTransfer||this).files[0];
	if ($(this).is('#import')) { //reset input
		this.outerHTML = this.outerHTML;
		$('#import').change(AWE.setup.import);
	}
	if (!window.hasOwnProperty('FileReader')) {
		alert(AWE.msg('old-browser'));
		AWE.status('old-browser', '<a target="_blank" href="'+AWE.index_php+'?title=Special:MyPage/'+AWE.settingspage+'-settings.'+AWE.configext+'">/'+AWE.settingspage+'-settings.'+AWE.configext+'</a>');
		return;
	}
	if (file.name.split('.').pop().toLowerCase() !== 'json') {
		alert(AWE.msg('not-json'));
		return;
	}
	AWE.status('Processing file');
	var reader = new FileReader();
	reader.readAsText(file);
	reader.onload = function(e) {
		AWE.status('done', true);
		try {
			//Exclusion regex based on http://stackoverflow.com/a/23589204/1256925
			//Removes all JS comments from the file, except when they're between quotes.
			var data = JSON.parse(reader.result.replace(/("[^"]*")|(\/\*[\w\W]*\*\/|\/\/[^\n]*)/g, function(match, g1, g2) {
				if (g1) return g1;
			}));
		} catch(e) {
			alert(AWE.msg('json-err', e.message, AWE.msg('json-err-upload')));
			console.log(e); //also log the error for further info
			return;
		}
		AWE.setup.extend(data);
	};
	
	AWE.status('Processing file');
};

AWE.setup.load = function() {
	AWE.status('setup-load');
	AWE.api.call({
		'action': 'query',
		'titles': 'User:' + (AWE.username||mw.config.get('wgUserName')) + '/'+AWE.settingspage+'-settings.'+AWE.configext,
		'prop': 'info|revisions',
		'intoken': 'edit',
		'rvprop': 'content',
		'indexpageids': true
	}, function(response) {
		AWE.status('done', true);
		if (AWE === false) return; //user is not allowed to use AWE
		var firstrun =  AWE.setup.edittoken ? false : true;
		var page = response.query.pages[response.query.pageids[0]];
		AWE.setup.edittoken = page.edittoken;
		if (response.query.pageids[0] === '-1') {
			if (AWE.allowed && firstrun) AWE.setup.save('default'); //this runs when this callback returns after the init has loaded.
			return;
		}
		var data = page.revisions[0]['*'];
		if (!data) {
			if (AWE.allowed && firstrun) AWE.setup.save('default'); //this runs when this callback returns after the init has loaded.
			return;
		}
		try {
			data = JSON.parse(data);
		} catch(e) {
			alert(AWE.msg('json-err', e.message, AWE.msg('json-err-page', AWE.settingspage)) || 'JSON error:\n'+e.message);
			AWE.setup.save('default');
			return;
		}
		AWE.setup.extend(data);
	});
};

AWE.setup.extend = function(obj) {
	$.extend(AWE.settings, obj);
	if (!AWE.settings.hasOwnProperty('default')) {
		AWE.setup.save('default');
	}
	for (var i in AWE.settings) {
		if ($('#loadSettings').find('option[value="'+i+'"]').length) continue;
		$('#loadSettings').append('<option value="'+i+'">'+i+'</option>');
	}
	AWE.setup.apply($('#loadSettings').val());
};

AWE.setup.delete = function() {
	var name = $('#loadSettings').val();
	if (name === '_blank') return alert(AWE.msg('setup-delete-blank'));
	var temp = {};
	temp[name] = AWE.settings[name];
	AWE.setup.temp = $.extend({}, temp);
	delete AWE.settings[name];
	$('#loadSettings').val('default');
	if (name === 'default') {
		AWE.setup.apply('_blank');
		AWE.setup.save('default');
		AWE.status(AWE.msg('status-del-default', '<a href="javascript:AWE.setup.undelete();">'+AWE.msg('status-del-undo')+'</a>'), true);
	} else {
		$('#loadSettings').find('[value="'+name+'"]').remove();
		AWE.setup.apply();
		AWE.status(AWE.msg('status-del-setup', name, '<a href="javascript:AWE.setup.undelete();">'+AWE.msg('status-del-undo')+'</a>'), true);
	}
};
AWE.setup.undelete = function() {
	AWE.setup.extend(AWE.setup.temp);
	AWE.status('done', true);
};

/***** Main other functions *****/

//Show status message
AWE.status = function(action, done) {
	$('#summary, .editbutton').prop('disabled', !done); //Disable box when not done (so busy loading). re-enable when done loading.
	var status = AWE.msg('status-'+action);
	if (status === false) return;
	var spinImg = '<img src="//upload.wikimedia.org/wikipedia/commons/d/de/Ajax-loader.gif" width="15" height="15" alt="'+AWE.msg('status-alt')+'"/>';
	if (status) {
		if (!done) { //spinner if not done
			status += ' ' + spinImg;
		}
	} else {
		status = action;
	}
	$('#status').html(status);
	AWE.pageCount();
	return action=='done';
};

AWE.pageCount = function() {
	if (AWE.allowed === false||!$('#articleList').length) return;
	$('#articleList').val(($('#articleList').val()||'').replace(/(^[ \t]*$\n)*/gm, ''));
	AWE.list = $('#articleList').val().split('\n');
	var count = AWE.list.length;
	if (count === 1 && AWE.list[0] === '') count = 0;
	$('#totPages').html(count);
};

//Perform all specified find&replace actions
AWE.replace = function(input) {
	AWE.pageCount();
 	var varOffset = AWE.list[0].indexOf('|') !== -1 ? AWE.list[0].indexOf('|') + 1 : 0;
 	AWE.page.pagevar = AWE.list[0].substr(varOffset);
	$('.replaces').each(function() {
		var $this = $(this);
		var regexFlags = $this.find('.regexFlags').val();
		var replace = $this.find('.replaceText').val().replace(/\$x/gi, AWE.page.pagevar).replace(/\\{2}/g, '\\').replace(/\\n/g,'\n') || '$';
		var useRegex = replace === '$' || $this.find('.useRegex').prop('checked');
		if (useRegex && regexFlags.indexOf('_') !== -1) {
			replace = replace.replace(/[ _]/g, '[ _]'); //replaces any of [Space OR underscore] with a match for spaces or underscores.
			replace = replace.replace(/(\[[^\]]*)\[ _\]/g, '$1 _'); //in case a [ _] was placed inside another [] match, remove the [].
			regexFlags = regexFlags.replace('_', '');
		}
		//apply replaces where \n and \\ work in both regular text and regex mode.
		var rWith = $this.find('.replaceWith').val().replace(/\$x/gi, AWE.page.pagevar).replace(/\\{2}/g, '\\').replace(/\\n/g,'\n');
		try {
			if ($this.find('.ignoreNowiki').prop('checked')) {
				if (!useRegex) {
					replace = replace.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
					regexFlags = 'g';
				}
				input = AWE.replaceParsed(input, replace, regexFlags, rWith);
			} else if (useRegex) {
				replace = new RegExp(replace, regexFlags);
				input = input.replace(replace, rWith);
			} else {
				input = input.split(replace).join(rWith); //global replacement without having to escape all special chars.
			}
		} catch(e) {
			AWE.stop();
			return AWE.status('regex-err', false);
		}
	});
	if ($('#enableRETF').prop('checked')) {
		input = RETF.replace(input);
	}
	return input;
};

//function to *only* replace the parsed wikitext
//It excludes comments (<!-- -->), and nowiki, math, source, syntaxhighlight, pre, code, gallery and timeline tags)
//Based on http://stackoverflow.com/a/23589204/1256925
AWE.replaceParsed = function(str, replace, flags, rwith) {
	var exclude = '(<!--[\\s\\S]*?-->|<(nowiki|math|source|syntaxhighlight|pre|gallery|timeline)[^>]*?>[\\s\\S]*?<\\/\\2>)';
	//add /i flag, to exclude the correct tags regardless of casing.
	//This won't matter for the actual replacing, as the specified flags are used there.
	var re = new RegExp(exclude + '|(' + replace + ')', flags.replace(/i|$/, 'i'));
	return str.replace(re, function(match, g1, g2, g3) {
		if (g3 !== undefined) { //continue to perform replacement if the match is the group that's supposed to be the match
			return match.replace(new RegExp(replace, flags), rwith);
		} else { //do nothing if the match is one of the excluded groups
			return match;
		}
	});
};

//Adds a line to the logs tab.
AWE.log = function(action, page, info) {
	var d = new Date();
	var pagee = encodeURIComponent(page);
	var extraInfo = '', actionStat = '';
	switch (action) {
		case 'edit':
			if (typeof info === 'undefined') {
				action = 'null-edit';
				actionStat = 'nullEdits';
				extraInfo = '';
			} else {
				extraInfo = ' (<a target="_blank" href="'+AWE.index_php+'?title='+pagee+'&diff='+info+'">diff</a>)';
				actionStat = 'pagesSaved';
			}
			break;
		case 'skip':
			actionStat = 'pagesSkipped';
			break;
		case 'move':
			extraInfo = ' to <a target="_blank" href="/wiki/'+encodeURIComponent(info)+'" title="'+info+'">'+info+'</a>';
			break;
		case 'protect':
			extraInfo = info;
			break;
	}
	actionStat = '#' + (actionStat || 'otherActions');
	$(actionStat).html(+$(actionStat).html() + 1);
	$('#actionlog tbody')
		.append('<tr>'+
			'<td>'+(AWE.fn.pad0(d.getHours())+':'+AWE.fn.pad0(d.getMinutes())+':'+AWE.fn.pad0(d.getSeconds()))+'</td>'+
			'<th>'+action+'</th>'+
			'<td><a target="_blank" href="/wiki/'+pagee+'" title="'+page+'">'+page+'</a>'+ extraInfo +'</td>'+
		'</tr>')
		.parents('.AWEtabc').scrollTop($('#actionlog tbody').parents('.AWEtabc')[0].scrollHeight);
};

//Move to the next page in the list
AWE.next = function(nextPage) {
	if ($.trim(nextPage) && !$('#skipAfterAction').prop('checked')) {
		nextPage = $.trim(nextPage) + '\n';
	} else {
		nextPage = '';
	}
	$('#articleList').val($('#articleList').val().replace(/^.*\n?/, nextPage));
	AWE.list.splice(0,1);
	AWE.pageCount();
	AWE.api.get(AWE.list[0].split('|')[0]);
};

//Stop everything, reset inputs and editor
AWE.stop = function() {
	$('#stopbutton,'+
	  '.editbutton,'+
	  '#watchNow,'+
	  '.AWEtabc[data-tab="2"] .editbutton,'+
	  '#watchNow'+
	  '.AWEtabc[data-tab="4"] button').prop('disabled', true);
	$('#startbutton, #articleList,'+
	  '.AWEtabc[data-tab="1"] button,'+
	  '#replacesPopup button,'+
	  '#replacesPopup input,'+
	  '.AWEtabc input, select').prop('disabled', false);
	$('#resultWindow').html('');
	$('#editBoxArea').val('');
	$('#currentpage').html(AWE.msg('editbox-currentpage', ' ', ' '));
	AWE.pl.stop();
	AWE.status('done', true);
	AWE.isStopped = true;
};

//Start AutoWikiBrowsing
AWE.start = function() {
	AWE.pageCount();
	if (AWE.list.length === 0 || (AWE.list.length === 1 && !AWE.list[0])) {
		alert(AWE.msg('no-pages-listed'));
	} else if ($('#skipNoChange').prop('checked') && !$('.replaceText').val() && !$('.replaceWith').val() && !$('#enableRETF').prop('checked')) {
		alert(AWE.msg('infinite-skip-notice'));
	} else {
		AWE.isStopped = false;
		if ($('#preparse').prop('checked') && !$('#articleList').val().match('#PRE-PARSE-STOP')) {
			$('#articleList').val($.trim($('#articleList').val()) + '\n#PRE-PARSE-STOP'); //mark where to stop pre-parsing
		} else {
			$('#preparse-reset').click();
		}
		$('#stopbutton, .editbutton, #watchNow, .AWEtabc[data-tab="2"] button, .AWEtabc[data-tab="4"] button').prop('disabled', false);
		$('#startbutton, #articleList, .AWEtabc[data-tab="1"] button, #replacesPopup button, #replacesPopup input, .AWEtabc input, select').prop('disabled', true);
		AWE.api.get(AWE.list[0].split('|')[0]);
	}
};

AWE.updateButtons = function() {
	if (!AWE.page.exists && $('#deletePage').is('.delete')) {
		$('#deletePage').removeClass('delete').addClass('undelete').html('Undelete');
		AWE.fn.blink('#deletePage'); //Indicate the button has changed
	} else if (AWE.page.exists && $('#deletePage').is('.undelete')) {
		$('#deletePage').removeClass('undelete').addClass('delete').html('Delete');
		AWE.fn.blink('#deletePage'); //Indicate the button has changed
	}
	if (!AWE.page.exists) {
		$('#movePage').prop('disabled', true);
	} else {
		$('#movePage').prop('disabled', false);
	}
	$('#watchNow').html( AWE.msg('watch-' + (AWE.page.watched ? 'remove' : 'add')) );
};

/***** General functions *****/

//Clear all existing timers to prevent them from getting errors
AWE.fn.clearAllTimeouts = function() {
	var i = setTimeout(function() {
		return void(0);
	}, 1000);
	for (var n=0;n<=i;n++) {
		clearTimeout(n);
		clearInterval(i);
	}
	console.log('Cleared all running intervals up to index',i);
};

//Filter an array to only contain unique values.
AWE.fn.uniques = function(arr) {
	var a = [];
	for (var i=0, l=arr.length; i<l; i++) {
		if (a.indexOf(arr[i]) === -1 && arr[i] !== '') {
			a.push(arr[i]);
		}
	}
	return a;
};

//Prepends zeroes until the number has the desired length of len (default 2)
AWE.fn.pad0 = function(n, len) {
	n = n.toString();
	len = len||2;
	return n.length < len ? Array(len-n.length).join('0')+n : n;
};

AWE.fn.blink = function(el,t) {
	t=t?t:500;
	$(el).prop('disabled', true)
	.children().animate({opacity:'0.1'},t-100)
	.animate({opacity:'1'},t)
	.animate({opacity:'0.1'},t-100)
	.animate({opacity:'1'},t);
	setTimeout("$('"+el+"').prop('disabled', false)",t*4-400);
};

AWE.fn.setSelection = function(el, start, end, dir) {
    dir = dir||'none'; //Default value
    end = end||start; //If no end is specified, assume the caret is placed without creating text selection.
    if (el.setSelectionRange) {
        el.focus();
        el.setSelectionRange(start, end, dir);
    } else if (el.createTextRange) {
        var rng = el.createTextRange();
        rng.collapse(true);
        rng.moveStart('character', start);
        rng.moveEnd('character', end);
        rng.select();
    }
};

AWE.fn.scrollSelection = function(el, index) { //function to fix scrolling to selection - doesn't do that automatically.
	var newEl = document.createElement('textarea'); //create a new textarea to simulate the same conditions
	var elStyle = getComputedStyle(el);
	newEl.style.height = elStyle.height; //copy over size-influencing styles
	newEl.style.width = elStyle.width;
	newEl.style.lineHeight = elStyle.lineHeight;
	newEl.style.fontSize = elStyle.fontSize;
	newEl.value = el.value.substr(0,index);
	document.body.appendChild(newEl); //needs to be added to the HTML for the scrollHeight and clientHeight to work.
	if (newEl.scrollHeight != newEl.clientHeight) {
		el.scrollTop = newEl.scrollHeight - 2;
	} else {
		el.scrollTop = 0;
	}
	newEl.remove(); //clean up the mess I've made
};

//i18n function
AWE.msg = function(message) {
	var args = arguments;
	var lang = AWE.lang;
	if (typeof message === 'object') {
		lang = message[1];
		message = message[0];
	}
	if (lang == 'qqx') return message;
	if (!AWE.messages || !AWE.messages.en) return message;
	var msg;
	if (AWE.messages.hasOwnProperty(lang) && AWE.messages[lang].hasOwnProperty(message)) {
		msg = AWE.messages[lang][message];
	} else {
		msg = (AWE.messages.en.hasOwnProperty(message)) ? AWE.messages.en[message] : '';
	}
	msg = msg.replace(/\$(\d+)/g, function(match, num) {
		return args[+num] || match;
	});
	return msg;
};

/***** Init *****/

AWE.init = function() {
	console.log(AWE.messages.en, !!AWE.messages.en);
	AWE.setup.load();
	AWE.fn.clearAllTimeouts();
	if (!AWE.messages[AWE.lang] && AWE.lang != 'qqx') AWE.lang = 'en';
	
	var findreplace = '<div class="replaces">'+
		'<label style="display:block;">'+AWE.msg('label-replace')+' <input type="text" class="replaceText"/></label>'+
		'<label style="display:block;">'+AWE.msg('label-rwith')+' <input type="text" class="replaceWith"/></label>'+
		'<div class="regexswitch">'+
			'<label><input type="checkbox" class="useRegex"> '+AWE.msg('label-useregex')+'</label>'+
			'<a class="re101" href="http://regex101.com/#javascript" target="_blank">?</a>'+
			'<label class="divisor" title="'+AWE.msg('tip-regex-flags')+'" style="display:none;">'+
				AWE.msg('label-regex-flags')+' <input type="text" class="regexFlags" value="g"/>'+ //default: global replacement
			'</label>'+
			'<br/>'+
		'</div>'+
		'<label title="'+AWE.msg('tip-ignore-comment')+'">'+
			'<input type="checkbox" class="ignoreNowiki"> '+AWE.msg('label-ignore-comment')+
		'</label>'+
	'</div>';
	
	var NSList = '<select multiple name="namespace" id="namespacelist">';
	for (var i in AWE.ns) {
		if (parseInt(i) < 0) continue; //No Special: or Media: in the list
		NSList += '<option value="'+AWE.ns[i].id+'" selected>'+(AWE.ns[i]['*'] || '('+AWE.msg('namespace-main')+')')+'</option>';
	}
	NSList += '</select>';
	
	/***** Interface *****/
	
	document.title = 'AutoWikiEditor'+(document.title.split('-')[1] ? ' -'+document.title.split('-')[1] : '');
	$('body').html(
		'<article id="resultWindow"></article>'+
		'<main id="inputsWindow">'+
			'<div id="inputsBox">'+
				'<aside id="articleBox">'+
					'<b>'+AWE.msg('pagelist-caption')+'</b>'+
					'<textarea id="articleList"></textarea>'+
				'</aside>'+
				'<section id="tabs">'+
					'<nav class="tabholder">'+
						'<span class="AWEtab" data-tab="1">'+AWE.msg('tab-setup')+'</span> '+
						'<span class="AWEtab active" data-tab="2">'+AWE.msg('tab-editing')+'</span> '+
						'<span class="AWEtab" data-tab="3">'+AWE.msg('tab-skip')+'</span> '+
						(AWE.sysop?'<span class="AWEtab" data-tab="4">'+AWE.msg('tab-other')+'</span> ':'')+
						' <span class="AWEtab log" data-tab="5">'+AWE.msg('tab-log')+'</span> '+
					'</nav>'+
					'<section class="AWEtabc" data-tab="1"></section>'+
					'<section class="AWEtabc active" data-tab="2"></section>'+
					'<section class="AWEtabc" data-tab="3"></section>'+
					(AWE.sysop?'<section class="AWEtabc" data-tab="4"></section>':'')+
					'<section class="AWEtabc log" data-tab="5"></section>'+
					'<footer id="status">done</footer>'+
				'</section>'+
				'<aside id="editBox">'+
					'<b>'+AWE.msg('editbox-caption')+' - <span id="currentpage">'+AWE.msg('editbox-currentpage', ' ', ' ')+'</span></b>'+
					'<textarea id="editBoxArea"></textarea>'+
				'</aside>'+
			'</div>'+
		'</main>'+
		'<footer id="stats">'+
			AWE.msg('stat-pages')+' <span id="totPages">0</span>;&emsp;'+
			AWE.msg('stat-save')+' <span id="pagesSaved">0</span>;&emsp;'+
			AWE.msg('stat-null')+' <span id="nullEdits">0</span>;&emsp;'+
			AWE.msg('stat-skip')+' <span id="pagesSkipped">0</span>;&emsp;'+
			AWE.msg('stat-other')+' <span id="otherActions">0</span>;&emsp;'+
		'</footer>'+
		'<div id="overlay" style="display:none;"></div>'+
		'<section class="AWEpopup" id="replacesPopup" style="display:none;">'+
			'<button id="moreReplaces">'+AWE.msg('button-more-fields')+'</button>'+
			'<br>'+findreplace+
		'</section>'+
		'<section class="AWEpopup" id="pagelistPopup" style="display:none;">'+
			'<form action="javascript:AWE.pl.generate();"></form>'+
		'</section>'
	);
	
	$('.AWEtabc[data-tab="1"]').html(
		'<fieldset id="pagelist">'+
			'<legend>'+AWE.msg('label-pagelist')+'</legend>'+
			'<button id="removeDupes">'+AWE.msg('button-remove-dupes')+'</button> '+
			'<button id="sortArticles">'+AWE.msg('button-sort')+'</button>'+
			'<br>'+
			'<label title="'+AWE.msg('tip-preparse')+'">'+
				'<input type="checkbox" id="preparse"> '+AWE.msg('preparse')+
			'</label>'+
			'<span class="divisor"></span>'+
			'<button id="preparse-reset" title="'+AWE.msg('tip-preparse-reset')+'">'+AWE.msg('preparse-reset')+'</button>'+
			'<br>'+
			'<button id="pagelistButton">'+AWE.msg('pagelist-generate')+'</button>'+
		'</fieldset>'+
		'<fieldset id="settings">'+
			'<legend>'+AWE.msg('label-settings')+'</legend>'+
			'<button id="saveAs" title="'+AWE.msg('tip-store-setup')+'">'+AWE.msg('store-setup')+'</button>'+
			'<br>'+
			'<label>'+
				AWE.msg('load-settings') + ' '+
				'<select id="loadSettings">'+
					'<option value="default" selected>default</option>'+
					'<option value="_blank">'+AWE.msg('blank-setup')+'</option>'+
				'</select>'+
			'</label>'+
			'<span class="divisor"></span>'+
			'<button id="deleteSetup" title="'+AWE.msg('tip-delete-setup')+'">'+AWE.msg('delete-setup')+'</button>'+
			'<hr>'+
			'<button id="saveToWiki">'+AWE.msg('save-setup')+'</button>'+
			'<span class="divisor"></span>'+
			'<button id="download">'+AWE.msg('download-setup')+'</button>'+
			'<hr>'+
			'<label class="button" id="importLabel" title="'+AWE.msg('tip-import-setup')+'">'+
				'<input type="file" id="import" accept=".json">'+
				AWE.msg('import-setup')+
			'</label>'+
			'<span class="divisor"></span>'+
			'<button id="updateSetups" title="'+AWE.msg('tip-update-setup', AWE.settingspage)+'">'+AWE.msg('update-setup')+'</button>'+
			'<div id="downloads">'+
				'<a download="AWE-settings.json" target="_blank" id="download-anchor"></a>'+
				'<iframe id="download-iframe"></iframe>'+
			'</div>'+
		'</fieldset>'
	);
	$('.AWEtabc[data-tab="2"]').html(
		'<label style="float:right;"><input type="checkbox" id="minorEdit" checked> '+AWE.msg('minor-edit')+'</label>'+
		'<label class="viaAWE">'+AWE.msg('edit-summary')+' <input class="fullwidth" type="text" id="summary" maxlength="250"></label>'+
		' <input type="checkbox" id="viaAWE" checked title="'+AWE.msg('tip-via-AWE')+'">'+
		'<select id="watchPage">'+
			'<option value="watch">'+AWE.msg('watch-watch')+'</option>'+
			'<option value="unwatch">'+AWE.msg('watch-unwatch')+'</option>'+
			'<option value="nochange" selected>'+AWE.msg('watch-nochange')+'</option>'+
			'<option value="preferences">'+AWE.msg('watch-preferences')+'</option>'+
		'</select>'+
		'<span class="divisor"></span>'+
		'<button id="watchNow" disabled accesskey="w" title="['+AWE.tooltip+'w]">'+
			AWE.msg('watch-add')+
		'</button>'+
		'<br>'+
		(AWE.bot?
			'<label><input type="checkbox" id="autosave"> '+AWE.msg('auto-save')+'</label>'+
			'<label title="'+AWE.msg('tip-save-interval')+'" class="divisor">'+
				AWE.msg('save-interval', '<input type="number" min="0" value="0" style="width:50px" id="throttle" disabled>')+
			'</label>'+
			'<br>'
		:'')+
		'<span id="startstop">'+
			'<button id="startbutton" accesskey="a" title="['+AWE.tooltip+'a]">'+AWE.msg('editbutton-start')+'</button>'+
			'<br>'+
			'<button id="stopbutton" disabled accesskey="q" title="['+AWE.tooltip+'q]">'+AWE.msg('editbutton-stop')+'</button> '+
		'</span>'+
		'<button class="editbutton" id="skipButton" disabled accesskey="n" title="['+AWE.tooltip+'n]">'+AWE.msg('editbutton-skip')+'</button>'+
		'<button class="editbutton" id="submitButton" disabled accesskey="s" title="['+AWE.tooltip+'s]">'+AWE.msg('editbutton-save')+'</button>'+
		'<br>'+
		'<button class="editbutton" id="previewButton" disabled accesskey="p" title="['+AWE.tooltip+'p]">'+AWE.msg('editbutton-preview')+'</button>'+
		'<button class="editbutton" id="diffButton" disabled accesskey="d" title="['+AWE.tooltip+'d]">'+AWE.msg('editbutton-diff')+'</button>'+
		'<button id="replacesButton">'+AWE.msg('button-open-popup')+'</button>'+
		findreplace+
		'<hr>'+
		'<label><input type="checkbox" id="enableRETF">'+
			AWE.msg('label-enable-RETF', 
				'<a href="https://en.wikipedia.org/wiki/Project:AutoWikiBrowser/Typos" target="_blank">'+
					AWE.msg('label-RETF')+
				'</a>')+
		'</label>'+
		' <img src="https://upload.wikimedia.org/wikipedia/commons/thumb/2/2a/Gnome-view-refresh.svg/20px-Gnome-view-refresh.svg.png"'+
		'id="refreshRETF" title="'+AWE.msg('tip-refresh-RETF')+'">'
	);
	$('.AWEtabc[data-tab="3"]').html(
		'<fieldset>'+
			'<legend>'+AWE.msg('label-redirects')+'</legend>'+
			'<label title="'+AWE.msg('tip-redirects-follow')+'">'+
				'<input type="radio" class="redirects" value="follow" name="redir" id="redir-follow"> '+AWE.msg('redirects-follow')+' '+
			'</label>'+
			'<label title="'+AWE.msg('tip-redirects-skip')+'">'+
				 '<input type="radio" class="redirects" value="skip" name="redir" id="redir-skip"> '+AWE.msg('redirects-skip')+' '+
			'</label>'+
			'<label title="'+AWE.msg('tip-redirects-edit')+'">'+
				'<input type="radio" class="redirects" value="edit" name="redir" id="redir-edit" checked> '+AWE.msg('redirects-edit')+''+
			'</label>'+
		'</fieldset>'+
		'<fieldset>'+
			'<legend>'+AWE.msg('label-skip-when')+'</legend>'+
			'<label><input type="checkbox" id="skipNoChange"> '+AWE.msg('skip-no-change')+'</label>'+
			'<br>'+
			'<label><input type="radio" id="exists-yes" name="exists" value="yes"> '+AWE.msg('skip-exists-yes')+'</label>'+
			'<label><input type="radio" id="exists-no" name="exists" value="no" checked> '+AWE.msg('skip-exists-no')+'</label>'+
			'<label><input type="radio" id="exists-neither" name="exists" value="neither">'+AWE.msg('skip-exists-neither')+'</label>'+
			'<br>'+
			(AWE.sysop?'<label><input type="checkbox" id="skipAfterAction" checked> '+AWE.msg('skip-after-action')+'</label>':'')+
		'</fieldset>'+
		'<label>'+AWE.msg('skip-contains')+' <input class="fullwidth" type="text" id="skipContains"></label>'+
		'<label>'+AWE.msg('skip-not-contains')+' <input class="fullwidth" type="text" id="skipNotContains"></label>'+
		'<div class="regexswitch">'+
			'<label><input type="checkbox" id="containRegex"> '+AWE.msg('label-useregex')+'</label>'+
			'<a class="re101" href="http://regex101.com/#javascript" target="_blank">?</a>'+
			'<label class="divisor" title="'+AWE.msg('tip-regex-flags')+'" style="display:none;">'+
				AWE.msg('label-regex-flags')+' <input type="text" id="containFlags"/>'+
			'</label>'+
		'</div>'
	);
	if (AWE.sysop) $('.AWEtabc[data-tab="4"]').html(
		'<fieldset>'+
			'<legend>'+AWE.msg('move-header')+'</legend>'+
			'<label><input type="checkbox" id="suppressRedir"> '+AWE.msg('move-redir-suppress')+'</label>'+
			'<br>'+
			AWE.msg('move-also')+' '+
			'<label><input type="checkbox" id="movetalk"> '+AWE.msg('move-talk-page')+'</label> '+
			'<label><input type="checkbox" id="movesubpage"> '+AWE.msg('move-subpage')+'</label>'+
			'<br>'+
			'<label>'+AWE.msg('move-new-name')+' <input type="text" id="moveTo"></label>'+
		'</fieldset>'+
		'<fieldset>'+
		'<legend>'+AWE.msg('protect-header')+'</legend>'+
			AWE.msg('protect-edit')+
			'<select id="editProt">'+
				'<option value="all" selected>'+AWE.msg('protect-none')+'</option>'+
				'<option value="autoconfirmed">'+AWE.msg('protect-autoconf')+'</option>'+
				'<option value="sysop">'+AWE.msg('protect-sysop')+'</option>'+
			'</select> '+
			'<br>'+
			AWE.msg('protect-move')+
			'<select id="moveProt">'+
				'<option value="all" selected>'+AWE.msg('protect-none')+'</option>'+
				'<option value="autoconfirmed">'+AWE.msg('protect-autoconf')+'</option>'+
				'<option value="sysop">'+AWE.msg('protect-sysop')+'</option>'+
			'</select> '+
			'<br>'+
			'<label>'+AWE.msg('protect-expiry')+' <input type="text" id="protectExpiry"/></label>'+
		'</fieldset>'+
		'<button id="movePage" disabled accesskey="m" title="['+AWE.tooltip+'m]">'+AWE.msg('editbutton-move')+'</button> '+
		'<button id="deletePage" disabled accesskey="x" title="['+AWE.tooltip+'x]">'+AWE.msg('editbutton-delete')+'</button> '+
		'<button id="protectPage" disabled accesskey="z" title="['+AWE.tooltip+'z]">'+AWE.msg('editbutton-protect')+'</button> '+
		'<button id="skipPage" disabled title="['+AWE.tooltip+'n]">'+AWE.msg('editbutton-skip')+'</button>'
	);
	$('.AWEtabc[data-tab="5"]').html('<table id="actionlog"><tbody></tbody></table>');
	$('#pagelistPopup form').html(
		'<div id="ns-filter" title="'+AWE.msg('tip-ns-select')+'">' + AWE.msg('label-ns-select') + NSList + '</div>'+
		'<fieldset>'+
			'<legend><label><input type="checkbox" id="categorymembers" name="categorymembers" value="cm"> '+AWE.msg('legend-cm')+'</label></legend>'+
			'<label title="Namespace prefix not required.">'+AWE.msg('label-cm')+' <input type="text" name="cmtitle" id="cmtitle"></label>'+
			'<div>'+AWE.msg('cm-include')+' '+
				'<label><input type="checkbox" id="cmtype-page" name="cmtype" value="page" checked> '+AWE.msg('cm-include-pages')+'</label>'+
				'<label><input type="checkbox" id="cmtype-subcg" name="cmtype" value="subcat" checked> '+AWE.msg('cm-include-subcgs')+'</label>'+
				'<label><input type="checkbox" id="cmtype-file" name="cmtype" value="file" checked> '+AWE.msg('cm-include-files')+'</label>'+
			'</div>'+
		'</fieldset>'+
		'<fieldset>'+
			'<legend><label><input type="checkbox" name="linksto" id="linksto"> '+AWE.msg('legend-linksto')+'</label></legend>'+
			'<label>'+AWE.msg('label-linksto')+' <input type="text" name="title" id="linksto-title"></label>'+
			'<div>'+AWE.msg('links-include')+' '+
				'<label><input type="checkbox" id="backlinks" name="backlinks" value="bl" checked> '+AWE.msg('links-include-links')+'</label>'+
				'<label><input type="checkbox" id="embeddedin" name="embeddedin" value="ei"> '+AWE.msg('links-include-templ')+'</label>'+
				'<label><input type="checkbox" id="imageusage" name="imageusage" value="iu"> '+AWE.msg('links-include-files')+'</label>'+
			'</div>'+
			'<div>'+AWE.msg('links-redir')+' '+
				'<label><input type="radio" id="rfilter-redir" name="filterredir" value="redirects"> '+AWE.msg('links-redir-redirs')+'</label>'+
				'<label><input type="radio" id="rfilter-nonredir" name="filterredir" value="nonredirects"> '+AWE.msg('links-redir-noredirs')+'</label>'+
				'<label><input type="radio" id="rfilter-all" name="filterredir" value="all" checked> '+AWE.msg('links-redir-all')+'</label>'+
			'</div>'+
			'<label title="'+AWE.msg('tip-link-redir')+'">'+
				'<input type="checkbox" name="redirect" value="true" checked id="linksto-redir"> '+AWE.msg('label-link-redir')+
			'</label>'+
		'</fieldset>'+
		'<fieldset>'+
			'<legend><label><input type="checkbox" id="prefixsearch" name="prefixsearch" value="ps"> '+AWE.msg('legend-ps')+'</label></legend>'+
			'<label>'+AWE.msg('label-ps')+' <input type="text" name="pssearch" id="pssearch"></label>'+
		'</fieldset>'+
		'<fieldset>'+
			'<legend><label><input type="checkbox" id="watchlistraw" name="watchlistraw" value="wr"> '+AWE.msg('legend-wr')+'</label></legend>'+
			AWE.msg('label-wr')+
		'</fieldset>'+
		'<fieldset>'+
			'<legend><label><input type="checkbox" id="proplinks" name="links" value="pl"> '+AWE.msg('legend-pl')+'</label></legend>'+
			'<label title="'+AWE.msg('tip-pl')+'">'+AWE.msg('label-pl')+' <input type="text" id="pltitles" name="titles"></label>'+
		'</fieldset>'+
		'<button type="submit">'+AWE.msg('pagelist-generate')+'</button>'
	);
	$('body').addClass('AutoWikiBrowser'); //allow easier custom styling of AWE.
	
	/***** Setup *****/
	AWE.setup.save('_blank'); //default setup
	if (AWE.settings.hasOwnProperty('default')) {
		AWE.setup.apply();
	} else if (AWE.setup.hasOwnProperty('edittoken')) {
		AWE.setup.save('default');
	}
	AWE.setup.extend({});

	/***** Event handlers *****/
	
	//Alert user when leaving the tab, to prevent accidental closing.
	onbeforeunload = function() {
		return "Closing this tab will cause you to lose all progress.";
	};
	ondragover = function(e) {
		e.preventDefault();
	};
	
	$('.AWEtab').click(function() {
		$('.active').removeClass('active');
		$(this).addClass('active');
		$('.AWEtabc[data-tab="'+$(this).attr('data-tab')+'"]').addClass('active');
	});
	
	function showRegexFlags() {
		// >>this<< is the element that's triggered
		$(this).parent().nextAll('label').toggle(this.checked);
	}
	$('body').on('change', '#useRegex, #containRegex, .useRegex', showRegexFlags);
	
	$('#preparse-reset').click(function() {
		$('#articleList').val($('#articleList').val().replace(/#PRE-PARSE-STOP/g,'').replace(/\n\n/g, '\n'));
	});
	$('#saveAs').click(function() {
		AWE.setup.save();
	});
	$('#loadSettings').change(function() {
		AWE.setup.apply(this.value);
	});
	$('#download').click(AWE.setup.download);
	$('#saveToWiki').click(AWE.setup.submit);
	$('#import').change(AWE.setup.import);
	ondrop = AWE.setup.import;
	$('#updateSetups').click(AWE.setup.load);
	$('#deleteSetup').click(AWE.setup.delete);
	
	if (window.RETF) $('#refreshRETF').click(RETF.load);

	$('#replacesButton, #pagelistButton').click(function() {
		var popup = this.id.slice(0, -6); //omits the 'Button' in the id by cutting off the last 6 characters
		$('#'+popup+'Popup, #overlay').show();
	});
	$('#overlay').click(function() {
		$('#replacesPopup, #pagelistPopup, #overlay').hide();
	});
	$('#moreReplaces').click(function() {
		$('#replacesPopup').append(findreplace);
	});
	$('#replacesPopup').on('keydown', '.replaces:last', function(e) {
		if (e.which === 9) $('#moreReplaces')[0].click();
	});
	
	$('#pagelistPopup legend input').change(function() {
		//remove disabled attr when checked, add when not.
		$(this).parents('fieldset').find('input').not('legend input').prop('disabled', !this.checked);
		$(this).parents('fieldset').prop('disabled', !this.checked);
	}).trigger('change');
	
	$('#resultWindow').on('click', 'tr[data-line]:not(.lineheader) *', function(e) {
		var line = +$(e.target).closest('tr[data-line]').data('line');
		var index = $('#editBoxArea').val().split('\n').slice(0, line-1).join('\n').length;
		$('#editBoxArea')[0].focus();
		AWE.fn.setSelection($('#editBoxArea')[0], index+1);
		AWE.fn.scrollSelection($('#editBoxArea')[0], index);
	});
	
	$('#removeDupes').click(function() {
		$('#articleList').val(AWE.fn.uniques($('#articleList').val().split('\n')).join('\n'));
		AWE.pageCount();
	});
	$('#sortArticles').click(function() {
		$('#articleList').val($('#articleList').val().split('\n').sort().join('\n'));
		AWE.pageCount();
	});
	
	$('#watchNow').click(AWE.api.watch);
	$('#autosave').change(function() {
		$('#throttle').prop('disabled', !this.checked);
	});
	
	$('#viaAWE').change(function() {
		$('#summary').parent('label')
			.toggleClass('viaAWE', this.checked)
			.attr('maxlength', 250 - this.checked*AWE.summarySuffix.length); // Change the max size of the allowed summary according to having a suffix or not.
	});
	$('#startbutton').click(AWE.start);
	$('#stopbutton').click(AWE.stop);
	$('#submitButton').click(AWE.api.submit);
	$('#previewButton').click(AWE.api.preview);
	$('#diffButton').click(AWE.api.diff);
	
	$('#skipButton, #skipPage').click(function() {
		AWE.log('skip', AWE.list[0].split('|')[0]);
		AWE.next();
	});
	
	if (AWE.sysop) {
		$('#movePage').click(function() {
			if ($('#moveTo').val().length === 0) {
				return alert(AWE.msg('alert-no-move'));
			}
			AWE.api.move();
		});
		$('#protectPage').click(AWE.api.protect);
		$('#deletePage').click(AWE.api.delete);
	}
};

//Disable AWE altogether when it's loaded on a page other than Project:AutoWikiBrowser/Script. This script shouldn't be loaded on any other page in the first place.
if (AWE.allowed === false) AWE = false;