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.
// XwikiXfer - Copy files from one WMF wiki to another
// XwikiXfer is public domain, irrevocably released as WTFPL Version 2[www.wtfpl.net/about/] by its author, Alexis Jazz.
/*globals $:false,mw:false,OO:false*/

// <nowiki>

window.ajxwxf = {};
var ajxwxf = window.ajxwxf;

ajxwxf.msg = {};
ajxwxf.msg.en = {
	version: '4',
	filename: 'Filename:',
	wikitext: 'Wikitext:',
	upload: 'Upload',
	portlet: 'XwXf',
	portlettitle: 'Upload file to another wiki',
	wiki: 'Wiki:',
	enwikifixes: 'enwiki fixes',
	summary:'changed image from \1 to \2 [[[w:User:Alexis Jazz/XwikiXfer|XwikiXfer]]]',
	uploadsummary:'Uploaded file from \1 [[[w:User:Alexis Jazz/XwikiXfer|XwikiXfer]]]',
	pending:'Pending',
	edit:'Edit ',
	LuckyRenameActionCompleted: 'Done',
	LuckyRenameActionFailed: "FAILED",
};
ajxwxf.msgs = ajxwxf.msg.en;

if ( mw.config.get('wgNamespaceNumber') == 6 ) {
	ajxwxf.portlet = mw.util.addPortletLink(
	'p-tb',
		'/wiki/', //URL not used
		ajxwxf.msgs.portlet,
		'p-ajxwxf',
		ajxwxf.msgs.portlettitle,
		null//accesskey
		//'#t-'
	);
}

$('#p-ajxwxf a').on('click', function(event){
	event.preventDefault();
	mw.loader.using( [ 'oojs-ui-core','oojs-ui-windows' ] ).then( function () {
		mw.util.addCSS(
		'#ajxwxf-uploadform .progresstable, #ajxwxf-uploadform .progresstable th, #ajxwxf-uploadform .progresstable td { border: 1px solid black; }'+
		'.LuckyRenamePendingBlink { background-color:lightgrey }'+
		'@keyframes LuckyRenameBlinker { 50% { opacity: 0.5; } }'+
		'.LuckyRenameActionCompleted { color: green;font-weight: bold; }'+
		'.LuckyRenameActionFailed { color: red;font-weight: bold; }'+
		'.LuckyRenameActionSkipped { color: orange;font-weight: bold; }'+
		'.LuckyRenameActionSkippedDisallowed { color: orange;font-weight: bold; }'+
		'.LuckyRenameActionFailedMWE { color: red;font-weight: bold; }'+
		'.LuckyRenameActionFailedMissingTitle { color: red;font-weight: bold; }'+
		'.LuckyRenameActionFailedOther { color: red;font-weight: bold; }'+
		'.LuckyRenameActionFailedRetry { animation: LuckyRenameBlinker 1s linear infinite;color: orange;font-weight: bold; }'+
		'.LuckyRenameActionFailedGaveUp { color: red;font-weight: bold; }'+
		'.actionFilenamenotfound { color: orange;font-weight: bold; }'+
		'.LuckyRenameFloatRight { float: right; }'+
		'.LuckyRenameHalfOpacity { opacity: 0.50; }'+
		'.LuckyRenameVisible { display:block; }'+
		'.LuckyRenameInvisible { display:none; }'+
		'.LuckyRenameButtonBarPadding { padding-top:0.5em; }'+
		'.LuckyRename2Em { font-size:2em; margin-top:-8px; }'+
		'.ajxwxfuploadedfilelink { margin:1em }'
		);

		ajxwxf.formelements = [];
		ajxwxf.form = {};
		ajxwxf.form.wikiLabel = new OO.ui.LabelWidget( {
			label: ajxwxf.msgs.wiki,
			id: 'ajxwxfwikilabel',
		} );

		ajxwxf.form.wiki = new OO.ui.TextInputWidget( {
			value: ( mw.storage.get('ajxwxfexportwiki') || 'en.wikipedia.org' ),
			classes: [],
			title: ajxwxf.msgs.wiki,
		} );
		ajxwxf.form.titleLabel = new OO.ui.LabelWidget( {
			label: ajxwxf.msgs.filename,
		} );
		ajxwxf.form.title = new OO.ui.TextInputWidget( {
			value: mw.config.get('wgTitle'),
			classes: [],
			title: ajxwxf.msgs.filename,
		} );
		ajxwxf.api = new mw.ForeignApi('https://'+ajxwxf.form.wiki.getValue()+mw.config.get('wgScriptPath')+'/api.php');
		ajxwxf.form.title.on( 'change', function(){ajxwxf.checkNewFilename();});
		ajxwxf.form.wikitext = new OO.ui.MultilineTextInputWidget( {
			id: 'ajxwxf-wikitext',
			rows: 15,
			spellcheck: false,
			value: '',
		} );

		ajxwxf.form.enwiki = new OO.ui.ButtonWidget( {
			label:ajxwxf.msgs.enwikifixes,
			title:ajxwxf.msgs.enwikifixes,
			id:'ajxwxfenwikibutton',
			flags:['progressive','primary']
		} );

		ajxwxf.form.upload = new OO.ui.ButtonWidget( {
			label:ajxwxf.msgs.upload,
			title:ajxwxf.msgs.upload,
			id:'ajxwxfuploadbutton',
			flags:['progressive','primary']
		} );

		ajxwxf.disableMoveButton = function() {
				ajxwxf.form.upload.setDisabled(true);
		};
		ajxwxf.enableMoveButton = function() {
				ajxwxf.form.upload.setDisabled(false);
		};
		ajxwxf.updateNewFileProblemHint = function(hint) {
			ajxwxf.form.title.setLabel(hint);
		};

		ajxwxf.fixenwiki = function(){
			//ajxwxf.form.title.setValue(ajxwxf.form.title.getValue().replace(/\.([A-Za-z0-9]*)$/,' (enwiki).$1'));
			ajxwxf.form.wikitext.setValue(ajxwxf.form.wikitext.getValue().replace(/{{(PD-[Tt]extlogo|PD-[Ll]ogo)}}/,'{{PD-ineligible-USonly}}').replace(/\{\{delete[^\}]*\}\}\n/,'').replace(/\[\[[Cc]ategory:([^\]]*)\]\]([\n]*)/g,''));
		};
		ajxwxf.form.upload.on('click',function(){ajxwxf.getFile();});
		ajxwxf.form.enwiki.on('click',function(){ajxwxf.fixenwiki();});
		ajxwxf.formelements.push(ajxwxf.form.wikiLabel,ajxwxf.form.wiki,ajxwxf.form.titleLabel,ajxwxf.form.title,ajxwxf.form.wikitext,ajxwxf.form.enwiki,ajxwxf.form.upload);

		ajxwxf.uploadForm = new OO.ui.FormLayout( {
			items: ajxwxf.formelements,
			id: 'ajxwxf-uploadform',
			classes: [],
		} );
		$(document.getElementById('content')).append(ajxwxf.uploadForm.$element);
		$('#ajxwxfwikilabel')[0].scrollIntoView({behavior: 'smooth',block: 'start',inline: 'nearest'});

		ajxwxf.getWikitextFromExport = function(text) {
			if ( text.match(/[^]*<text bytes[^>]*>([^]*)<\/text>[^]*/) ) {
				return text.replace(/<model>wikibase-mediainfo[^]*/,'').replace(/[^]*<text bytes[^>]*>([^]*)<\/text>[^]*/, '$1').replace(/\&lt\;/g, '<').replace(/\&gt\;/g, '>').replace(/\&amp\;/g, '&');
			} else {
				return '';
			}
		};
		ajxwxf.lapi = new mw.Api(); //local api, to get wikitext of file page
		ajxwxf.lapi.get( {
			action: 'query', export: 'true', format: 'json', titles: mw.config.get('wgPageName'),
		} ).then( function ( data ) {
			ajxwxf.wikiTextForEdit = ajxwxf.getWikitextFromExport(data.query.export["*"]);
			ajxwxf.form.wikitext.setValue(ajxwxf.wikiTextForEdit);
		});
		ajxwxf.checkNewFilename();
	});

	ajxwxf.callbackUpload = function ( jqXHR, textStatus, errorThrown ) {
		ajxwxf.file = new File([jqXHR], ajxwxf.form.title.getValue(), { type: jqXHR.type });
		if ( mw.config.get('wgSiteName') == "Wikimedia Commons" ) {
			ajxwxf.filelink = '[[:c:File:'+mw.config.get('wgTitle')+']]';
		} else {
			ajxwxf.filelink = mw.config.get('wgServer').replace(/^\/\//,'https://')+mw.config.get('wgArticlePath').replace('$1',encodeURIComponent(mw.config.get('wgPageName')));
		}
		ajxwxf.formdata = {
			filename:ajxwxf.form.title.getValue(),
			ignorewarnings:1, //skip dupe warning
			assert:'user',
			assertuser:mw.config.get('wgUserName'),
			title:ajxwxf.form.title.getValue(),
			text:ajxwxf.form.wikitext.getValue(),
			watchlistexpiry:'3 months',
			comment:ajxwxf.msgs.uploadsummary.replace('\1',ajxwxf.filelink),
		};
		//using wgScriptPath/wgArticlePath from the wiki we are currently on isn't strictly correct, but this info should be universal across WMF wikis
		ajxwxf.api.upload( ajxwxf.file, ajxwxf.formdata ).then( function ( data ) {
		}, function ( code, data ) {
			$( '#ajxwxf-uploadform' ).append('<div class="ajxwxfuploadedfilelink"><a href="https://'+ajxwxf.form.wiki.getValue()+mw.config.get('wgArticlePath').replace('$1',encodeURIComponent('File:' + ajxwxf.form.title.getValue()))+'">'+ajxwxf.form.title.getValue()+'</a></div>');
			ajxwxf.DoRename();

			//window.location = 'https://'+ajxwxf.form.wiki.getValue()+mw.config.get('wgArticlePath').replace('$1',encodeURIComponent('File:'+ajxwxf.form.title.getValue()));
		});
	};
});

ajxwxf.getFile = function () {
	mw.storage.set('ajxwxfexportwiki',ajxwxf.form.wiki.getValue());
	ajxwxf.form.upload.setDisabled(1);
	ajxwxf.doCallGetFile = function () {
	ajxwxf.fileType = mw.config.get('wgPageName').match(/\.([A-Za-z0-9]*)$/,'$1')[1].toLowerCase();
		if ( ajxwxf.fileType == 'svg' ) {
			ajxwxf.xhr = $.ajax( {	url: $('.fullMedia a.internal')[0].href, cache: false, type: 'GET', xhrFields: { responseType: 'text'}, dataType: 'text', success: ajxwxf.callbackUpload, error: ajxwxf.handleError } );

		} else {
			ajxwxf.xhr = $.ajax( {	url: $('.fullMedia a.internal')[0].href, cache: false, type: 'GET', xhrFields: { responseType: 'blob'}, success: ajxwxf.callbackUpload, error: ajxwxf.handleError } );
		}
	};
	ajxwxf.doCallGetFile();
};

// what now follows is a stripped version of LuckyRename

ajxwxf.settings = {};

ajxwxf.escapeRegExp = function(string) {
	return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
};
ajxwxf.reportDebugMsg = function(msg) {
	if ( typeof msg == 'string' ) {
		console.log('LuckyRename: ' + msg);
	} else {
		console.log(msg);
	}
	if ( ajxwxf.settings.debugUI ) {
		$( '.LuckyRename' ).append( msg + '<br \>');
	}
};
ajxwxf.escapeReplacement = function(text) {
	return text.replace(/\$/g, '$$$$');
};

ajxwxf.updateReplaceUsageStatus = function(title, status, description) {
	if ( document.getElementById("replaceusage_" + encodeURIComponent(title).replace( /[%\._]/g, '')) ) {
		document.getElementById("replaceusage_" + encodeURIComponent(title).replace( /[%\._]/g, '')).classList = [ status ];
		document.getElementById("replaceusage_" + encodeURIComponent(title).replace( /[%\._]/g, '')).innerHTML = ajxwxf.msgs[status];
		if ( typeof description != "undefined" ) {
			document.getElementById("replaceusageStatusMsg_" + encodeURIComponent(title).replace( /[%\._]/g, '')).innerHTML = description;
		}
	} else if ( typeof title != "undefined" && title != ajxwxf.oldFile ){
		$( '.LuckyRename' ).append('<br \>Element with ID "replaceusage_' + encodeURIComponent(title).replace( /[%\._]/g, '') + '" could not be found. Please <a href="http://wiki.nitrosworld.org/wiki/User_talk:Alexis_Jazz/LuckyRename">report this error</a>.');
	} else if ( title != ajxwxf.oldFile ) {
		$( '.LuckyRename' ).append('<br \>Attempt to run updateReplaceUsageStatus without a title. Please <a href="http://wiki.nitrosworld.org/wiki/User_talk:Alexis_Jazz/LuckyRename">report this error</a>.');
	} else {
		ajxwxf.reportDebugMsg('Attempted to run updateReplaceUsageStatus on the current page');
	}
};
ajxwxf.allowBots = function(text, user){ // this function was copied from https://en.wikipedia.org/wiki/Template:Bots/doc by User:Tóraí, CC BY-SA 3.0
	if (!new RegExp("\\{\\{\\s*(nobots|bots[^}]*)\\s*\\}\\}", "i").test(text)) return true;
	return (new RegExp("\\{\\{\\s*bots\\s*\\|\\s*deny\\s*=\\s*([^}]*,\\s*)*" + user.replace(/([\(\)\*\+\?\.\-\:\!\=\/\^\$])/g, "\\$1") + "\\s*(?=[,\\}])[^}]*\\s*\\}\\}", "i").test(text)) ? false : new RegExp("\\{\\{\\s*((?!nobots)|bots(\\s*\\|\\s*allow\\s*=\\s*((?!none)|([^}]*,\\s*)*" + user.replace(/([\(\)\*\+\?\.\-\:\!\=\/\^\$])/g, "\\$1") + "\\s*(?=[,\\}])[^}]*|all))?|bots\\s*\\|\\s*deny\\s*=\\s*(?!all)[^}]*|bots\\s*\\|\\s*optout=(?!all)[^}]*)\\s*\\}\\}", "i").test(text);
};
ajxwxf.checkTitleInUse = function( checkTitle,fileusageparams ) {
			//For a file that exists locally, query.pages.(filepage ID) is defined and greater than 0.
			//For a file that exists on Commons, query.pages.-1.known is defined but empty. query.pages.-1.missing is also defined but empty.
			//For a filename that doesn't exist on either project, query.pages.-1.known is undefined. query.pages.-1.missing is defined but empty.
			ajxwxf.reportDebugMsg('Checking if entered title is in use');
			checkTitle = mw.config.get('wgCanonicalNamespace') + ':' + checkTitle;
			if ( checkTitle.replace( /_/g, ' ' ) == mw.config.get('wgPageName').replace( /_/g, ' ' ) ) {
				ajxwxf.reportDebugMsg('Entered title is identical to the current title');
				ajxwxf.updateNewFileProblemHint(ajxwxf.msgs.currentname);
				ajxwxf.disableMoveButton('#FFFFCC');
			} else {
	 			fileusageparams = {
				action: 'query',
				titles: checkTitle,
				prop: 'fileusage'
				};
				ajxwxf.doAPICall( fileusageparams, function ( r ) { } );
			}
};
ajxwxf.checkNewFilename = function() {

			// see global MW function wfStripIllegalFilenameChars for details. we also add some original ones that may conflict with various fs or scripts: '?', '!', '"', "'"
			// In Windows filenames / ? < > \ : * | " are illegal. When using FAT fs the caret ^ is also illegal so we exclude all of these. On Mac only the colon : is illegal
			// A period can't be the first character (this would be a hidden file on various *nix) so we disallow that too, but periods are otherwise ok
			// By default, $wgIllegalFileChars includes ':', '/', '\'
			// testLegalChars includes '#', '[', ']', '{', '}', '<', '>', '|' and non-ascii characters /[\\x00-\\x1f\\x7f]/
			// we use /[^\x00-\xFF]/ instead because I have no idea what this means
			ajxwxf.hasIllegalCharacters = ajxwxf.form.title.getValue().search( /[^\x00-\xFF]/ );	//search for characters that aren't legal, there should be none
			if ( ajxwxf.hasIllegalCharacters == -1 ) {
				ajxwxf.hasIllegalCharacters = ajxwxf.form.title.getValue().search( /[\/\\\:\#\[\]\{\}<>\|\!\?\"\\*\^]/ );	//search for characters that are illegal, there should be none
			}
			if ( ajxwxf.hasIllegalCharacters == -1 ) {
				ajxwxf.hasIllegalCharacters = ajxwxf.form.title.getValue().search( /^\./ ); //check if the first character is a period
			}
			ajxwxf.NewFilenameExtension = ajxwxf.form.title.getValue().replace( /.*\./g, "");

			if ( ajxwxf.hasIllegalCharacters != -1 ) {
				ajxwxf.updateNewFileProblemHint(ajxwxf.msgs.illegalchars);
				ajxwxf.disableMoveButton();
			} else if ( ajxwxf.NewFilenameExtension != ajxwxf.correctFilenameExtension ) {
				ajxwxf.updateNewFileProblemHint(ajxwxf.msgs.badextension);
				ajxwxf.disableMoveButton();
			} else {
				ajxwxf.isAvailable = ajxwxf.checkTitleInUse( ajxwxf.form.title.getValue() ); // ajxwxf.checkTitleInUse calls doAPIcall, doAPIcall enables/disables the move button
			}
};
ajxwxf.articletextUrl = mw.config.get('wgServer') + '/wiki/';

ajxwxf.updateMoveStatus = function(){};

if ( mw.config.get('wgDBname') == 'enwiki' ) {
	ajxwxf.automaticallyGeneratedTemplate = new RegExp('{{[\s]*[Aa]utomatically[ _]generated(?![^}]*allow[\s]*=[^\|}]*luckyrename)', '');
} else {
	ajxwxf.automaticallyGeneratedTemplate = new RegExp('{{[\s]*[Aa]utomatically[ _]generated(?![^}]*allow[\s]*=[^\|}]*luckyrename)', '');
}

ajxwxf.totalActionsTodo = 0;
ajxwxf.totalActionsDone = 0;
ajxwxf.overridden = 0;
ajxwxf.correctFilenameExtension = mw.config.get('wgPageName').replace( /.*\./g , '').replace( /^jpeg$/i, 'jpg').replace( /^jpg$/i, 'jpg').replace( /^png$/i, 'png').replace( /^gif$/i, 'gif').replace( /^tif$/i, 'tif').replace( /^tiff$/i, 'tif').replace( /^svg$/i, 'svg');

	ajxwxf.doAPICall = function( params,i,mode ) {
		params = $.extend( {
			action: 'query',
			format: 'json'
		}, params );

		i = 0;
			ajxwxf.callback = function ( jqXHR, textStatus, errorThrown ) {

				if ( typeof params.prop != "undefined" && typeof params.titles != "undefined" && params.prop == 'fileusage' && params.titles == 'File:' + ajxwxf.form.title.getValue() ) {
					ajxwxf.reportDebugMsg('received usage info for '+params.titles);

					ajxwxf.usageResponse = jqXHR;
					if ( typeof ajxwxf.usageResponse != "undefined" && typeof ajxwxf.usageResponse.query != "undefined" && ajxwxf.usageResponse.query.pages != "undefined" ) {
					ajxwxf.usagepageID = Object.keys(ajxwxf.usageResponse.query.pages)[0];
						if ( ajxwxf.usagepageID == "-1" && typeof ajxwxf.usageResponse.query.pages[-1].known != "undefined") {
							ajxwxf.updateNewFileProblemHint(ajxwxf.msgs.existsoncommons);
							ajxwxf.disableMoveButton();
						} else if ( ajxwxf.usagepageID == "-1" && typeof ajxwxf.usageResponse.query.pages[-1].missing != "undefined") {
							ajxwxf.enableMoveButton();
						} else if ( ajxwxf.usagepageID > 0 ) {
							ajxwxf.updateNewFileProblemHint(ajxwxf.msgs.existslocally);
							ajxwxf.disableMoveButton();
						} else {
							ajxwxf.reportDebugMsg('Could not determine if ' + params.titles + ' is free');
						}
					}
				} else if (typeof jqXHR.warnings != "undefined" && typeof jqXHR.warnings.main != "undefined") {
					ajxwxf.reportDebugMsg('API warning:');
					ajxwxf.reportDebugMsg(jqXHR.warnings);
					if ( params.action == 'move' ) {
						ajxwxf.updateMoveStatus(params.from, 'LuckyRenameActionFailed', ajxwxf.msgs.LuckyRenameActionFailed1);
					}

				} else if (typeof jqXHR.edit != "undefined" && typeof jqXHR.edit.result != "undefined" && jqXHR.edit.result == 'Success') { // edit succeeded
					ajxwxf.reportDebugMsg(jqXHR);
					ajxwxf.reportDebugMsg(params);
					ajxwxf.reportDebugMsg('edited '+params.title);
					ajxwxf.reportDebugMsg('edited '+jqXHR.edit.title);
					ajxwxf.reportDebugMsg(mode);
					if ( typeof ajxwxf.renameRequestWikitext == "undefined" && mode != 'decline' ) { // there is no progress bar or status table when requesting
						ajxwxf.totalActionsDone++; // +1
						ajxwxf.updateReplaceUsageStatus(jqXHR.edit.title, 'LuckyRenameActionCompleted');
					} else if ( mode == 'request' ) {
						$( '.LuckyRename' ).append('<br>' + ajxwxf.msgs.renamerequested);
						var myIntReloadRequested = setInterval(function () {
							clearInterval(myIntReloadRequested);
							location.reload();
						}, 3000);
					}
				} else if (typeof jqXHR.edit != "undefined" && typeof jqXHR.edit.result != "undefined") { 
					if ( params.action == 'move' ) {
						ajxwxf.reportDebugMsg('moved '+params.title);
						ajxwxf.updateMoveStatus(params.from, 'LuckyRenameActionFailed', ajxwxf.msgs.LuckyRenameActionFailed2);
					} else {
						ajxwxf.reportDebugMsg('no edit done for '+params.title);
					}
				} else if (typeof jqXHR.error != "undefined" && typeof jqXHR.error.code != "undefined") { // API action failed
					if ( i < 5 ) {							//number of retries in case of failure
						window.setTimeout( ajxwxf.doCall, 3000 );
						i++;
						ajxwxf.retrymsg = ajxwxf.msgs.failretry;
					}
				} else if (typeof jqXHR.move != "undefined" && typeof jqXHR.move.from != "undefined" && typeof jqXHR.move.to != "undefined") { // move succeeded
					ajxwxf.updateMoveStatus(params.from, 'LuckyRenameActionCompleted');
					ajxwxf.totalActionsDone++; // +1
				} else {
				ajxwxf.reportDebugMsg(ajxwxf.msgs.unknownstatus);
				}
			};
		ajxwxf.doCall = function () {

			ajxwxf.api.postWithEditToken( params ).then( function ( data ) {

				ajxwxf.callback(data);

			}, function ( code, data ) {
				//fail
			});
		};
		ajxwxf.doCall();
	};

ajxwxf.getUsageAndRedir = function(int,filepageText) {
	ajxwxf.redirectlinksdone[int] = 1;
	ajxwxf.api.get( {'action':'query','format':'json','prop':'linkshere','lhlimit':'500','titles': ajxwxf.linkshere1[int].title} ).then( function ( data ) {
		if (typeof data != "undefined" && typeof data.query != "undefined" && typeof data.query.pages != "undefined" ) {
			ajxwxf.sourcePageID = Object.keys(data.query.pages)[0];
			if (typeof data.query.pages[ ajxwxf.sourcePageID ] != "undefined" && typeof data.query.pages[ ajxwxf.sourcePageID ].linkshere != "undefined") {
				ajxwxf.redirectlinks[int] = data.query.pages[ ajxwxf.sourcePageID ].linkshere;
				ajxwxf.linkshere2 = ajxwxf.linkshere2.concat(ajxwxf.redirectlinks[int]);
			}
		}
		ajxwxf.api.get( {'action':'query','format':'json','prop':'fileusage','fulimit':'500','titles':ajxwxf.linkshere1[int].title} ).then( function ( data ) {
			if (typeof data != "undefined" && typeof data.query != "undefined" && (( typeof data.query.pages[ mw.config.get('wgArticleId') ] != "undefined" && typeof data.query.pages[ mw.config.get('wgArticleId') ].fileusage != "undefined" ) || ( typeof data.query.pages[-1] != "undefined" && typeof data.query.pages[-1].fileusage != "undefined" ) ) ) { //data.query.pages[-1] is for a file on Commons
	 			ajxwxf.sourcePageID = Object.keys(data.query.pages)[0];
	 			ajxwxf.redirectusage[int] = data.query.pages[ ajxwxf.sourcePageID ].fileusage;
				ajxwxf.fileUsages2 = ajxwxf.fileUsages2.concat(ajxwxf.redirectusage[int]);
			}
			if ( int == ajxwxf.linkshere1.length-1 ) { //last entry
				ajxwxf.DoRename(filepageText,1);
			}
		});
	});
};

ajxwxf.redirectlinks = {};
ajxwxf.redirectlinksdone = {};
ajxwxf.redirectusage = {};
ajxwxf.redirectusagedone = {};

ajxwxf.DoRename = function (filepageText,skipLinksHere,int,int2,int3){


	ajxwxf.disableMoveButton('nochange'); //no need to use this button anymore, we've started, but don't change the bgcolor of the filename field
	ajxwxf.totalActionsDone = 0;
	ajxwxf.oldFile = mw.config.get('wgPageName').replace(/_/g, ' ');
	ajxwxf.newFile = 'File:' + ajxwxf.form.title.getValue();
	ajxwxf.Summary = ajxwxf.msgs.summary.replace('\1',' [[:' + ajxwxf.oldFile.replace( /_/g, ' ') + ']] ').replace('\2',' [[:' + ajxwxf.newFile + ']] ');

	//replacement of interwiki links that aren't interwiki links (e.g. [[:w:File:Example.jpg]] on English Wikipedia), more sites could be added as needed, let me know if you use LuckyRename on another project
	if ( mw.config.get('wgSiteName') == 'Wikipedia' && mw.config.get('wgContentLanguage') == 'en' ) {
		ajxwxf.interWiki = '|(\[\[:?[Ww]:|\[\[:?[Ee][Nn]:|\[\[:?[Ww]:[Ee][Nn]:|\[\[:?[Ee][Nn]:[Ww]:)\\b[^:]+:';
	} else if ( mw.config.get('wgSiteName') == 'Wikipedia' ) {
		ajxwxf.interWiki = '|(\[\[:?[Ww]:' + mw.config.get('wgContentLanguage') + ':|\[\[:?' + mw.config.get('wgContentLanguage') + ':)\\b[^:]+:'; //does not catch e.g. [[:JA:Example.jpg]] but I don't care
	} else if ( mw.config.get('wgSiteName') == 'Wikimedia Commons' || mw.config.get('wgSiteName') == 'Beta Wikimedia Commons' ) {
		ajxwxf.interWiki = '|\[\[:?[Cc]:\\b[^:]+:';
	} else if ( mw.config.get('wgSiteName') == 'Meta' ) {
		ajxwxf.interWiki = '|\[\[:?[Mm]:\\b[^:]+:';
	}

	ajxwxf.oldFileReplaceFirstChar = ajxwxf.escapeRegExp(ajxwxf.oldFile).replace( /File:/, '').slice(0, 1).toUpperCase() + ajxwxf.escapeRegExp(ajxwxf.oldFile).replace( /File:/, '').slice(0, 1).toLowerCase();
	ajxwxf.oldFileReplaceRest = ajxwxf.escapeRegExp(ajxwxf.oldFile).replace ( /File:/, '').slice(1, ajxwxf.escapeRegExp(ajxwxf.oldFile).length);
	ajxwxf.oldFileReplace = new RegExp('([\n=\|\^]\\s*|([^a-z]:|[^:])\\b[^:]+:' + ajxwxf.interWiki + ')[' + ajxwxf.oldFileReplaceFirstChar + ']' + ajxwxf.oldFileReplaceRest.replace( /[_ ]/g, '[_ ]'), "g");
	ajxwxf.newFileReplace = ajxwxf.newFile.replace( /File:/, '').replace ( /_/g, ' ').slice(0, 1).toUpperCase() + ajxwxf.newFile.replace( /File:/, '').replace( /_/g, ' ').slice(1, ajxwxf.newFile.replace( /File:/, '').length);
	// Explain regexp part 1 (filenames without a namespace) [\n=\|\^]\\s?
	// \n : filename preceded by a newline (typical for <gallery> usage)
	// = : filename preceded by an equals sign (typical for use as a named template argument)
	// | : filename preceded by a pipe (typical for use as an unnamed template argument)
	// \^ : filename preceded by start-of-document (unlikely, perhaps if someone created a talk page without a header and started with "Example.jpg is a good image", it would have to be linked later on to get detected by linkshere though)
	// \\s? : whitespace character that may or may not exist between the above and the filename
	// part 2 (filenames with a namespace) ([^a-z]:|[^:])\\b[^:]+:
	// ([^a-z]:|[^:]) : non-letter character plus a colon or a non-colon character. This ensures c:File:Example.jpg won't match but [[:File:Example.jpg]] or File:Example.jpg on a new line (common in <gallery> usage) will
	// \\b[^:]+: : beginning of a word (does not match colons, asterisks, etc), any character that isn't a colon, colon (this matches any namespace, e.g. File:, Image:, Datei:, ファイル:, etc)

	if ( ajxwxf.overridden == 1 ) {
		ajxwxf.Summary = ajxwxf.Summary + ajxwxf.msgs.summaryoverride;
		ajxwxf.SummaryFilePage = ajxwxf.SummaryFilePage + ajxwxf.msgs.summaryoverride;
		ajxwxf.SummaryForMove = ajxwxf.SummaryForMove + ajxwxf.msgs.summaryoverride;
	}

	if ( typeof ajxwxf.fileUsages1 == 'undefined' && !ajxwxf.fileUsages1done ) {
		ajxwxf.api.get( {'action':'query','format':'json','prop':'fileusage','fulimit':'500','titles':mw.config.get('wgPageName')} ).then( function ( data ) {
			ajxwxf.fileUsages1done = 1;

			if (typeof data != "undefined" && typeof data.query != "undefined" && ( ( typeof data.query.pages[ mw.config.get('wgArticleId') ] != "undefined" && typeof data.query.pages[ mw.config.get('wgArticleId') ].fileusage != "undefined" ) || ( typeof data.query.pages[-1] != "undefined" && typeof data.query.pages[-1].fileusage != "undefined" ) ) ) {

	 			ajxwxf.sourcePageID = Object.keys(data.query.pages)[0];
	 			ajxwxf.fileUsages1 = data.query.pages[ ajxwxf.sourcePageID ].fileusage;
			}
			ajxwxf.DoRename(filepageText);
		});
		ajxwxf.reportDebugMsg('exit fileUsages1');
		return;
	}

	if ( typeof ajxwxf.linkshere1 == "undefined" ) { ajxwxf.linkshere1 = []; }
	if ( typeof ajxwxf.linksheretalk == "undefined" ) { ajxwxf.linksheretalk = []; }
	if ( typeof ajxwxf.fileUsages1 == "undefined" ) { ajxwxf.fileUsages1 = []; }
	ajxwxf.linkshere2 = ajxwxf.linkshere1;
	ajxwxf.fileUsages2 = ajxwxf.fileUsages1;

	ajxwxf.waitforredirectinfo = 0;

	for (int = 0; int < ajxwxf.linkshere1.length; int++) {
		if ( typeof ajxwxf.linkshere1[int].redirect != "undefined" ) {
			if ( typeof ajxwxf.redirectlinks[int] == 'undefined' && !ajxwxf.redirectlinksdone[int] ) {
				ajxwxf.waitforredirectinfo = 1;
				ajxwxf.getUsageAndRedir(int,filepageText);
			}
		}
	}

	if ( ajxwxf.waitforredirectinfo ) {
		return;
	}

	ajxwxf.allUsages = ajxwxf.linkshere2.concat(ajxwxf.fileUsages2).concat(ajxwxf.linksheretalk);

	ajxwxf.totalActionsTodo = ajxwxf.allUsages.length;

	ajxwxf.queueTableMoveRow = '<tr><td class="LuckyRenamePendingBlink LuckyRenameMoveStatusCell" id="movePage_' + encodeURIComponent(ajxwxf.oldFile).replace( /[%\._]/g, '') + '">' + ajxwxf.msgs.pending + '</td><td id="movePageStatusMsg_' + encodeURIComponent(ajxwxf.oldFile).replace( /[%\._]/g, '') + '"></td><td id="movePageDescription_' + encodeURIComponent(ajxwxf.oldFile).replace( /[%\._]/g, '') + '">' + ajxwxf.msgs.move + ' ' + ajxwxf.msgs.to + ' <a href="' + mw.config.get('wgServer') + '/wiki/' + encodeURIComponent(ajxwxf.newFile) + '">' + ajxwxf.newFile + '</a>' + '</td></tr>';
	ajxwxf.queueTableRedirSpeedyRow = '<tr><td class="LuckyRenamePendingBlink LuckyRenameReplaceStatusCell" id="replaceusage_' + encodeURIComponent(ajxwxf.oldFile).replace( /[%\._]/g, '') + '">' + ajxwxf.msgs.pending + '</td><td id="replaceusageStatusMsg_' + encodeURIComponent(ajxwxf.oldFile).replace( /[%\._]/g, '') + '"></td><td id="replaceusageDescription_' + encodeURIComponent(ajxwxf.oldFile).replace( /[%\._]/g, '') + '">' + ajxwxf.msgs.redirtagspeedy1 + ' <a href="' + mw.config.get('wgServer') + '/wiki/' + encodeURIComponent(ajxwxf.oldFile) + '">' + ajxwxf.oldFile + '</a>' + ajxwxf.msgs.redirtagspeedy2 + '</td></tr>';
	ajxwxf.queueTableFilePageRow = '<tr><td class="LuckyRenamePendingBlink LuckyRenameReplaceStatusCell" id="replaceusage_' + encodeURIComponent(ajxwxf.newFile).replace( /[%\._]/g, '') + '">' + ajxwxf.msgs.pending + '</td><td id="replaceusageStatusMsg_' + encodeURIComponent(ajxwxf.newFile).replace( /[%\._]/g, '') + '"></td><td id="replaceusageDescription_' + encodeURIComponent(ajxwxf.newFile).replace( /[%\._]/g, '') + '">' + ajxwxf.msgs.edit + '<a href="' + mw.config.get('wgServer') + '/wiki/' + encodeURIComponent(ajxwxf.newFile) + '">' + ajxwxf.newFile + '</a></td></tr>';
	ajxwxf.queueTable = '<table class="progresstable">';
	if ( ajxwxf.filepageText != ajxwxf.filepageTextNew ) { //only add a row for the file page if we're actually going to edit it
		ajxwxf.queueTable = ajxwxf.queueTable + ajxwxf.queueTableFilePageRow;
	}
	ajxwxf.allUsagesArray = []; //initialize empty array

	for (int = 0; int < ajxwxf.allUsages.length; int++) {
		if ( ajxwxf.allUsagesArray.indexOf(ajxwxf.allUsages[int].title) == -1 && ajxwxf.allUsages[int].title != ajxwxf.oldFile ) { //not a duplicate and not the move target which is processed by DoEditPages. duplicates happen when one page links AND uses an image
			ajxwxf.allUsagesArray.push(ajxwxf.allUsages[int].title); //add title to our array so we'll know if we hit a duplicate
			if ( typeof ajxwxf.allUsages[int].redirect != "undefined" ) {
				ajxwxf.usageRedirectIndicator = '<span style="font-weight:bold;"> R</span>';
				ajxwxf.usageNoRedirect = '?redirect=no';
			} else {
				ajxwxf.usageRedirectIndicator = '';
				ajxwxf.usageNoRedirect = '';
			}

			ajxwxf.queueTable = ajxwxf.queueTable + '<tr><td class="LuckyRenamePendingBlink LuckyRenameReplaceStatusCell" id="replaceusage_' + encodeURIComponent(ajxwxf.allUsages[int].title).replace( /[%\._]/g, '') + '">' + ajxwxf.msgs.pending + '</td><td id="replaceusageStatusMsg_' + encodeURIComponent(ajxwxf.allUsages[int].title).replace( /[%\._]/g, '') + '"></td><td id="replaceusageDescription_' + encodeURIComponent(ajxwxf.allUsages[int].title).replace( /[%\._]/g, '') + '">' + ajxwxf.msgs.edit + '<a href="' + 'https://'+ajxwxf.form.wiki.getValue() + mw.config.get('wgArticlePath').replace( '$1', ajxwxf.escapeReplacement(encodeURIComponent(ajxwxf.allUsages[int].title)) ) + ajxwxf.usageNoRedirect + '">' + ajxwxf.allUsages[int].title + '</a>' + ajxwxf.usageRedirectIndicator + '</td></tr>';
		} else {
			ajxwxf.totalActionsTodo = ajxwxf.totalActionsTodo - 1; //one less thing to do
		}
	}

	ajxwxf.queueTable = ajxwxf.queueTable + '</table><hr>';
	$( '#ajxwxf-uploadform' ).append(ajxwxf.queueTable);

	ajxwxf.replaceUsage = function(articlepageText,articleTitle,int,allowedToEditLucky,allowedToEditUserscript,articlepageTextNew,redirectFileReplaceFirstChar,redirectFileReplaceRest,redirectFileReplace,allowedToEditAutomaticallyGeneratedPage) {

		if (!articlepageText) {
			ajxwxf.api.get( {'action':'query','format':'json','export':'true','titles': articleTitle} ).then( function ( data ) {
				ajxwxf.reportDebugMsg('got filepagetext of '+articleTitle+' for replaceUsage');
				ajxwxf.pageText = ajxwxf.getWikitextFromExport(data.query.export['*']); 
				if ( ajxwxf.pageText ) {
					ajxwxf.reportDebugMsg('start replaceUsage');
					ajxwxf.replaceUsage(ajxwxf.pageText,articleTitle,int);
				} else {
					ajxwxf.reportDebugMsg('extraction of wikitext failed for '+articleTitle);
				}
			});
			return;
		}

		articlepageTextNew = articlepageText.replace( ajxwxf.oldFileReplace, '$1' + ajxwxf.escapeReplacement(ajxwxf.newFileReplace));
			for (int3 = 0; int3 < ajxwxf.allUsages.length; int3++) {
				if ( typeof ajxwxf.allUsages[int3].redirect != "undefined" ) {
					ajxwxf.redirectTitle = ajxwxf.allUsages[int3].title;
					redirectFileReplaceFirstChar = ajxwxf.escapeRegExp(ajxwxf.redirectTitle).replace( /File:/, '').slice(0, 1).toUpperCase() + ajxwxf.escapeRegExp(ajxwxf.redirectTitle).replace ( /File:/, '').slice(0, 1).toLowerCase();
					redirectFileReplaceRest = ajxwxf.escapeRegExp(ajxwxf.redirectTitle).replace( /File:/, '').slice(1, ajxwxf.escapeRegExp(ajxwxf.redirectTitle).length);
					redirectFileReplace = new RegExp('([\n=\|\^]\\s?|([^a-z]:|[^:])\\b[^:]+:)[' + redirectFileReplaceFirstChar + ']' + redirectFileReplaceRest.replace( /[_ ]/g, '[_ ]'), "g");
					articlepageTextNew = articlepageTextNew.replace( redirectFileReplace, '$1' + ajxwxf.escapeReplacement(ajxwxf.newFileReplace));
				}
			}
		allowedToEditLucky = ajxwxf.allowBots(articlepageText, 'luckyrename');
		allowedToEditUserscript = ajxwxf.allowBots(articlepageText, 'userscript');
		allowedToEditAutomaticallyGeneratedPage = articlepageText.search( ajxwxf.automaticallyGeneratedTemplate );
	
		if ( articlepageText != articlepageTextNew && allowedToEditLucky && allowedToEditUserscript && typeof ajxwxf.allUsages[int].title != "undefined" && allowedToEditAutomaticallyGeneratedPage == -1 ) {
			ajxwxf.reportDebugMsg('make API call to replace usage in '+ajxwxf.allUsages[int].title);
			ajxwxf.articledata = {
				action: 'edit',
				minor: '1',
				nocreate: true,
				title: ajxwxf.allUsages[int].title,
				summary: ajxwxf.Summary,
				text: articlepageTextNew,
				watchlist: 'nochange',
			};
			ajxwxf.reportDebugMsg('Replacing file name on ' + ajxwxf.allUsages[int].title + ' from ' + ajxwxf.oldFile + ' to ' + ajxwxf.newFile);
			ajxwxf.doAPICall( ajxwxf.articledata, function ( r ) {	} );
		} else if ( ! allowedToEditLucky || ! allowedToEditUserscript ) {
			ajxwxf.reportDebugMsg('allowedToEditLucky or allowedToEditUserscript is false');
			ajxwxf.totalActionsDone++; // +1
		} else if ( allowedToEditAutomaticallyGeneratedPage != -1 ) {
			ajxwxf.reportDebugMsg('page automatically generated, not editing: '+ajxwxf.allUsages[int].title);
			ajxwxf.totalActionsDone++; // +1
		} else if ( articlepageText == articlepageTextNew ) {
			ajxwxf.reportDebugMsg('no instances of filename found on '+ajxwxf.allUsages[int].title);
			ajxwxf.totalActionsDone++; // +1
		} else if ( typeof int != "undefined" && typeof ajxwxf.allUsages[int].title != "undefined" ) {
			ajxwxf.reportDebugMsg('unknown error: '+ajxwxf.allUsages[int].title);
			ajxwxf.totalActionsDone++; // +1
		}
	};

	ajxwxf.DoReplaceUsages = function() {
		if (typeof ajxwxf.linkshere2[0] != "undefined" || typeof ajxwxf.fileUsages2[0] != "undefined") { //something links here or this is used somewhere
			ajxwxf.allUsagesArray = [];
			for (int = 0; int < ajxwxf.allUsages.length; int++) {
				if ( ajxwxf.allUsagesArray.indexOf(ajxwxf.allUsages[int].title) == -1 && ajxwxf.allUsages[int].title != ajxwxf.newFile && ajxwxf.allUsages[int].title != ajxwxf.oldFile ) { //not a duplicate and not the move target which is processed by DoEditPages. Also not the current page. Duplicates happen when one page links AND uses an image
					ajxwxf.allUsagesArray.push(ajxwxf.allUsages[int].title); //add title to our array so we'll know if we hit a duplicate
					ajxwxf.replaceUsageTitle = ajxwxf.allUsages[int].title;
					ajxwxf.replaceUsage(null,ajxwxf.replaceUsageTitle,int);
				} //end not a duplicate
			} //end for
		} else {
			ajxwxf.reportDebugMsg('nothing links here. At all.');
		}	//end something links here or this is used somewhere
	}; //end DoReplaceUsages

	ajxwxf.WaitForPendingIntMax = 300; // 300*200ms=1 minute
	ajxwxf.WaitForPendingInt = 0;

	ajxwxf.SetAllPendingTableCellsToSkipped = function(int) {
		for (int = 0; int < document.getElementsByClassName('LuckyRenameReplaceStatusCell').length; int++) {
			document.getElementsByClassName('LuckyRenameReplaceStatusCell')[int].classList = [ 'LuckyRenameActionSkipped LuckyRenameReplaceStatusCell' ];
			document.getElementsByClassName('LuckyRenameReplaceStatusCell')[int].innerHTML = ajxwxf.msgs.LuckyRenameActionFailed;
		}
	};

	ajxwxf.DoReplaceUsages();


}; // end ajxwxf.DoRename function

ajxwxf.getWikitextFromExport = function(text) {
	if ( text.match(/[^]*<text bytes[^>]*>([^]*)<\/text>[^]*/) ) {
		return text.replace(/[^]*<text bytes[^>]*>([^]*)<\/text>[^]*/, '$1').replace(/\&lt\;/g, '<').replace(/\&gt\;/g, '>').replace(/\&amp\;/g, '&');
	} else {
		return '';
	}
};

mw.loader.using( ['oojs-ui-core','mediawiki.api','mediawiki.ForeignApi'] ).done( function () {

} );

// </nowiki>