User:Erutuon/scripts/gadgets-definition.js

Note: You may have to bypass your browser’s cache to see the changes. In addition, after saving a sitewide CSS file such as MediaWiki:Common.css, it will take 5-10 minutes before the changes take effect, even if you clear your cache.

  • Mozilla / Firefox / Safari: hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (Command-R on a Macintosh);
  • Konqueror and Chrome: click Reload or press F5;
  • Opera: clear the cache in Tools → Preferences;
  • Internet Explorer: hold Ctrl while clicking Refresh, or press Ctrl-F5.

/*
 * Adds links to gadget definitions in [[MediaWiki:Gadgets-definition]] and
 * prettifies them by adding whitespace.
 * Adds anchors to gadget definitions as well as CSS to highlight them when we
 * click a link to them.
 *
 * Can be loaded with the following code:
mw.loader.load("//en.wiktionary.org/w/index.php?title=User:Erutuon/scripts/gadgets-definition.js&action=raw&ctype=text/javascript");
 *
 */

/* jshint boss: true, undef: true, unused: true */
/* globals $, mw */

(function gadgetsDefinitionIIFE () {
"use strict";

// Only operate on [[MediaWiki:Gadgets-definition]] when the text is visible.
if (!(mw.config.get("wgCanonicalNamespace") == "MediaWiki"
&& mw.config.get("wgTitle") === "Gadgets-definition"
&& document.querySelector(".mw-parser-output")))
	return;

mw.loader.using("mediawiki.util", function () {
	// Highlight a gadget's definition when we follow a link to it.
	mw.util.addCSS("li:target { \
		border: solid 1px lightgreen; \
		padding: 0.1em 0.3em; \
		background-color: #eee; \
	}");
});

// Technique gleaned from [[w:fr:Utilisateur:Od1n/AddLinksGadgetsDefinition.js]].
// This anchor element is used to generate links and is not attached to the document.
var link = document.createElement("a");
function makeLink(href, text) {
	link.href = href;
	link.textContent = text;
	return link.outerHTML;
}

function makeWikilink(page, text) {
	return makeLink(mw.util.getUrl(page), text || page);
}

function linkGadgetSource(sourcePage) {
	return makeWikilink("MediaWiki:Gadget-" + sourcePage, sourcePage);
}

function linkGadgetAnchor(gadgetName, text) {
	return makeLink("#" + makeGadgetId(gadgetName), text || gadgetName);
}

var gadgetNameRegex = /^(\s*)([\w_-]+)\s*/;
function getGadgetName(innerHTML) {
	var match = gadgetNameRegex.exec(innerHTML);
	return match ? match[2] : null;
}

function makeGadgetId(gadgetName) {
	return "Gadget-" + gadgetName;
}

function processGadgetDefinition(innerHTML) {
	return innerHTML
		// link gadget name to system message page and add space after it
		.replace(gadgetNameRegex,
			function (wholeMatch, whitespace, gadgetName) {
				return whitespace
					+ linkGadgetSource(gadgetName)
					+ " ";
			})
		.replace(/([\w_\-.]+\.(?:css|js(?:on)?))/g, linkGadgetSource) // link script names
		.replace(/\s*\|\s*/g, " | ") // spaces around pipes
		
		/*
		 * process options
		 *
		 * Link dependencies: ext.gadget.name to entry on this page, others to
		 * [[mw:ResourceLoader/Core modules]] (even though not all have an entry
		 * there).
		 *
		 * Link peers to entry on this page.
		 *
		 * Link rights to [[mw:Manual:User_rights#List_of_permissions]]. There
		 * are unfortunately no anchors for individual rights.
		 *
		 * Link skin names to page in Skin namespace on MediaWiki. This uses
		 * wgAvailableSkins so will probably fail if the skin has a
		 * MediaWiki:skinname-<name> page in the local wiki.
		 */
		.replace(/([a-z]+)\s*=\s*(.+?)(?=\s*[|\]])/g,
			function (wholeMatch, key, value) {
				var splitValue = value.split(/\s*,\s*/g);
				switch (key) {
					case "dependencies":
						splitValue = splitValue.map(function (dependency) {
							var gadgetName = /^ext\.gadget\.(.+)$/.exec(dependency);
							if (gadgetName)
								return linkGadgetAnchor(gadgetName[1], dependency);
							else
								return makeWikilink("mw:ResourceLoader/Core modules#" + dependency, dependency);
						});
						break;
					case "rights":
						key = makeWikilink("mw:Manual:User_rights#List_of_permissions", key);
						break;
					case "skins": {
						var skinNames = mw.config.get('wgAvailableSkins');
						if (skinNames) {
							splitValue = splitValue.map(function (skin) {
								return skinNames[skin]
									? makeWikilink("mw:Skin:" + skinNames[skin], skin)
									: skin;
							});
						}
						break;
					}
					case "peers":
						splitValue = splitValue.map(linkGadgetAnchor);
					
				}
				return key + " = " + splitValue.join(", ");
			});
}

$(function () {
	var $parserOutput = $(".mw-parser-output");
	
	// :not(.gadgets-validation li) excludes elements under
	// class="gadgets-definition" in output of Module:validate_gadgets on other wikis.
	
	// Process gadget definitions in lists.
	$parserOutput.find("li:not(.gadgets-validation li)").each(function (i, element) {
		// Add id so that gadget definitions can be highlighted when we click a link
		// to them.
		var gadgetName = getGadgetName(element.innerHTML);
		if (gadgetName)
			element.id = makeGadgetId(gadgetName);
		
		element.innerHTML = processGadgetDefinition(element.innerHTML);
	});
	
	// Process gadget definitions in pre tags.
	$parserOutput.find("pre:not(.gadgets-validation pre)").each(function (i, element) {
		element.innerHTML = element.innerHTML.replace(/[^\n]+/g, processGadgetDefinition);
	});
});

})(); // IIFE