User:Useigor/Gadget-Ledokol.js

Note – after saving, you may have to bypass your browser’s cache to see the changes.

  • 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.

//en LEDOKOL: Little-Effort Dictionaries Overview by Known word for One Language
//ru ЛЕДОКОЛ: ЛЕгкоДОступный Каталог Открытых Лексиконов

var langcodes;      // "name":"code"
var langnames = {}; // "code":"name" (reversed langcodes)

// https://www.mediawiki.org/wiki/API:Get_the_contents_of_a_page
// /w/api.php?action=parse&page=Module:languages/canonical names.json&prop=wikitext&formatversion=2
function updateStorageLangcodes( present ) {
	return new mw.Api().get({
		"action": "parse",
		"page": "Module:languages/canonical names.json",
		"prop": "wikitext",
		"formatversion": 2, // omitted? data.parse.wikitext["*"]
		"format": "json"
	}).done( function(data) {
		localStorage["languages/canonical names/date"] = present || Math.floor( Date.now() / 8.64e7 ); // avoid storing over-specific timestamp
		localStorage["languages/canonical names/json"] = data.parse.wikitext.replaceAll(/\n */g,"").replaceAll(/" *: *"/g,'":"');
	});
}

function displayHeaderLangcodes() {
	langcodes = JSON.parse( localStorage["languages/canonical names/json"] || null );
	if ( !langcodes ) {
		delete localStorage["languages/canonical names/date"];
		console.warn('Local storage: "languages/canonical names/json" is absent');
		return;
	}
	Object.entries(langcodes).forEach( function(entry) {
		langnames[ entry[1] ] = entry[0];
	});
	document.querySelectorAll(".mw-parser-output > h2 .mw-headline").forEach( function(hl) {
		var name = hl.innerText;
		var code = langcodes[name] || "--";
		var a = document.createElement("a");
		a.href = "/wiki/Category:"+ name + (name.includes("Language")? "" : "_language"); // Sign Language [language]
		a.innerText = "("+ code +")";
		hl.after( a );
		a.before( document.createTextNode(" ") ); // a.style["margin-left"] = "1ch"
	});
}

var ledokolRef = document.createElement("span"); // preserve em
ledokolRef.style["position"] = "absolute";
ledokolRef.style["padding-top"] = "0.20em";
ledokolRef.style["margin-top"] = "1.20em";

var ledokolRef2 = ledokolRef.appendChild( document.createElement("code") ); // reset inconsistent properties
ledokolRef2.style["font-size"] = "0.875rem";
ledokolRef2.style["font-family"] = "sans-serif";
ledokolRef2.style["font-style"] = "normal";
ledokolRef2.style["font-weight"] = "normal";
ledokolRef2.appendChild( document.createElement("a") ).target = "_blank";
ledokolRef2.append( document.createTextNode(" ") );
ledokolRef2.appendChild( document.createElement("a") ).target = "_blank";
ledokolRef2.children[0].innerText = "References";
ledokolRef2.children[1].innerText = "(Category)";

function toggleLedokolRef( ev ) {
	if ( !langcodes )
		return;

	if ( ev.type == "mouseenter" ) {
		var code = "0code";
		var name = "0lang";
		var word = "0word";
		if ( this.nodeName == "A" ) { // a
			code = this.parentNode["lang"];
			if ( this.classList.contains("new") ) {
				word = this.search.replace(/.*title=([^&]*).*/g, "$1");
			} else if ( this.pathname.search("^/wiki/") != -1 ) {
				word = this.pathname;
				if ( !langnames[code] )
					name = this.hash.replace("#","");
			}
			name =  langnames[code] || name;
		} else { // h2 .mw-headline
			word = location.pathname;
			name = this.innerText;
			code = langcodes && langcodes[name] || code;
		}	
		word = word.replace(/.*\//g, "");
		var linkName = name.replaceAll(" ","_");
		ledokolRef2.firstElementChild.href = "/wiki/Appendix:"+ name +"_bibliography#"+ word;
		ledokolRef2.lastElementChild.href = "/wiki/Category:"+ name +"_reference_templates";
		ledokolRef.style["display"] = "";
		this.before( ledokolRef );
	} else if ( ev.type == "mouseleave" ) { // a.parentNode, h2
		ledokolRef.style["display"] = "none";
	}
}

function ledokolEncode( input, href ) {
	if ( !input ) return;

	if ( href.includes("FFFFFF") ) {
		return href.replace( "FFFFFF", input );
	} else if ( href.includes("EEEEEE") ) {
		return href.replace( "EEEEEE", input.replaceAll(" ","+") );
	}
}

function loadLedokol() {
	if ( mw.config.get("wgArticleId") == 0 ) // wgWMEPageLength, wgRevisionId
		return;
	
	var ns = mw.config.get("wgNamespaceNumber"); // wgNamespaceIds
	if ( ns == 100 && mw.config.get("wgTitle").search("bibliography$") != -1 ) { // 100:"appendix"
		var search = document.querySelector("#mw-content-text .mw-parser-output").insertAdjacentElement( "beforebegin", document.createElement("p") );
		search.style["position"] = "fixed";
		search.style["left"] = "0";
		search.style["bottom"] = "0";
		search.style["width"] = "100%";
		search.style["text-align"] = "center";
		var input = search.appendChild( document.createElement("input") );
		input.placeholder = 'Change links with query="FFFFFF"';
		input.title = "FFFFFF (space=space), EEEEEE (space=+)"
		var button = search.appendChild( document.createElement("button") );
		button.innerText = "open";
		
		if ( location.hash ) {
			input.value = decodeURI(location.hash).replace("#","").replaceAll("_"," ");
		}
		var linkCount = 0;
		document.querySelectorAll("#mw-content-text a").forEach( function(a) {
			if ( a.href.search("(FFFFFF|EEEEEE)") != -1 ) {
				linkCount++;
				a.dataset["href"] = a.href;
				a.href = ledokolEncode( input.value, a.dataset["href"] );
				a.style["background-color"] = "rgba(255,127,0,0.20)";
			}
		});
		button.innerText += " "+ linkCount;

		input.addEventListener("input", function() {
			location.hash = "#"+ input.value;
			document.querySelectorAll("#mw-content-text a[data-href]").forEach( function(a) {
				ledokolEncode( input.value, a.dataset["href"] );
				a.href = ledokolEncode( input.value, a.dataset["href"] );
			});
		});
		button.addEventListener("click", function() {
			document.querySelectorAll("#mw-content-text a[data-href]").forEach( function(a) {
				open( a.href, "_blank" ); // _parent, _top
			});
		});
	} else if ( ns == 0 || ns == 118 ) { // 0:"" || 118:"reconstuction"
		var past = JSON.parse( localStorage["languages/canonical names/date"] || null );
		var present = Math.floor( Date.now() / 8.64e7 );
		if ( !past || present-past > 7 ) {
			$.when( updateStorageLangcodes(present) ).done( function() {
				displayHeaderLangcodes();
			});
		} else {
			displayHeaderLangcodes();
		}
		document.querySelectorAll("#mw-content-text a").forEach( function(a) {
			if ( a.parentNode["lang"] && a.host == location.host && a.innerText ) { // lang-marked && internal && not empty
				a.addEventListener("mouseenter", toggleLedokolRef);
				a.parentNode.addEventListener("mouseleave", toggleLedokolRef);
			}
		});
		document.querySelectorAll("#mw-content-text h2 .mw-headline").forEach( function(h) {
			h.addEventListener("mouseenter", toggleLedokolRef);
			h.parentNode.addEventListener("mouseleave", toggleLedokolRef);
		});
	}
}

document.addEventListener("DOMContentLoaded", loadLedokol);