User:RossPatterson/Reorganize References.js

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> */

/* Add an editting tab called "ReorgRef" to convert reorganize references */

/*
Simply add ''importScript("User:RossPatterson/Reorganize References.js");'' to your own monobook.js and clear the cache before it will work.
*/

/* Version 1.0 */
var RossPatterson_Reorganize_References = function () {
	var _private = {
		generatedNameIndex: 0
		,
		debugLevel: 0
		,

		debug: function(text) {
			if (_private.debugLevel > 0) {
				alert(text);
			}
		}
		,
		reorgRefs: function (articleText, refs) {
			_private.debug("reorgRefs: start");
			// Match "<ref>...</ref>", "<ref name=x>...</ref>", etc., but not "<ref name=x/>"
			var refPat = new RegExp("(<ref[^/>]*>[^<]*</ref\\s*>)", "gi");
			var refElements = (articleText.match(refPat));
			_private.debug("reorgRefs: Found " + refElements.length + " references");
			for (var i=0; i < refElements.length; i++) {
				_private.debug("reorgRefs: i=" + i);
				_private.debug("reorgRefs: refElements[" + i + "]=" + refElements[i]);
				var name = '';
				var originalRef=refElements[i];
				var refParms=refElements[i].substr(4, refElements[i].indexOf('>') - 4);	// "<ref xxxx>yyy" -> " xxxx"
				if (refParms != "" && refParms.search(new RegExp("\\s+name\\s*=", "i")) != -1) {
					// Extract the existing "name=x"
					name = refParms.replace(new RegExp("\\s+name\\s*=\\s*([^\\s]*)", "i"), '$1');
					_private.debug("reorgRefs: found name=" + name);
				} else {
					_private.debug("reorgRefs: no name=");
					// No "name=x", add one
					name = _private.chooseUniqueName(refElements[i], articleText);
					refElements[i] = "<ref name=" + name + refElements[i].substr(4);  // "<ref xxxx>yyy" -> " <ref name=zzz xxxx>yyy"
					_private.debug("reorgRefs: modified refElements[" + i + "]=" + refElements[i]);
				}
				refs.push(refElements[i]);		
				articleText = articleText.replace(originalRef, "<ref name=" + name + "/>");
			}
			_private.debug("reorgRefs: end");
			return articleText;
		}
		,

		chooseUniqueName: function (refText, articleText) {
			_private.debug("chooseUniqueName: start");
			var name='';
			// Try to use the parameters of {{cite whatever}} to set the reference name
			if (refText.search(new RegExp("\\{\\{[Cc]ite")) != -1) {
				_private.debug("chooseUniqueName: found {{cite");
				// Build an array of parameters by name
				var temp = refText.substr(refText.indexOf("|"));	// "{{cite whatever |aa=bb |cc=dd}}eee" -> "|aa=bb |cc=dd}}eee"
				temp = temp.substr(0, temp.indexOf("}}"));		// "|aa=bb |cc=dd}}eee" -> "|aa=bb |cc=dd"
				var temp2 = temp.split("|");				// "|aa=bb |cc=dd" -> ["aa=bb", "cc=dd"]
				var citeParms = new Array();
				for (var i=0; i < temp2.length; i++) {
					var temp3 = temp2[i].split("=");		// "aa=bb" -> ["aa",bb"]
					if ((temp2[i] == "") || (temp3[0] == "")) {
						continue;
					}
					citeParms[_private.trim(temp3[0])] = _private.trim(temp3[1]);	// citeParams["aa"] = "bb"
				}
				// Build the reference name from some of the parameters
				if ((citeParms["last1"] != null) && (citeParms["last1"] !=  "")) {
					name = citeParms["last1"];	// Add the last1= value
				} else if ((citeParms["last"] != null) && (citeParms["last"] !=  "")) {
					name = citeParms["last"];	// Add the last= value
				} else if ((citeParms["author1"] != null) && (citeParms["author1"] !=  "")) {
					name = citeParms["author1"];	// Add the author1= value
				} else if ((citeParms["author"] != null) && (citeParms["author"] !=  "")) {
					name = citeParms["author"];	// Add the author= value
				} else if ((citeParms["editor1"] != null) && (citeParms["editor1"] !=  "")) {
					name = citeParms["editor1"];	// Add the editor1= value
				} else if ((citeParms["editor"] != null) && (citeParms["editor"] !=  "")) {
					name = citeParms["editor"];	// Add the editor= value
				} else if ((citeParms["publisher"] != null) && (citeParms["publisher"] !=  "")) {
					name = citeParms["publisher"];	// Add the publisher= value
				} else if ((citeParms["title"] != null) && (citeParms["title"] !=  "")) {
					name = citeParms["title"];	// Add the title= value
				}
				name = name + " ";
				if ((citeParms["date"] != null) && (citeParms["date"] !=  "")) {
					name = name + citeParms["date"];	// Add the date= value
				} else if ((citeParms["year"] != null) && (citeParms["year"] !=  "")) {
					name = name + citeParms["year"];	// Add the year= value
				}
				name = name.replace(new RegExp("[\\W]+", "g"), " ");	// Replace whitespace, specials, ...
				name = (_private.trim(name)).replace(new RegExp("[\\s]+", "g"), "_");	// ... with "_"
				_private.debug("chooseUniqueName: name=" + name);
				if (articleText.indexOf(name) == -1) {
					return '"' + name + '"';
				}
				_private.debug("chooseUniqueName: name already in use");
			}
			// Try to use the URL components to set the reference name
			if (refText.search(new RegExp("^<ref[^/>]*>\\s*\\[\\s*https?:")) != -1) {
				_private.debug("chooseUniqueName: found http:");
				var URL = (refText.match(new RegExp("https?:[^\\s]*[^?;<\\]]*")))[0];	// "<ref xx>[http://aaa/bbb ccc]</ref>" -> "http://aaa/bbb ccc"
				_private.debug("chooseUniqueName: URL=" + URL);
				var host = URL.replace(new RegExp("^https?:\\/\\/([^\\/]*)\\/.*$"), '$1');	// Isolate the hostname/IP addr
				_private.debug("chooseUniqueName: host=" + host);
				var path = URL.replace(new RegExp("^https?:\\/\\/[^\\/]*\\/([^\\s]*).*$"), '$1');	// Isolate the pathname
				_private.debug("chooseUniqueName: path=" + path);
				var title = URL.replace(new RegExp("^https?:\\/\\/[^\\/]*\\/[^\\s]*\\s+(.*)$"), '$1');	// Isolate the title
				_private.debug("chooseUniqueName: title=" + title);
				var file= path.replace(new RegExp("^.*([^\\/]*)$"), '$1');		// Isolate the file name from the pathname
				_private.debug("chooseUniqueName: file=" + file);
				if (host != "") {
					name = host;
				}
				name = name + " ";
				if (title != "") {
					name = name + title;
				} else if (file != "") {
					name = name + file;
				} else if (path != "") {
					name = name + path;
				}
				name = name.replace(new RegExp("[\\W]+", "g"), " ");	// Replace whitespace, specials, ...
				name = (_private.trim(name)).replace(new RegExp("[\\s]+", "g"), "_");	// ... with "_"
				_private.debug("chooseUniqueName: name=" + name);
				if (articleText.indexOf(name) == -1) {
					return '"' + name + '"';
				}
				_private.debug("chooseUniqueName: name already in use");
			}
			// Make up a name of our own when all else fails
			for (var i=0; i < 20; i++) {
				name = '"RRGEN_' + _private.generatedNameIndex++ + '_"';
				_private.debug("chooseUniqueName: name=" + name);
				if (articleText.indexOf(name) == -1) {
					return name;
				}
				_private.debug("chooseUniqueName: name already in use");
			}
			alert("chooseUniqueName: Unable to generate a unique name for reference: " + refText);
			exit(1);
		}
		,

		addRefs: function (articleText, refs) {
			_private.debug("addRefs: start");
			var referencesEndTag = new RegExp("(</references[^>]*>)", "i");
			var referencesMinTag = new RegExp("<(references)([^\\/>]*)\\/>", "i");
			var reflistWithRefs  = new RegExp("(\\{\\{[Rr]eflist[^\\}]*\\s*\\|\\s*refs=)");
			var reflistNoRefs    = new RegExp("(\\{\\{[Rr]eflist[^}]*)\\}\\}");
			if (articleText.search(referencesEndTag) != -1) {
				// Add our collected refs to the existing <references>...</references>
				articleText = articleText.replace(referencesEndTag, refs.join("\n") + "\n$1");
			} else if (articleText.search(reflistWithRefs) != -1) {
				// Add our collected refs to the existing {{reflist refs=...}}
				articleText = articleText.replace(reflistWithRefs, "$1\n" + refs.join("\n") + "\n");
			} else 	if (articleText.search(referencesMinTag) != -1) {
				// Expand the references tag and insert our collected refs
				articleText = articleText.replace(referencesMinTag, "<$1$2>\n" + refs.join("\n") + "\n</$1>");
			} else if (articleText.search(reflistNoRefs) != -1) {
				// Expand the {{reflist}} and include our collected refs
				articleText = articleText.replace(reflistNoRefs, "$1 |refs=\n" + refs.join("\n") + "\n}}");
			} else {
				alert("addRefs: Can't find reference list, adding my own!!!!");
				articleText += "<references>\n" + refs.join("\n") + "\n</references>";
			}
			_private.debug("addRefs: end");
			return articleText;
		}
		,
		trim: function (input) {
			if (input == null) {
				return "";
			}
			var start;
			var end;
			for (start = 0; start < input.length; start++) {
				if (input[start] != " ") {
					break;
				}
			}
			for (end = input.length; end >= 0; end--) {
				if (input[end] != " ") {
					break;
				}
			}
			return input.substr(start, end);
		}
	}

	var _public = {
		run: function () {
			_private.debug("run: start");
			var articleTextField = document.editform.wpTextbox1;
			var articleText = articleTextField.value;
			var refs = new Array();
			articleText = _private.reorgRefs(articleText, refs);
			articleTextField.value = _private.addRefs(articleText, refs);
			// Add a tag to the summary box
			var summaryField = document.editform.wpSummary;
			var summary = "Reorganize references";
			if (summaryField.value.indexOf(summary) == -1) {
				// If the summary contains anything other than a section comment, add a separator
				if (summaryField.value.match(/[^\*\/\s][^\/\s]?\s*$/)) {
					summaryField.value += "; ";
				}
				summaryField.value += summary;
			} 
			// Press the "Show changes" button to let the user see the diffs.
			document.editform.wpDiff.click()
				_private.debug("run: end");
		}
		,

		initialize: function () {
			if (document.forms.editform) {
				mw.util.addPortletLink('p-cactions', 'javascript:RossPatterson_Reorganize_References.run()',
						'RefReorg', 'ca-ref-reorg', 'Reorganize references', '', '');
			}
		}

	}

	return _public;
}();
addOnloadHook(RossPatterson_Reorganize_References.initialize);

/* </nowiki> */