Jump to content

User:Ahecht/Scripts/potd-helper.js

From Wikipedia, the free encyclopedia
This is an old revision of this page, as edited by Ahecht (talk | contribs) at 16:32, 30 May 2022 (not sandbox). The present address (URL) is a permanent link to this revision, which may differ significantly from the current revision.
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.
//jshint maxerr:512
mw.loader.using( [ 'mediawiki.util', 'oojs-ui' ], function () {
	var potdScriptLongTitle = "Picture of the Day Helper",
		potdScriptShortTitle = "POTDHelper",
		potdScriptLocation = "User:Ahecht/Scripts/potd-helper.js",
		potdFPCategory = 'Featured pictures',
		debug = false;
	
	function POTDHelper() {
		if (typeof XRegExp === 'undefined') {
			mw.loader.load('https://tools-static.wmflabs.org/cdnjs/ajax/libs/xregexp/3.2.0/xregexp-all.js');
		}
		
		var config = {
			fpCategory: potdFPCategory,
			fpcPrefix: 'Wikipedia:Featured picture candidates/',
			potdPrefix: 'Template:POTD/',
			editSummaryPattern: '[[File:%0]] scheduled for [[WP:POTD|POTD]] on [[Template:POTD/%1|%1]]',
			editSummarySuffix: ' ([[' + potdScriptLocation + '|' + potdScriptShortTitle + ']])',
			submitMessageHeader: '<strong>Submitting Picture of the Day:</strong><ul><li>',
			submitMessageFooter: '</li></ul>',
			submitMessages: [],
			query: {
				action: 'query',
				formatversion: '2'
			},
			revQuery: {
				prop: 'revisions',
				rvprop: 'content',
				rvslots: 'main',
				rvlimit: '1',
				rvsection: '0',
			},
			imageQuery: {
				prop: 'imageinfo|revisions|categories',
				iiprop: 'user',
				iilimit: 'max',
				cllimit: 'max'
			},
			nomQuery: {
				rvprop: 'user',
				rvdir: 'newer'
			},
			edit: {
				action: 'edit',
				watchlist: 'preferences',
				recreate: 1
			}
		};
		
		function wikiLink(message) {
			message = message.replace(/\[\[(.*?)\]\]/g, function(s,v) {
				var url = mw.config.get("wgServer") + mw.config.get("wgArticlePath").replace("$1", encodeURI(v));
				return '<a href="'+ url + '">' + v + "</a>";
			} );
			return message;
		}

		function showImageError(error) {
			error = "The script " + error + " Check that the image name [[File:" + imageInput.value + "]] is correct.";
			imageMessage.setLabel(new OO.ui.HtmlSnippet(wikiLink(error)));
			imageMessage.toggle(true);
			imageMessage.scrollElementIntoView();
		}
		
		function showTitleError(error) {
			error = "The script " + error + " Check that the article name [[" + titleInput.value + "]] is correct.";
			titleMessage.setLabel(new OO.ui.HtmlSnippet(wikiLink(error)));
			titleMessage.toggle(true);
			titleMessage.scrollElementIntoView();
		}
		
		function showDateError(error) {
			dateMessage.setLabel(new OO.ui.HtmlSnippet(wikiLink(error)));
			dateMessage.toggle(true);
			dateMessage.scrollElementIntoView();
		}
		
		function showSubmitMessage(message, type = 'notice') {
			config.submitMessages.push(wikiLink(message));
			var label = new OO.ui.HtmlSnippet( config.submitMessageHeader + config.submitMessages.join("</li><li>") + config.submitMessageFooter );
			submitMessage.setLabel(label);
			var types = ['notice', 'success', 'warning', 'error'];
			if (types.indexOf(type) > types.indexOf(submitMessage.type)) {
				submitMessage.setType(type);
			}
			submitMessage.toggle(true);
			submitMessage.scrollElementIntoView();
		}
		
		function getImageInfo() {
			function getNominator(nom) {
				if (nom && nom.query && nom.query.pages && nom.query.pages[0] && nom.query.pages[0].revisions) {
					if (nom.query.pages[0].revisions[0] && nom.query.pages[0].revisions[0].user && nom.query.pages[0].revisions[0].user.length) {
						nominatorInput.setValue("User:" + nom.query.pages[0].revisions[0].user);
						console.log("Nominated by " + nominatorInput.value);
						if (nominatorInput.value == uploaderInput.value) {
							nominatorInput.setValue();
						}
					} else {
						showImageError("was unable to parse API data on nomination page [[" + nomination + "]].");
					}
				} else {
					showImageError("was unable to find the nomination page [[" + nomination + "]].");
				}
			}
			
			function getNomination(imageData) {
				if (imageData.revisions && imageData.revisions.length && imageData.categories && imageData.categories.length) {
					var cats=[];
					imageData.categories.forEach((cat) => cats.push(cat.title));
					if (cats.includes('Category:' + config.fpCategory)) {
						if (imageData.revisions[0] && imageData.revisions[0].slots && imageData.revisions[0].slots.main && imageData.revisions[0].slots.main.content) {
								var content = imageData.revisions[0].slots.main.content,
									nominations = [];
								try {
									nominations = XRegExp.matchRecursive(content, "\\{\\{featured\\s*picture\\s*\\|", "\\}}", 'i');
								} catch(error) {
									console.warn(error + " when parsing local file description.");
									console.log(content);
									showImageError("was unable to parse the {{Featured picture}} template on [[" + imageInput.value + "]]: " + error + ".");
								}
								if (nominations.length && nominations[0].length) {
									var nomination = config.fpcPrefix + nominations[0];
									console.log("Nominated at " + nomination);
									new mw.Api().get(
											Object.assign( {titles: nomination}, config.query, config.revQuery, config.nomQuery )
										).fail(function(code, error) {
											console.warn("API error retrieving nomination:");
											console.warn(error);
											showImageError("got an API error '" + code + "' when retrieving the nomination page [[" + nomination + "]]: " + error.error.info);
										}).done( getNominator );
								} else {
									showImageError("was unable to find the featured picture template in the local description. Are you sure this is a featured image on the English Wikipedia?");
								}
						} else {
							showImageError("was unable to parse API data on the image.");
						}
					} else {
						showImageError("was unable to find [[Category:" + config.fpCategory + "]] on that image. Are you sure this is a featured image on the English Wikipedia?");
					}
				} else {
					showImageError("was unable to find a local file description. Are you sure this is a featured image on the English Wikipedia?");
				}
			}
			
			function getUploader(imageData) {
				if (imageData.imageinfo && imageData.imageinfo.length) {
					info = imageData.imageinfo;
					info = info[info.length - 1];
					if (info.user) {
						uploaderInput.setValue("User:" + info.user);
						console.log("Uploaded by " + uploaderInput.value);
						getNomination(imageData);
					} else {
						console.warn("Error parsing API respose for image uploader:");
						console.log(data);
						showImageError("was unable to parse the API response when trying to determine who uploaded the image.");
					}
				} else {
					console.warn("Error parsing API respose for image uploader:");
					console.log(data);
					showImageError("was unable to parse the API response when trying to determine who uploaded the image.");
				}
			}
			
			imageMessage.toggle(false);
			var imageName = 'File:' + imageInput.value;
			new mw.Api().get(
				Object.assign( {titles: imageName}, config.query, config.revQuery, config.imageQuery )
			).fail(function(code, error) {
				console.warn("API error retrieving image info:");
				console.warn(error);
				showImageError("got an API error '" + code + "' when querying image [[" + imageName + "]]: " + error.error.info);
			}).done( function(data) {
				if (data && data.query && data.query.pages && data.query.pages[0]) {
					if (data.query.pages[0].missing) {
						showImageError("was unable find the image.");
					} else {
						config.imageData = data.query.pages[0];
						getUploader(config.imageData);
					}
				} else {
					console.warn("Error parsing API respose for image:");
					console.log(data);
					showImageError("was unable to parse the API response when trying get info on the image.");
				}
			} );
		}
		
		function getCaption() {
			function extractCaption(data) {
				var extract = "";
				
				if (data && data.query && data.query.pages && data.query.pages[0]) {
					config.titleData = data.query.pages[0];
					if (config.titleData.revisions && config.titleData.revisions[0] && config.titleData.revisions[0].slots
						&& config.titleData.revisions[0].slots.main && config.titleData.revisions[0].slots.main.content) {

						var content = config.titleData.revisions[0].slots.main.content,
							xValues = [];
						
						content = content.replace(/(\[\[File:.*\]\][\s\n]*)*/ig, '');
						
						try {
							xValues = XRegExp.matchRecursive(content, "\\{{", "\\}}[\s\n]*", 'gi', {valueNames: ['b', 'l', 'm', 'r']});
						} catch(error) {
							console.warn(error + " when parsing linked article.");
							console.log(content);
							showTitleError("encountered an error when parsing the article's lead section: " + error + ".");
						}
						if (xValues.length) {
							var startSub = 0;

							for (const x of xValues) {
								if (x.name && x.name=='b' && x.start) {
									startSub=x.start;
									break;
								}
							}

							extract = content.substr(startSub).split('\n\n')[0];
							
							
							if (extract && extract.length) {
								captionInput.setValue(extract.replace(/'''(.*?)'''/, "'''[["+titleInput.value + "]]'''"));
							} else {
								showTitleError("was unable to find non-template content in lead section.");
								extract = "";
							}
						} else {
							showTitleError("was unable to parse the article's lead section.");
						}
					} else if (config.titleData.missing) {
						console.warn("Could not find revisions for Title:");
						console.log(data);
						showTitleError("was unable to find an article with that title.");
					} else {
						console.warn("Error parsing API respose when fetching lead section:");
						console.log(data);
						showTitleError("encountered an error parsing the API response when fetching the article's lead section.");
					}
				} else {
					console.warn("Error parsing API respose when fetching lead section:");
					console.log(data);
					showTitleError("encountered an error parsing the API response when fetching the article's lead section.");
				}
			}
			
			titleMessage.toggle(false);
			new mw.Api().get(
					Object.assign( {titles: titleInput.value}, config.query, config.revQuery )
				).fail(function(code, error) {
					console.warn("API error retrieving linked article:");
					console.warn(error);
					showTitleError("encountered an API error '" + code + "' when retrieving the article: " + error.error.info);
				}).done( extractCaption );
		}
		
		function finishSubmit(done = false) {
			if (done) {showSubmitMessage("Done!", 'success');}
			while (closeButton.isPending()) {closeButton.popPending();}
			closeButton.toggleFramed(true).setDisabled(false);
			while (submitButton.isPending()) {submitButton.popPending();}
			submitButton.toggleFramed(true);
			checkButtons();
		}
		
		function writeUserTalk(user) {
			var templateText = "\n{{subst:" + "NotifyPOTD|1=" + 
				"|2=File:" + imageInput.value +
				"|3=" + dateInput.value +
				(commentsInput.value.length ? ("|4=" + commentsInput.value) : ""),
				userTalk = "";
			
			if (user == 'uploader') {
				userTalk = uploaderInput.value;
				templateText += "|action=uploaded}}";
			} else if ((user == 'nominator') && (nominatorInput.value != uploaderInput.value)) {
				userTalk = nominatorInput.value;
				templateText += "|action=nominated}}";
			}
			
			if (userTalk.search(/^User:./i) == 0) { //Value starts with "User:"
				console.log(templateText);
				userTalk = userTalk.replace(/^User:/i, 'User talk:');
				var params = Object.assign( {
					title: userTalk,
					appendtext: templateText,
					summary: config.editSummary,
					redirect: 1,
					nocreate: 1
				}, config.edit );
				
				if (debug) {
					console.log(params);
					showSubmitMessage("Added message to [[" + userTalk + "]].");
					if (user == 'uploader') {
						writeUserTalk('nominator');
					} else {
						finishSubmit(true);
					}
				} else {
					new mw.Api().postWithEditToken(params).fail( function(code, error) {
						console.error("API error when creating article talk page message: ");
						console.error(error);
						showSubmitMessage("ERROR '" + code + "' when creating message on [[" + userTalk + "]]: " + error.error.info, 'warning');
						if (user == 'uploader') {
							writeUserTalk('nominator');
						} else {
							finishSubmit(true);
						}
					} ).done( function() {
						showSubmitMessage("Added message to [[" + userTalk + "]].");
						if (user == 'uploader') {
							writeUserTalk('nominator');
						} else {
							finishSubmit(true);
						}
					} );
				}
			} else if (user == 'uploader') {
				writeUserTalk('nominator');
			} else {
				finishSubmit(true);
			}
		}
		
		function writeArticleTalk(){
			var templateText = "\n{{subst:" + "UpcomingPOTD" + 
				"|1=File:" + imageInput.value +
				"|2=" + dateInput.value +
				(commentsInput.value.length ? ("|3=" + commentsInput.value) : "") +
				"}}",
				titleTalk = 'Talk:' + titleInput.value;
			
			console.log(templateText);
			
			var params = Object.assign( {
				title: titleTalk,
				appendtext: templateText,
				summary: config.editSummary,
				redirect: 1
			}, config.edit );
			
			if (debug) {
				console.log(params);
				showSubmitMessage("Added message to [[" + titleTalk + "]].");
				writeUserTalk('uploader');
			} else {
				new mw.Api().postWithEditToken(params).fail( function(code, error) {
					console.error("API error when creating article talk page message: ");
					console.error(error);
					showSubmitMessage("ERROR '" + code + "' when creating message on [[" + titleTalk + "]]: " + error.error.info, 'warning');
					writeUserTalk('uploader');
				} ).done( function() {
					showSubmitMessage("Added message to [[" + titleTalk + "]].");
					writeUserTalk('uploader');
				} );
			}
		}
		
		function writePOTDTemplate() {
			var templateName = config.potdPrefix + dateInput.value;
			if (!texttitleInput.value.length) {
				texttitleInput.setValue(titleInput.value);
			}
			if (!sizeInput.value.length) {
				sizeInput.setValue('350');
			}
			if (!captionInput.value.length) {
				captionInput.setValue("'''[[<!--article-->]]'''");
			}
			var templateText = "{{POTD {{{1|{{{style|default}}}}}}" +
				"\n|image=" + imageInput.value +
				"\n|size=" + sizeInput.value +
				"\n|title=[[" + titleInput.value + "]]" +
				"\n|texttitle=" + texttitleInput.value +
				( alttextInput.value.length ? ("\n|alttext=" + alttextInput.value) : "" ) +
				"\n|caption=\n\n" + captionInput.value +
				"\n\n|credit=" + creditInput.value + ( secondaryCreditInput.value.length ? ("; " + secondaryCreditInput.value) : "" ) +
				"\n}}<noinclude>[[Category:Wikipedia Picture of the day {{#time:F Y|{{SUBPAGENAME}}}}]]" + 
				"\n\n== See also ==" + 
				"\n* [[Template:POTD{{#ifeq:{{BASEPAGENAME}}|POTD protected||&#32;protected}}/{{SUBPAGENAME}}]]</noinclude>";
			
			console.log(templateText);
			
			var params = Object.assign( {
				createonly: 1,
				title: templateName,
				text: templateText,
				summary: 'Creating a [[WP:POTD|POTD]] template for [[File:' + imageInput.value + ']]' + config.editSummarySuffix
			}, config.edit );
			
			if (debug) {
				console.log(params);
				showSubmitMessage("Created [[" + templateName + "]].");
				writeArticleTalk();
			} else {
				new mw.Api().postWithEditToken(params).fail( function(code, error) {
					console.error("API error when creating template: ");
					console.error(error);
					showSubmitMessage("ERROR '" + code + "' when creating template [[" + templateName + "]]: " + error.error.info, 'error');
					finishSubmit(true);
				} ).done( function() {
					showSubmitMessage("Created [[" + templateName + "]].");
					writeArticleTalk();
				} );
			}
		}
		
		function writeLocalDesc() {
			var params = Object.assign( {
				title: 'File:' + imageInput.value,
				appendtext: '\n{{Picture of the day|' + dateInput.value + '}}',
				summary: config.editSummary,
				redirect: 1,
				nocreate: 1
			}, config.edit );
				
			new mw.Api().postWithEditToken(params).fail( function(code, error) {
					console.error("API error when adding template to local file description: ");
					console.error(error);
					showSubmitMessage("ERROR '" + code + "' when adding template to [[File:" + imageInput.value + "]]: " + error.error.info, 'warning');
					finishSubmit(true);
				} ).done( function() {
					showSubmitMessage("Added message to [[File:" + imageInput.value + "]].");
					writePOTDTemplate();
				} );
		}
		
		function checkButtons() {
			if (!titleInput.value.length) {
				autofillTitleButton.setDisabled(true);
			} else {
				autofillTitleButton.setDisabled(false);
			}
			
			if (!imageInput.value.length) {
				autofillImageButton.setDisabled(true);
			} else {
				autofillImageButton.setDisabled(false);
			}
			
			if (titleInput.value.length && imageInput.value.length && dateInput.value.length && creditInput.value.length && !submitButton.isPending()) {
				submitButton.setDisabled(false);
			} else {
				submitButton.setDisabled(true);
			}
		}
		
		function preCheck() {
			var imageData = config.imageData;
			
			if (imageData.categories && imageData.categories.length){
				var cats=[];
				imageData.categories.forEach((cat) => cats.push(cat.title));
				if (cats.includes('Category:' + config.fpCategory)) {
					var templateName = config.potdPrefix + dateInput.value;
					new mw.Api().get(
						Object.assign( {titles: templateName}, config.query )
					).fail(function(code, error) {
						console.warn("API error checking if POTD template exists:");
						console.warn(error);
						showDateError("got an API error '" + code + "' when checking if [[" + templateName + "]] exists: " + error.error.info);
						finishSubmit();
					}).done( function(data) {
						if (data && data.query && data.query.pages && data.query.pages[0]) {
							if (data.query.pages[0].missing) {
								console.log(templateName + " does not yet exist.");
								if (config.titleData) {
									if (config.titleData.missing) {
										showTitleError("was unable to find that article.");
									} else {
										writeLocalDesc();
									}
								} else {
									new mw.Api().get(
										Object.assign( {titles: titleInput.value}, config.query )
									).fail(function(code, error) {
										console.warn("API error checking if article exists:");
										console.warn(error);
										showDateError("got an API error '" + code + "' when checking if [[" + titleInput.value + "]] exists: " + error.error.info);
										finishSubmit();
									}).done( function(data) {
										if (data && data.query && data.query.pages && data.query.pages[0]) {
											if (data.query.pages[0].missing) {
												showTitleError("was unable to find that article.");
											} else {
												writeLocalDesc();
											}
										} else {
											console.warn("Error parsing API respose for article:");
											console.log(data);
											showTitleError("was unable to parse the API response when trying get info on [[" + titleInput.value + "]].");
											finishSubmit();
										}
									});
								}
							} else {
								showDateError("A Picture of the Day template already exists at [[" + templateName + "]].");
								finishSubmit();
							}
						} else {
							console.warn("Error parsing API respose for template:");
							console.log(data);
							showDateError("The script was unable to parse the API response when trying get info on the [[" + templateName + "]] template.");
							finishSubmit();
						}
					} );
				} else {
					showImageError("was unable to find [[Category:" + config.fpCategory + "]] on that image.");
					finishSubmit();
				}
			} else {
				showImageError("was unable to find any categories on that image.");
				finishSubmit();
			}
		}
		
		function submitClick() {
			titleMessage.toggle(false);
			imageMessage.toggle(false);
			dateMessage.toggle(false);
			submitMessage.toggle(false);
			if (uploaderInput.value != "" && uploaderInput.value.search(/^User:/i) == -1) {
				imageMessage.setLabel("Uploader name must begin with \"User:\".");
				imageMessage.toggle(true);
				imageMessage.scrollElementIntoView();
				uploaderInput.select();
			} else if (nominatorInput.value != "" && nominatorInput.value.search(/^User:/i) == -1) {
				imageMessage.setLabel("Nominator name must begin with \"User:\".");
				imageMessage.toggle(true);
				imageMessage.scrollElementIntoView();
				nominatorInput.select();
			} else if (creditInput.value == creditDefault) {
				imageMessage.setLabel("Please enter a real image credit.");
				imageMessage.toggle(true);
				imageMessage.scrollElementIntoView();
				creditInput.select();
			} else if (secondaryCreditInput.value == secondaryCreditDefault) {
				imageMessage.setLabel("Please enter a real secondary credit or leave it blank.");
				imageMessage.toggle(true);
				imageMessage.scrollElementIntoView();
				secondaryCreditInput.select();
			} else if (isNaN(Date.parse(dateInput.value))) {
				showDateError("Invalid date.");
				dateInput.select();
			} else {
				submitButton.setDisabled(true).pushPending().toggleFramed(false);
				closeButton.setDisabled(true).pushPending().toggleFramed(false);
				
				dateInput.setValue(new Date(dateInput.value).toISOString().split('T')[0]);
				config.editSummary = config.editSummaryPattern.replace(/%(\d+)/g, function(_, n) {return [imageInput.value, dateInput.value][n]}) + config.editSummarySuffix;
				
				if (typeof config.imageData === 'undefined') {
					var imageName = 'File:' + imageInput.value;
					new mw.Api().get(
						Object.assign( {titles: imageName}, config.query, config.imageQuery )
					).fail(function(code, error) {
						console.warn("API error retrieving image info:");
						console.warn(error);
						showImageError("got an API error '" + code + "' when querying image: " + error.error.info);
						finishSubmit();
					}).done( function(data) {
						if (data && data.query && data.query.pages && data.query.pages[0]) {
							if (data.query.pages[0].missing) {
								showImageError("was unable to find the image.");
								finishSubmit();
							} else {
								config.imageData = data.query.pages[0];
								preCheck();
							}
						} else {
							console.warn("Error parsing API respose for image:");
							console.log(data);
							showImageError("was unable to parse the API response when trying get info on the image.");
							finishSubmit();
						}
					} );
				} else {
					console.log("Using cached API response.");
					preCheck();
				}
			}
		}
				
		if (typeof POTDFieldset === 'undefined') {
			var creditDefault = 'Photograph/Painting/etc. credit: [[<!--name-->]]',
				secondaryCreditDefault = 'restored/photographed/etc. by [[<!--name-->]]';
			
			var titleMessage = new OO.ui.MessageWidget( {type: 'error', showClose: true} ),
				titleInput = new OO.ui.TextInputWidget( { placeholder: 'Article the image represents', indicator: 'required', validate: 'non-empty'} ),
				autofillTitleButton = new OO.ui.ButtonWidget( { label: 'Autofill caption', icon: 'search', flags: ['progressive'] } ),
				captionInput = new OO.ui.MultilineTextInputWidget({placeholder: '\'\'\'[[Article title]]\'\'\' is...', autosize: true, }),
				texttitleInput = new OO.ui.TextInputWidget( { placeholder: 'Short caption. Leave blank to use Title' } ),
				alttextInput = new OO.ui.TextInputWidget( { placeholder: 'Leave blank to use Text Title' } ),
				creditInput = new OO.ui.TextInputWidget( { value: creditDefault, indicator: 'required', validate: function(v){return (v != "" && v != creditDefault);} } ),
				secondaryCreditInput = new OO.ui.TextInputWidget( { value: secondaryCreditDefault, validate: function(v){return (v != secondaryCreditDefault);} } ),
				sizeInput = new OO.ui.TextInputWidget( { placeholder: 'Size in pixels (defaults to 350)', validate: 'integer' } ),
				imageMessage = new OO.ui.MessageWidget( {type: 'error', showClose: true} ),
				imageInput = new OO.ui.TextInputWidget( { placeholder: 'File name without "File:"', indicator: 'required', validate: 'non-empty' } ),
				autofillImageButton = new OO.ui.ButtonWidget( { label: 'Autofill uploader/nominator', icon: 'search', flags: ['progressive'] } ),
				uploaderInput = new OO.ui.TextInputWidget( { placeholder: 'User:', validate: function(v){return (v == "" || v.search(/^User:/i) != -1) } } ),
				nominatorInput = new OO.ui.TextInputWidget( { placeholder: 'User:', validate: function(v){return (v == "" || v.search(/^User:/i) != -1) } } ),
				dateMessage = new OO.ui.MessageWidget( {type: 'error', showClose: true} ),
				dateInput = new OO.ui.TextInputWidget( { placeholder: 'YYYY-MM-DD', indicator: 'required', validate: function(v) {return !isNaN(Date.parse(v));} } ),
				commentsInput = new OO.ui.TextInputWidget( { placeholder: '[optional]' } ),
				submitMessage = new OO.ui.MessageWidget( {type: 'notice', showClose: true} ),
				submitButton = new OO.ui.ActionWidget( { label: 'Submit', disabled: true, framed: true, flags: ['primary','progressive']} ),
				closeButton = new OO.ui.ActionWidget( { label: 'Close', framed: true, flags: ['primary','destructive']} );
				
			var POTDFieldset = new OO.ui.FieldsetLayout( { label: potdScriptLongTitle, classes: [ 'container' ] } ),
				titleFieldset = new OO.ui.FieldsetLayout( { label: 'Linked article', classes: [ 'container' ] } ),
				imageFieldset = new OO.ui.FieldsetLayout( { label: 'Image information', classes: [ 'container' ] } ),
				templateFieldset = new OO.ui.FieldsetLayout( { label: 'Template information', classes: [ 'container' ] } ),
				submitFieldset = new OO.ui.FieldsetLayout( { classes: [ 'container' ] } );
			
			titleFieldset.addItems( [
				titleMessage,
				new OO.ui.ActionFieldLayout(titleInput, autofillTitleButton, {align: 'top', label: 'Title'}),
				new OO.ui.FieldLayout(captionInput, {align: 'top', label: 'Caption'}),
				new OO.ui.FieldLayout(texttitleInput, {align: 'top', label: 'Text title'})
			] );
			
			imageFieldset.addItems( [
				imageMessage,
				new OO.ui.ActionFieldLayout(imageInput, autofillImageButton, {align: 'top', label: 'Image'}),
				new OO.ui.FieldLayout(uploaderInput, {align: 'top', label: 'Original uploader'}),
				new OO.ui.FieldLayout(nominatorInput, {align: 'top', label: 'Featured Picture nominator'}),
				new OO.ui.FieldLayout(creditInput, {align: 'top', label: 'Credit (use full name, not user name, if known)'}),
				new OO.ui.FieldLayout(secondaryCreditInput, {align: 'top', label: 'Secondary credit (may be blank)'}),
				new OO.ui.FieldLayout(alttextInput, {align: 'top', label: 'Alt text'}),
				new OO.ui.FieldLayout(sizeInput, {align: 'top', label: 'Size'}),
			] );
				
			templateFieldset.addItems( [
				dateMessage,
				new OO.ui.FieldLayout(dateInput, {align: 'top', label: 'Date'}),
				new OO.ui.FieldLayout(commentsInput, {align: 'top', label: 'Additional comments for talk page messages'}),
			] );
			
			submitFieldset.addItems( [
				new OO.ui.FieldLayout(submitMessage, {}),
				new OO.ui.FieldLayout(new OO.ui.ButtonGroupWidget( { items: [ submitButton, closeButton] } ))
			] );
			
			POTDFieldset.addItems( [ 
				titleFieldset,
				imageFieldset,
				templateFieldset,
				submitFieldset
			] );
			
			if (mw.config.get('wgNamespaceNumber') == 6) {
				imageInput.setValue(mw.config.get('wgTitle'));
			} else if (mw.config.get('wgNamespaceNumber') == 0) {
				titleInput.setValue(mw.config.get('wgTitle'));
			}
			checkButtons();

			titleInput.inputFilter = function(value){return value.replace(/^\[\[/, '').replace(/\]\]$/, '').replace('_', ' ');};
			sizeInput.inputFilter = function(value){return value.replace(/[^0-9]/, '');};
			imageInput.inputFilter = function(value){return value.replace(/^File:/, '').replace('_', ' ');};
			creditInput.on( 'change', checkButtons );
			titleInput.on( 'change', function() {checkButtons();delete config.titleData;});
			dateInput.on( 'change', checkButtons );
			imageInput.on( 'change', function() {checkButtons();delete config.imageData;});
			autofillTitleButton.on( 'click', getCaption);
			autofillImageButton.on( 'click', getImageInfo);
			submitButton.on( 'click', submitClick);
			closeButton.on( 'click', function() {POTDFieldset.toggle(false)} );
			submitMessage.on( 'close', function() {
					config.submitMessages = [];
					submitMessage.setType('notice');
				} ).on( 'toggle', function() {
					if (!submitMessage.isVisible()) {
						config.submitMessages = [];
						submitMessage.setType('notice');
					}
				} );
			titleMessage.toggle(false);
			imageMessage.toggle(false);
			dateMessage.toggle(false);
			submitMessage.toggle(false);
			
			$( POTDFieldset.$element ).insertAfter( "#jump-to-nav" );
		} else {
			POTDFieldset.toggle(true);
		}
	}
	
	if ((mw.config.get('wgNamespaceNumber') == 6 && mw.config.get('wgCategories').find(cat => cat == potdFPCategory)) || mw.config.get('wgNamespaceNumber') == 0) {
		var portletLink = mw.util.addPortletLink("p-cactions", "#", potdScriptShortTitle,
		"ca-potdhelper", "Make image a Picture of the Day");
		$( portletLink ).click(function(e) {
			e.preventDefault();
			return POTDHelper();
		} );
	} else if (mw.config.get('wgNamespaceNumber') == -1 && mw.config.get('wgTitle').toLowerCase() === "potdhelper") {
		document.title = "Special:" + potdScriptShortTitle + ' - Wikipedia';
		document.getElementsByTagName("h1")[0].textContent = "Special:" + potdScriptShortTitle;
		document.getElementById("mw-content-text").innerHTML="";
		POTDHelper();
	}
} );