User:BMacZero/shipcat.js

From Wikimedia Commons, the free media repository
Jump to navigation Jump to search
Note: After saving, you have to bypass your browser's cache to see the changes. Internet Explorer: press Ctrl-F5, Mozilla: hold down Shift while clicking Reload (or press Ctrl-Shift-R), Opera/Konqueror: press F5, Safari: hold down Shift + Alt while clicking Reload, Chrome: hold down Shift while clicking Reload.
// wizard for creating categories for ships

//<nowiki>

var showWizard = function($, mw)
{
	if (window.shipWizard)
	{
		window.shipWizard.show();
		return;
	}
	
	var shipWizard = window.shipWizard =
	{
		apiUrl: mw.util.wikiScript('api'),
		
		init: function()
		{
			importStylesheet('User:BMacZero/shipcat.css');
			
			$body = $(document.body);
			$container = shipWizard.$container = $('<div id="scat_container"></div>')
				.appendTo($body);
				
			$fader = shipWizard.$fader = $('<div id="scat_fade"></div>')
				.appendTo($body);
			
			$('<h2>Ship Category Wizard</h2>')
				.appendTo($container);
				
			$('<p>(<span style="color:red">*</span>) denotes a required field</p>')
				.appendTo($container);
				
			$('<br/>').appendTo($container);
				
			$inputTable = $('<table></table>')
				.appendTo($container);
			//TODO: fishing license # as prefix
			$prefixInput = shipWizard.$prefixInput = this.createInputElement($inputTable, 'Prefix (only if painted on ship)');
			$nameInput = shipWizard.$nameInput = this.createInputElement($inputTable, 'Name', "text", true);
			$typeInput = shipWizard.$typeInput = this.createSpecialInputElement($inputTable, "Type",
				$('<select><option>ship</option><option>tugboat</option><option>submarine</option></select>'));
			$yearCompleted = shipWizard.$yearCompleted = this.createInputElement($inputTable, 'Year Completed');
			$yearLaunched = shipWizard.$yearLaunched = this.createInputElement($inputTable, 'Year Launched');
			$locationBuilt = shipWizard.$locationBuilt = this.createInputElement($inputTable, 'Location Built');
			$yardNumber = shipWizard.$yardNumber = this.createInputElement($inputTable, 'Yard Number');
			
			$('<tr><td><br/></td></tr>').appendTo($inputTable);
			
			$imo = shipWizard.$imo = this.createInputElement($inputTable, 'IMO');
			$eni = shipWizard.$eni = this.createInputElement($inputTable, 'ENI');
			
			$('<tr><td><br/></td></tr>').appendTo($inputTable);
			
			$addThisPage = shipWizard.$addThisPage = this.createInputElement($inputTable, "Add this page to created category", "checkbox");
			
			// this is for showing output to the user
			$outputElement = shipWizard.$outputElement = $('<p></p>').appendTo($container);
			
			$optionsP = $('<p></p>').appendTo($container);
			$('<button>Create Category</button>')
				.appendTo($optionsP)
				.click(function(){ shipWizard.createCategory(); });
			$('<span style="display:inline-block;width:20px"></span>').appendTo($optionsP);
			//TODO: escape closes
			$('<a href="javaScript:void(0);">close window</a>')
				.appendTo($optionsP)
				.click(function(){ shipWizard.hide(); });
		},
		
		createInputElement: function($tableParent, labelText, type, required)
		{
			if (!type) type = "text";
			return this.createSpecialInputElement($tableParent, labelText, $('<input type="' + type + '">'), required);
		},
		
		createSpecialInputElement: function($tableParent, labelText, $inputElem, required)
		{
			if (required) labelText += '<span style="color:red">*</span>';
			
			$tr = $('<tr></tr>')
				.appendTo($tableParent);
			$('<td>' + labelText + '</td>')
				.appendTo($tr);
			$inputCell = $('<td></td>')
				.appendTo($tr);
			return $($inputElem).appendTo($inputCell);
		},
		
		createCategory: function()
		{
			shipWizard.$outputElement.html('<span><b>Working...</b></span>');
			
			// check that required fields are set
			if (!this.$nameInput.val())
			{
				shipWizard.$outputElement.html('<span style="color:red"><b>Missing required field "Name".</b></span>');
				return;
			}
			
			// figure displayed year
			//TODO: validate data
			var year = "";
			if (this.$yearCompleted.val()) year = this.$yearCompleted.val();
			else if (this.$yearLaunched.val()) year = this.$yearLaunched.val();
			
			var typeText = this.$typeInput.children("option").filter(":selected").text();
			var titleSuffix = " (" + typeText + ")";
			if (year) titleSuffix = " (" + typeText + ", " + year + ")";
			
			// figure title of page
			var pageTitle = "Category:";
			if (this.$prefixInput.val()) pageTitle += this.$prefixInput.val() + " ";
			pageTitle += this.$nameInput.val() + titleSuffix;
			
			//TODO: if category already exists, disambiguate with $locationBuilt then $yardNumber
			
			// check that category doesn't exist
			var params = this.getQueryParams(pageTitle);
			this.doAPICall(params, function(result)
			{
				var allMissing = true;
				// there should be only one, but we don't know its ID
				console.log(result);
				for (var id in result.query.pages)
				{
					allMissing = allMissing && result.query.pages[id].missing !== undefined;
					
					//TODO: this doesn't work
					shipWizard.queryTimestamp = result.query.pages[id].starttimestamp;
				}
				
				if (!allMissing)
				{
					shipWizard.$outputElement.html('<span style="color:red"><b>Category "' + pageTitle + '" already exists. Add more information or use that category.</b></span>');
				}
				else
				{
					shipWizard.createCategoryHelper(pageTitle, titleSuffix, year);
				}
			});
		},
		
		createCategoryHelper: function(pageTitle, titleSuffix, year)
		{
			// produce page contents
			var categoryText = "";
			
			// displaytitle
			categoryText += "{{DISPLAYTITLE:Category:";
			if (this.$prefixInput.val()) categoryText += this.$prefixInput.val() + " ";
			categoryText += "''" + this.$nameInput.val() + "''" + titleSuffix;
			categoryText += "}}\n";
			
			// defaultsort
			var normalizedName = this.$nameInput.val();
			if (normalizedName.normalize) normalizedName = normalizedName.normalize('NFKD').replace(/[\u0300-\u036F]/g, '');
			if (this.$prefixInput.val() || normalizedName !== this.$nameInput.val())
			{
				categoryText += "{{DEFAULTSORT:";
				categoryText += normalizedName + titleSuffix;
				categoryText += "}}\n";
			}
			
			// templates
			if (this.$imo.val()) categoryText += "{{IMOcat|" + this.$imo.val() + "}}\n";
			
			// categories
			categoryText += "[[Category:Ships by name (flat list)]]\n";
			if (this.$yearCompleted.val()) categoryText += "[[Category:Ships built in " + this.$yearCompleted.val() + "]]\n";
			if (!year) categoryText += "[[Category:Ship categories with missing year]]\n";
			//TODO: create if non-existant
			if (this.$imo.val()) categoryText += "[[Category:IMO " + this.$imo.val() + "]]\n";
			//TODO: create if non-existant
			if (this.$eni.val()) categoryText += "[[Category:ENI " + this.$eni.val() + "]]\n";
			
			// get an edit token if necessary
			if (!this.editToken)
			{
				var params = {
					action: 'query',
					meta: 'tokens',
					type: 'csrf'
				};
				this.doAPICall(params, function(result)
				{
					shipWizard.edittoken = result.query.tokens.csrftoken;
					shipWizard.createCategoryFinally(pageTitle, categoryText);
				});
			}
			else
			{
				this.createCategoryFinally(pageTitle, categoryText);
			}
		},
		
		createCategoryFinally: function(pageTitle, pageText)
		{
			var params = {
				action: 'edit',
				title: pageTitle,
				text: pageText,
				summary: "Creating new ship category with the [[User:BMacZero/Ship Category Wizard|Ship Category Wizard]].",
				token: this.edittoken,
				createonly: true,
				starttimestamp: this.queryTimestamp
			};
			this.doAPICall(params, function(result)
			{
				if (result.error)
				{
					shipWizard.$outputElement.html('<span style="color:red"><b>Error: ' + result.error.info + '</b></span>');
				}
				else
				{
					// add the category to this page
					if (shipWizard.$addThisPage.prop('checked'))
					{
						shipWizard.addCategoryToCurrentPage(pageTitle);
					}
					else
					{
						shipWizard.postAllDone();
					}
				}
			});
		},
		
		postAllDone: function()
		{
			shipWizard.$outputElement.html('<span style="color:green"><b>All done, refresh this page.</b></span>');
		},
		
		getQueryParams: function(pageTitle)
		{
			return {
				action: 'query',
				prop: 'info|revisions',
				rvprop: 'content|timestamp',
				titles: pageTitle
			};	
		},
		
		addCategoryToCurrentPage: function(categoryName)
		{
			var params = this.getQueryParams(mw.config.get('wgPageName'));
			this.doAPICall(params, function(result)
			{
				// stolen from MediaWiki:Gadget-Cat-a-lot.js
				var otext, starttimestamp, timestamp;
				if (!result)
				{
					//Happens on unstable wifi connections..
					//TODO: display error
					return;
				}
				var pages = result.query.pages;
	
				// there should be only one, but we don't know its ID
				for (var id in pages)
				{
					otext = pages[id].revisions[0]['*'];
					starttimestamp = pages[id].starttimestamp;
					timestamp = pages[id].revisions[0].timestamp;
				}
				
				var text = otext;
				text += "\n[[" + categoryName + "]]\n";
				
				var data = {
					action: 'edit',
					summary: "Creating new ship category with the [[User:BMacZero/Ship Category Wizard|Ship Category Wizard]].",
					title: pages[id].title,
					text: text,
					starttimestamp: starttimestamp,
					basetimestamp: timestamp,
					token: shipWizard.edittoken,
					nocreate: true,
				};
				
				shipWizard.doAPICall(data, function(result)
				{
					if (result.error)
					{
						shipWizard.$outputElement.html('<span style="color:red"><b>Error: ' + result.error.info + '</b></span>');
					}
					else
					{
						shipWizard.postAllDone();
					}
				});
			});
		},
		
		show: function()
		{
			shipWizard.$container.show();
			shipWizard.$fader.show();
		},
		hide: function()
		{
			shipWizard.$container.hide();
			shipWizard.$fader.hide();
		},
		
		// stolen from MediaWiki:Gadget-Cat-a-lot.js
		doAPICall: function(params, callback)
		{
			params.format = 'json';
			var i = 0;
			var apiUrl = this.apiUrl;
			var handleError = function(jqXHR, textStatus, errorThrown)
			{
				if (window.console && $.isFunction(window.console.error))
				{
					window.console.error('Error: ', jqXHR, textStatus, errorThrown);
				}
				if (i < 4)
				{
					window.setTimeout(doCall, 300);
					i++;
				}
				else if (params.title)
				{
					//TODO: display error
					return;
				}
			};
			var doCall = function()
			{
				$.ajax({
					url: apiUrl,
					cache: false,
					dataType: 'json',
					data: params,
					type: 'POST',
					success: callback,
					error: handleError
				});
			};
			doCall();
		},
	};
	
	// initialize when document is ready
	$(function()
	{
		shipWizard.init();
	});
};

 /*jshint scripturl:true*/
 $.when(mw.loader.using('mediawiki.util'), $.ready).then(function() { 
	var shipcatNode = mw.util.addPortletLink('p-tb', '', 'Create ship category', 't-shipcatwizard');
	$(shipcatNode).on('click', function(e) {showWizard(jQuery, mediaWiki); e.preventDefault();});
 });
/*jshint scripturl:false*/

//</nowiki>