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.
/* OLUtils.js: "Outline Utilities", with features optimized for outlines.
The initial function of this script is to strip redlinks

    Fork of December 26, 2016 15:05 version of User:AlexTheWhovian/script-redlinks.js
        It worked when the lastest version did not, but it has worked intermittently since.
        That script already does the last 2 steps needed for outlines: 
        	remove redlink categories,
        	and delink all remaining unprocessed redlinks.

For more detailed comments than those included below, see the Explanatory notes section on the talk page.
*/

// /////////////////////////// PROCESS READ PAGE ////////////////////////////////////
// Start off with a bodyguard function (see Explanatory notes on talk page), also call mw library
( function ( mw, $) {
	// we can now rely on $ within the safety of our “bodyguard” function

	// below is jQuery short-hand for $(document).ready(function() { ... });
	$(function() {

		// Create linked menu item
		var portletlink = mw.util.addPortletLink('p-tb', '#', 'Remove red links');
		// Bind click handler
		$(portletlink).click( function(e) {
			e.preventDefault();

			// Do some stuff when clicked...
			// Default parameters, and begin script on regular view of article
			var loc = window.location.href;
			var redlinks; var i;
		
			// Gather all redlinks with class "new"
			redlinks = [];
			var a = document.getElementsByTagName('a');
			for (i = 0; i < a.length; i++) {
				if (a[i].getAttribute('class') == "new") {
					redlinks[redlinks.length] = a[i].href.replace('https://en.wikipedia.org/w/index.php?title=','').replace('&action=edit&redlink=1','');
					redlinks[redlinks.length-1] = redlinks[redlinks.length-1].replace(/_/g,' ');
					redlinks[redlinks.length-1] = decodeURIComponent(redlinks[redlinks.length-1]);
				}
			}

			// Save all redlinks
			if (redlinks.length > 0) {
				var jsonString = JSON.stringify(redlinks);
				localStorage.OLUtils_redlinks = jsonString;

				// If we are in the edit page, then remove redlinks automatically; if we are on the reading page, then go to the edit page
				if (window.location.href.indexOf('action') >= 0) {
					// (do nothing - it already does it above)
				} else {
					window.location = window.location.href.substr(0, window.location.href.indexOf('#'))+"?action=edit";
				}	
			} else {
				alert('No redlinks!');
			}
		});     // end of function(e) (click handler)
	});

// //////////////////////////// PROCESS EDIT PAGE ////////////////////////////////

	// The ready() event listener/handler, to "defer" a functon while the page loads (the function is the handler), 
	// ensures that the function is called only after all the DOM elements of the page are ready to be used:
	$(document).ready( function () {

	    // Invoke a function by its name; this one checks the script's localStorage slot
	    // (The function itself is defined down the page a little, using the word "function"). 
	    check_storage();
	});

	function check_storage() {
		// Check to see if anything is in storage, and if there is, invoke redlinks removal 
    	if (localStorage.OLUtils_redlinks !== "") {

		    // Invoke a function by its name (it is defined further down the page). 
		    // This one removes redlinks, if they exist:
		    redlinks_removal();
    	}
	}
	
	// Automatic removal of redlinks when stored.
	function redlinks_removal() {
		// Gather saved redlinks
		var redlinks = JSON.parse(localStorage.OLUtils_redlinks);
	
		// Regular expression to escape special characters
		var totalredlinks = 0;
		RegExp.quote = function(str) { return str.replace(/[.?*+^$[\]\\(){}|-]/g, "\\$&"); };
		
		var wpTextbox1 = document.getElementById('wpTextbox1');

		// REMOVE REDLINKED END NODES (PROCESS OUTLINE ENTRIES)
		// Development note: Run this section if "Outline of" is in the page title
		// Development note: initialize incrementer
		// Development note: Loop/nested-loop pair
		// Development note: While incrementer > 0, do nested loop

		// Development note: Nested loop is modified version of the for loop from 
		// "remove embedded redlinks" section below, using the same array
		// Development note: Use modified regexes to match whole entry (with array term), sans annotation, plus next line.
		// That is, do not match entries that have annotations.
		// Development note: Save that match
		// Development note: Within the saved match, match parent/child
		// Development note: If parent/child match fails, remove whole entry (with array term)
		// Development note: if match/replace successful, add 1 to incrementer

		for (i = 0; i < redlinks.length; i++) {
			// Regular expression for piped links and direct links
			var reglink1 = new RegExp('\\[\\[\\s*'+RegExp.quote(redlinks[i])+'\\s*\\|\\s*([^\\]]*)\\s*\\]\\]','gi');
			var reglink2 = new RegExp('\\[\\[\\s*'+RegExp.quote(redlinks[i])+'\\s*\\]\\]','gi');
			
			// Add total number of matches for both
			if (wpTextbox1.value.match(reglink1) !== null) totalredlinks += wpTextbox1.value.match(reglink1).length;
			if (wpTextbox1.value.match(reglink2) !== null) totalredlinks += wpTextbox1.value.match(reglink2).length; // Includes categories
			
			// Remove redlinks and convert to unlinked text
			wpTextbox1.value = wpTextbox1.value.replace(reglink1,"$1");
			wpTextbox1.value = wpTextbox1.value.replace(reglink2,redlinks[i]);
		}

		// Development note: after for loop, still within while loop, at end of loop, subtract 1 from incrementer.
		// (If that drops the incrementer down to zero, the while loop should terminate). 
		// (Which means, if the for loop goes through the whole array without any replaces, the while loop terminates).

		// REMOVE EMBEDDED REDLINKS
		for (i = 0; i < redlinks.length; i++) {
			// Regular expression for piped links and direct links
			var reglink3 = new RegExp('\\[\\[\\s*'+RegExp.quote(redlinks[i])+'\\s*\\|\\s*([^\\]]*)\\s*\\]\\]','gi');
			var reglink4 = new RegExp('\\[\\[\\s*'+RegExp.quote(redlinks[i])+'\\s*\\]\\]','gi');
			
			// Add total number of matches for both
			if (wpTextbox1.value.match(reglink3) !== null) totalredlinks += wpTextbox1.value.match(reglink3).length;
			if (wpTextbox1.value.match(reglink4) !== null) totalredlinks += wpTextbox1.value.match(reglink4).length; // Includes categories
			
			// Remove category rather than simply convert it to unlinked text
			if (redlinks[i].substr(0,9) == "Category:") {
				var reglink5 = new RegExp('\\[\\[\\s*('+RegExp.quote(redlinks[i])+')\\s*\\]\\]\\n','gi');
				wpTextbox1.value = wpTextbox1.value.replace(reglink5,"");
			}
			
			// Remove redlinks and convert to unlinked text
			wpTextbox1.value = wpTextbox1.value.replace(reglink3,"$1");
			wpTextbox1.value = wpTextbox1.value.replace(reglink4,redlinks[i]);
		}
		
		// Alert for summary of removed redlinks; total in edit summary
		if (totalredlinks > 0) {
			document.getElementById('wpSummary').value += "Removed "+totalredlinks+" redlink"+(totalredlinks==1?"":"s")+" via [[User talk:The Transhumanist/OLUtils.js|script]].";
			alert("Automatically removed "+totalredlinks+" redlink"+(totalredlinks==1?"":"s")+"!");
		} else {
			// Redlinks were seen in the article but none were found in the wikicode - check the nevigational boxes for these redlinks
			alert('No redlinks in the article! (Check the navigational boxes.)');
		}
		
		// Remove the template(s)
		wpTextbox1.value = wpTextbox1.value.replace(/\{\{[C|c]leanup red links[^\}]*\}\}/g, "");
		wpTextbox1.value = wpTextbox1.value.replace(/\{\{[C|c]leanup Red Link[^\}]*\}\}/g, "");
		wpTextbox1.value = wpTextbox1.value.replace(/\{\{[C|c]leanup redlinks[^\}]*\}\}/g, "");
		wpTextbox1.value = wpTextbox1.value.replace(/\{\{[C|c]leanup-redlinks[^\}]*\}\}/g, "");
		wpTextbox1.value = wpTextbox1.value.replace(/\{\{[T|t]oo many red links[^\}]*\}\}/g, "");
		
		// Clear all saved redlinks
		localStorage.OLUtils_redlinks = '';
	}	
}) ( mediaWiki, jQuery );       //the end of bodyguard function
// END OF PROGRAM