User:Wugapodes/CapricornDev.js

// // This is a modified version of User:Sam Sailor/Scripts/Sagittarius+.js (Special:PermaLink/899463476) // Docs: User:Wugapodes/Capricorn

/*jshint undef:true, latedef:true, shadow:true, loopfunc:true, scripturl:true, undef:true */ /*globals jQuery, mw, importStylesheet */

var templateGroups = { "fromRelatedInfo": "Related information, From", "toRelatedInfo": "Related information, To", "fromPartOfSpeech": "Parts of speech, From", "fromEngVar": "English variant spelling, From", "fromOrthographicModification": "Orthographic difference, From", "toOrthographicModification": "Orthographic difference, To", "fromAlt": "Alternative names, From", "fromDisambiguation": "Ambiguity, From", //"toDisambiguation": "Ambiguity, To", //"fromSpecificity": "Specificity, From", "fromAnthroponym": "Anthroponym, From", "fromFiction": "Fiction, From", "fromWork": "Works of art and works generally, From", "toWork": "Works of art and works generally, To", "fromLocationOrInfrastructure": "Geographic location or infrastructure, From", "fromFormerName": "Former names, From", "toFormerName": "Former names, To", "fromSystematicName": "Systematic name, From", "toSystematicName": "Systematic name, To", "fromPostal": "From postal information", "fromOrganization": "From organization", "fromMath": "From mathematical topic", "fromComic": "Comics, From", "toComic": "Comics, To", "fromMiddleEarth": "Middle-earth topic, From", "toMiddleEarth": "Middle-earth topic, To", "fromMisc": "From miscellaneous information", "fromMeta": "Meta information, From", "toMeta": "Meta information, To", "fromProtected": "Protection level, From", "toNameSpace": "Namespaces, To", "fromPrintworthiness":"Printworthiness" };

//////////////////////////////////////////////////////////////////////////////// // Callback functions

function mainCallback(aliasJSON, templateJSON) { var templateAliases = aliasJSON; var redirectTemplates = templateJSON; //console.log(templateAliases); //console.log(redirectTemplates); // 	'use strict'; importStylesheet('User:Wugapodes/Capricorn.css'); var wgNamespaceIds = mw.config.get('wgNamespaceIds'); var contentText = document.getElementById('mw-content-text'); var firstHeading = document.getElementById('firstHeading'); var redirMsg = contentText.getElementsByClassName('redirectMsg')[0]; var uiWrapper = el('div'); var edittoken = null; function MarkupBlob(markup) { if (!markup) { this.target = ''; this.rcatt = {}; this.tail = ''; } else this.parse(markup); }	MarkupBlob.prototype.parse = function (markup) { var rdrx = /^#REDIRECT:?\s*\[\[\s*([^\|{}[\]]+?)\s*]]\s*/i; var tprx = /^\s*{{([A-Za-z ]+)((?:\|(?:[^|{}]*|{{[^|}]*}})+)*)}}\s*/i; var m;		m = rdrx.exec(markup) markup = markup.substr(m[0].length); this.target = m[1]; this.rcatt = {}; out: while ((m = tprx.exec(markup))) { var alias = normaliseTitle(m[1]); while (templateAliases[alias]) alias = templateAliases[alias]; // hopefully there are no loops. if (alias === "This is a redirect") { var params = m[2].split('|'); for (var j = 0; j < params.length; ++j) { if (!params[j]) continue; if (params[j].indexOf('=') !== -1) break out; alias = normaliseTitle("R " + params[j]); while (templateAliases[alias]) alias = templateAliases[alias]; // hopefully there are still no loops. if (alias in redirectTemplates) this.rcatt[alias] = true; else break out; }			} else if (alias === "Redirect category shell") { var mm, rr = //g; while (mm = rr.exec(m[2])) { alias = normaliseTitle(mm[1]); while (templateAliases[alias]) alias = templateAliases[alias]; if (alias in redirectTemplates) this.rcatt[alias] = true; }			} else if (alias in redirectTemplates) { if (m[2]) // TODO break; this.rcatt[alias] = true; } else { break; }			markup = markup.substr(m[0].length); }		this.tail = markup; };	MarkupBlob.prototype.toString = function { var markup = '#REDIRECT ' + this.target + '\n'; var tail = ''; var wrapped = []; for (var key in this.rcatt) { if (this.rcatt[key]) if ((wrapped.length < 6) && /^R\s+/.test(key)) wrapped.push('\n'); else tail += '\n'; }		if (wrapped.length) markup += "\n\n"; markup += tail + '\n'; markup += this.tail; return markup; };	function buildTagList(rcatt) { function makeCheckBox(key) { return el('label', [				el('input', null, { type: "checkbox", checked: (key in rcatt) ? "checked" : null, }, {					change: function (ev) { rcatt[key] = this.checked; }				}),				' ',				redirectTemplates[key].label			], {				"title": redirectTemplates[key].tooltip			}); }		var list = el('dl', null, { "class": "tag-list" }); var group = {}; for (var key in templateGroups) { list.appendChild(el('dt', templateGroups[key])); list.appendChild(el('dd', group[key] = el('ul'))); }		for (var key in redirectTemplates) { var label = makeCheckBox(key); group[redirectTemplates[key].group].appendChild(el('li', label)); }		var collapsibleContent = el('div', list, { 			"class": "mw-collapsible-content",			"id": "capricorn-toggle-content"		}) return collapsibleContent; }	//	// Interface creation //	function buildEditingUI(mblob, saveCallback) { var statusbar; var needsCheck = true; var doSave; var uiLink, uiTarget; mblob = mblob || new MarkupBlob; // Change text of status bar function setStatus(status) { while (statusbar.firstChild) // Remove previous statuses statusbar.removeChild(statusbar.firstChild); if (status) { // If status is a string, add it				if (typeof status === 'string') statusbar.appendChild(document.createTextNode(status)); else { // Otherwise, loop through list and add statuses for (var j = 0; j < status.length; ++j) { if (typeof status[j] === 'string') statusbar.appendChild(document.createTextNode(status[j])); else statusbar.appendChild(status[j]); }				}			}		}		// Check if the target has changed?? // Not actually sure what this does yet 21 Oct 2019 function inputChanged(ev) { /*jshint validthis:true */ try { mblob.target = this.value; var t = new mw.Title(this.value); var frag = t.getFragment ? '#' + normaliseAnchor(t.getFragment) : ''; if (uiLink) uiLink.href = mw.util.getUrl(t.getPrefixedDb, { redirect: "no" }) + frag; setStatus; } catch (e) { setStatus('Invalid title.'); if (uiLink) uiLink.href = 'javascript:void(0);'; }			needsCheck = true; }		var uiStatusLine; var patrolLine; var origTarget = mblob.target var ui = el('form', [			el('div', [ el('ul', [					el('li', [ uiTarget = el('input', null, {							'type': 'text',							'class': 'redirectText',							'value': mblob.target						}, {							'input': inputChanged,							'change': inputChanged,							'blur': function (ev) { // i would not have to write this, if it were not for jQuery. seriously.								if (mblob.target === this.value)									return;								inputChanged.call(this, ev);							}						}) ])				], { 'class': 'redirectText' }), el('input', null, {					"type": "button",					"class":"capricorn-toggle",					"id": "capricorn-toggle-button",					"value": "Hide rcat list"				}, {					'click': function {						$( "#capricorn-toggle-content" ).toggle;						var buttonText = $("#capricorn-toggle-button")[0].value;						if (buttonText === "Hide rcat list") {							$("#capricorn-toggle-button")[0].value = "Show rcat list"						} else {							$("#capricorn-toggle-button")[0].value = "Hide rcat list"						};					}				}) ], { 'class': 'redirectMsg' }),			buildTagList(mblob.rcatt),			uiStatusLine = el('p', [ patrolLine = el('span', [], {}), statusbar = el('span', [], {					'class': 'status-line'				}), el('span', [					link(["Statistics for this page"], 'https://tools.wmflabs.org/pageviews?project=en.wikipedia.org&pages=' + encodeURIComponent(mw.config.get('wgPageName'))),					' • ',					link(["WP:TMR"], mw.util.getUrl("Wikipedia:Template messages/Redirect pages")),					' • ',					link(["About Capricorn"], mw.util.getUrl("User:Wugapodes/Capricorn"))				], {					'style': 'float: right;'				}) ])		], {			'action': 'javascript:void(0)',			'class': 'kephir-sagittarius-editor'		}, {			'submit': function (ev) {				ev.preventDefault;				if (uiStatusLine.childNodes[1].childNodes[0]) {					var patrolVal = uiStatusLine.childNodes[1].childNodes[0].childNodes[0].checked;					if (patrolVal) {						api.get({ "action": "query", "format": "json", "prop": "revisions", "meta": "tokens", "titles": mw.config.get('wgPageName'), "rvprop": "ids", "rvslots": "", "rvlimit": "1", "rvdir": "newer", "type": "patrol" }, {							success: function (result) { //console.log(mw.config.get('wgPageName')) var patrolToken = result["query"]["tokens"]["patroltoken"]; var revIDpart = result["query"]["pages"]; var revID = null; for (var page in revIDpart) { revID = revIDpart[page]["revisions"][0]["revid"]; }								//console.log(revID) api.post({									"action": 'patrol',									"revid": revID,									"token": patrolToken								}, {									success: function (result) {										if (result.error) {											console.log(result.error);											setStatus([ 'API error: "',												result.error.info,												'" [code: ', el('code', [result.error.code]), ']' ]);											console.log(result.error)											return;										}									}								}); }						});					}				}				ui.doCheck(saveCallback);			}		}); ui.statusLine = uiStatusLine; ui.patrolLine = patrolLine; ui.origTarget = origTarget var sectCache = {}; var $uiTarget = jQuery(uiTarget); $uiTarget.suggestions({			submitOnClick: false,			delay: 500,			fetch: function (query) {				$uiTarget.suggestions('suggestions', []);				if (query.indexOf('#') !== -1) {					var title = query.substr(0, query.indexOf('#'));					var sect = query.substr(query.indexOf('#') + 1);					if (sectCache[title]) {						var normSect = normaliseAnchor(sect);						$uiTarget.suggestions('suggestions', sectCache[title].filter(function (item) {								var norm = normaliseAnchor(item.anchor);								return norm.substr(0, normSect.length) === normSect;							}) );						return;						}					api.get({ action: 'parse', page: title, prop: 'sections|properties', redirects: '1' }).then(function (result) { if (result.parse.redirects && result.parse.redirects.length) { // XXX return; }						var disambig = false; // XXX var normSect = normaliseAnchor(sect); sectCache[title] = result.parse.sections.map(function (item) {							return {								anchor: item.anchor,								title: title + '#' + decodeURIComponent(item.anchor.replace(/_/g, ' ').replace(/\.([0-9A-Fa-f][0-9A-Fa-f])/g, '%')), // XXX: hack								disambig: disambig,								toString: function {									return this.title;								}							};						}); $uiTarget.suggestions('suggestions',							sectCache[title].filter(function (item) { var norm = normaliseAnchor(item.anchor); return norm.substr(0, normSect.length) === normSect; })						);					});					return;				}				api.get({ action: 'query', generator: 'allpages', gapprefix: query, gaplimit: 16, prop: 'info|pageprops', }).then(function (result) { var pglist = []; for (var pgid in result.query.pages) { var page = result.query.pages[pgid]; pglist.push({							title: page.title,							pageid: page.pageid,							disambig: page.pageprops && ('disambiguation' in page.pageprops),							redirect: 'redirect' in page,							toString: function {								return this.title;							}						}); }					$uiTarget.suggestions('suggestions', pglist); });			},			result: {				render: function (item, content) {					var elm = this[0];					elm.appendChild(el('span', [item.title], {						style: item.redirect ? 'font-style: italic' : ''					}));					if (item.disambig)						elm.appendChild(el('small', [' (disambiguation page)']));					if (item.redirect)						elm.appendChild(el('small', [' (redirect)']));				},				select: function ($textbox) {					var item = this.data('text');					var textbox = $textbox[0];					textbox.value = item.title;					if (item.redirect) {						api.get({ action: 'query', pageids: item.pageid, redirects: '1' }).then(function (result) { var redir = result.query.redirects.pop; textbox.value = redir.to + (redir.tofragment ? '#' + redir.tofragment : ''); });					}					return true;				}			}		}); ui.doCheck = function (callback) { var that = this; if (!/^\s*[^\|{}[\]]+\s*$/.test(mblob.target)) { setStatus(['Error: the target page name is invalid.']); return; }			if (needsCheck) { var oldTarget = mblob.target; var normTarget; try { normTarget = new mw.Title(oldTarget); } catch (e) { setStatus(['"', oldTarget, '" is not a valid page name. Try again to proceed anyway.']); return; }				setStatus(['Checking target validity...']); needsCheck = false; api.get({					action: 'parse',					page: oldTarget = mblob.target,					prop: 'sections',					redirects: '1'				}, {					success: function (result) {						var m;						if (result.error) {							if (result.error.code === 'missingtitle') {								setStatus([ 'Error: The target page "',									link([normTarget.getPrefixedText], mw.util.getUrl(normTarget.getPrefixedText, { "class": "new" })),									'" does not exist. Try again to proceed anyway.' ]);							} else {								setStatus([ 'API error: "',									result.error.info,									'" [code: ', el('code', [result.error.code]), ']' ]);							}							return;						}						if (result.parse.redirects && result.parse.redirects[0]) {							var newTarget = result.parse.redirects[0].to + (result.parse.redirects[0].tofragment ? "#" + result.parse.redirects[0].tofragment : "");							setStatus([ 'Error: The target page "',								link([normTarget.getPrefixedText], mw.util.getUrl(normTarget.getPrefixedText, { redirect: "no" })),								'" is already a redirect to "',								link([newTarget], mw.util.getUrl(newTarget, { redirect: "no" })),								'". Try again to proceed anyway, or ', link(['retarget this redirect to point there directly'], function {									uiTarget.value = mblob.target = newTarget +										((!result.parse.redirects[0].tofragment && normTarget.fragment) ? '#' + normTarget.fragment : '');									needsCheck = true;								}), '.'							]);							return;						}						if (normTarget.fragment) { // we have a section link							var sect = normaliseAnchor(normTarget.fragment);							var isValidSect = false;							var sectlist = result.parse.sections;							for (var j = 0; j < sectlist.length; ++j) {								if (sectlist[j].anchor === sect)									isValidSect = true;							}							if (!isValidSect) {								setStatus([ 'Error: The target page "',									link([normTarget.getPrefixedText], mw.util.getUrl(normTarget.getPrefixedText, { redirect: "no" })),									'" does not have a a section called "',									normTarget.fragment,									'". Try again to proceed anyway.' ]);								return;							}						}						callback(setStatus);					}				}); return; }			callback(setStatus); };		return ui; }	function setSummary(current,orig) { var summary; if (orig === current) { summary= "Modifying redirect categories using Capricorn ♑"; } else { summary = 'Redirecting to ' + current + ' (♑)' }	   return summary }	if ((mw.config.get('wgAction') === 'view') && (mw.config.get('wgArticleId') === 0)) { // nonexistent page. uiWrapper.appendChild(el('div', [ link(['Create a redirect'], function {				while (uiWrapper.hasChildNodes)					uiWrapper.removeChild(uiWrapper.firstChild);				var mblob = new MarkupBlob;				var ui = buildEditingUI(mblob, function (setStatus) { setStatus(['Saving...']); var summary = setSummary(mblob.target,ui.origTarget) api.post({						action: 'edit',						title: mw.config.get('wgPageName'),						createonly: 1,						summary: summary,						text: mblob.toString,						token: mw.user.tokens.get('csrfToken')					}, {						success: function (result) {							if (result.error) {								setStatus([ 'API error: "',									result.error.info,									'" [code: ', el('code', [result.error.code]), ']' ]);								return;							}							setStatus(['Saved. Reloading page...']);							if (/redirect=no/.test(location.href)) // XXX								location.reload;							else								location.search = location.search ? location.search + '&redirect=no' : '?redirect=no';						}					}); });				ui.statusLine.insertBefore(el('input', null, {						type: 'submit',						value: 'Save'					}), ui.statusLine.firstChild);				uiWrapper.appendChild(ui);			}), ' from this page with Capricorn' ], {			"class": "kephir-sagittarius-invite" }));		contentText.parentNode.insertBefore(uiWrapper, contentText); } else if ((mw.config.get('wgAction') === 'view') && mw.config.get('wgIsRedirect') && redirMsg) { // start editor immediately uiWrapper.appendChild(el('div', ['Loading page source…'], { "class": "kephir-sagittarius-loading" }));		contentText.insertBefore(uiWrapper, contentText.firstChild); api.get({			action: 'query',			prop: 'revisions',			rvprop: 'timestamp|content',			pageids: mw.config.get('wgArticleId'),			rvstartid: mw.config.get('wgRevisionId'),			rvlimit: 1,			rvdir: 'older'		}, {			success: function (result) {				if (result.error) {					uiWrapper.appendChild(el('div', [						'API error: "',						result.error.info,						'" [code: ', el('code', [result.error.code]), ']. Reload to try again.'					], {						"class": "kephir-sagittarius-error"					}));					return;				}				while (uiWrapper.hasChildNodes)					uiWrapper.removeChild(uiWrapper.firstChild);				var page = result.query.pages[mw.config.get('wgArticleId')];				var mblob;				var token = mw.user.tokens.get('csrfToken')				try {					mblob = new MarkupBlob(page.revisions[0]['*']);				} catch(e) {					uiWrapper.appendChild(el('div', ['Error: unable to parse page. Edit the source manually.'], {						"class": "kephir-sagittarius-error" }));					return; }				redirMsg.parentNode.removeChild(redirMsg); var ui = buildEditingUI(mblob, function (setStatus) {					setStatus(['Saving...']);					var summary = setSummary(mblob.target,ui.origTarget)					api.post({ action: 'edit', title: mw.config.get('wgPageName'), basetimestamp: page.revisions[0].timestamp, summary: summary, text: mblob.toString, token: mw.user.tokens.get('csrfToken') }, {						success: function (result) { if (result.error) { setStatus([									'API error: "',									result.error.info,									'" [code: ', el('code', [result.error.code]), ']'								]); return; }							setStatus(['Saved. Reloading page...']); if (/redirect=no/.test(location.href)) // XXX location.reload; else location.search = location.search ? location.search + '&redirect=no' : '?redirect=no'; }					});								});				var userName = mw.user.getName; api.get({					"action": "query",					"format": "json",					"list": "users",					"usprop": "groups",					"ususers": userName				}, { success: function(result) {					var groups = result["query"]["users"][0]["groups"]					if (groups.includes("patroller")) {						ui.patrolLine.insertBefore(el('label', [									el('input', [], { 'class': 'checkbox', 'type': 'checkbox', 'id': 'patrol', 'value': 'patrol' }), 'Mark as patrolled?']),null);						}					}				}); ui.statusLine.insertBefore(el('input', null, { type: 'submit', value: 'Save' }), ui.statusLine.firstChild); uiWrapper.appendChild(ui); }		});	} else if ((mw.config.get('wgPageContentModel') === 'wikitext') && ((mw.config.get('wgAction') === 'edit') || (mw.config.get('wgAction') === 'submit'))) {		if (mw.util.getParamValue('section'))			return;		var editform = document.getElementById('editform');		if (!editform || !editform.wpTextbox1 || editform.wpTextbox1.readOnly)			return;		var uiPivot = document.getElementsByClassName('wikiEditor-ui')[0];		var ui, mblob;		firstHeading.appendChild(document.createTextNode(' '));		firstHeading.appendChild(link(['♑'], function {			if (ui && ui.parentNode)				ui.parentNode.removeChild(ui);			try {				mblob = new MarkupBlob(editform.wpTextbox1.value);			} catch (e) {				alert("Error: unable to parse page. This page is probably not a redirect.");				return;			}			currentTarget = mblob.target			ui = buildEditingUI(mblob, function  { editform.wpSummary.value = 'Redirecting to ' + mblob.target + ' (♑)'; editform.wpTextbox1.value = mblob.toString; mblob = null; ui.style.display = 'none'; uiPivot.style.display = ''; });			ui.style.display = 'none';			ui.statusLine.insertBefore(el('input', null, {				type: "button",				value: "Cancel",			}, {				click: function {					mblob = null;					ui.style.display = 'none';					uiPivot.style.display = ;								}			}), ui.statusLine.firstChild);			ui.statusLine.insertBefore(el('input', null, {				type: "submit",				value: "Check"			}), ui.statusLine.firstChild);			uiPivot.parentNode.insertBefore(ui, uiPivot);			uiPivot.style.display = 'none';			ui.style.display = ;		}, {			"class": "kephir-sagittarius-editlink",			"title": "Edit this redirect with Capricorn"		}));		var submitButton;		var inputs = editform.getElementsByTagName('input');		for (var i = 0; i < inputs.length; ++i) {			inputs[i].addEventListener('click', function (ev) { submitButton = this; }, false);		}		editform.addEventListener('submit', function (ev) { if (submitButton !== editform.wpSave) return; if (mblob) { ev.preventDefault; ev.stopImmediatePropagation; ui.doCheck(function (setStatus) {					setStatus(['Proceeding with saving...']);					var summary = setSummary(currentTarget,ui.origTarget)					editform.wpTextbox1.value = mblob.toString;					editform.wpSummary.value = summary;					mblob = null;					editform.submit;				}); }		}, false);	}	if (!window.kephirSagittariusFollowCategoryRedirects)	if ((mw.config.get('wgAction') === 'view') && (mw.config.get('wgNamespaceNumber') === wgNamespaceIds.category)) {		var pagesList = document.getElementById('mw-pages').getElementsByClassName('mw-redirect');		for (var i = 0; i < pagesList.length; ++i) {			pagesList[i].href += '?redirect=no';		}	} }

function abortConditions { if (window.location.href.includes('&diff=')) { throw 'Capricorn does not run when viewing page diffs. Please revert before editing redirect.'; }	if (mw.config.get('wgNamespaceNumber') < 0) { throw 'Page is in a virtual namespace. Capricorn aborts.'; } }

function Capricorn { $.getJSON("https://en.wikipedia.org/w/index.php?title=User:Wugapodes/Capricorn/RedirectAliases.json&action=raw&ctype=application/json", function(aliasJSON) {		$.getJSON("https://en.wikipedia.org/w/index.php?title=User:Wugapodes/Capricorn/RedirectTemplates.json&action=raw&ctype=application/json",function(templateJSON) { mw.loader.using(['jquery.suggestions', 'mediawiki.api', 'mediawiki.Title', 'mediawiki.action.view.redirectPage'], function {				mw.loader.getScript( "https://en.wikipedia.org/w/index.php?title=User:Wugapodes/CapricornUtilsDev.js&action=raw" ).then( function { mainCallback(aliasJSON,templateJSON); },					function(e) { console.error(e); }				);			});		});	}); }

var api = new mw.Api;

api.get({	action: "query",	format: "json",	prop: "info",	formatversion: 2,	titles: mw.config.get('wgPageName') }, {	success: function (result) {		try {			abortConditions;		} catch(abortMessage) {			console.info(abortMessage)			return;		}		if (result.query.pages[0].redirect || (window.location.href.includes('&redlink=1'))) {			Capricorn;		} else {			console.debug('Page is not a redirect.')			return;		}	} }); /*

//