MediaWiki talk:Gadget-OrangeLinks.js

Latest comment: 2 years ago by Erutuon in topic Yellow instead of blue when links to sense?

Testcases edit

wikitext result notes
{{m|en|Zhōngguó}} Zhōngguó no English entry
Zhōngguó MutationObserver should change this to orange link with $(".testcase a").each((i, elem) => elem.href = elem.href + "#English")
Zhōngguó, Zhōngguó, Zhōngguó, Zhōngguó links to index.php with title parameter
Zhōngguó link to wrong PHP file
empty, Testcases links in which href starts with #; should be skipped
Aare language name with space in it; should not be oranged
中國#Derived terms, →‎Further reading non-language header; should not be oranged
{{m|bsh|jʹukuř}} jʹukuř Kamkata-viri, language name with /-[a-z]/ in it
{{m|en|-er|id=Oxford}} -er sense id not starting with lowercase letter; should not oranged, but test for language name in link fragment is not sophisticated enough

Skip external links edit

JavaScript code:

/*jshint loopfunc:true,latedef:true,undef:true */
/*globals mw, jQuery */
(function(){ // <nowiki>
'use strict';
/**
 * General idea: for each bluelink with an anchor, the script fetches the categories for its target page
 * and checks whether it contains a part-of-speech category. If a suitable category is found, the script
 * assumes the anchor is valid. If not, the link is coloured orange.
 * 
 * Previous version by [[User:Yair rand]], based in turn on an idea by [[User:Hippietrail]].
 * This script is a complete rewrite.
 */

var api = new mw.Api();
var fresh = [], queue = {}, catcache = {};

var rxPage = new RegExp('^' + mw.config.get('wgArticlePath').replace(/([.+*?[\]$^])/g, '\\$1').replace('\\$1', '(.*)') + '$'); // hax

var console = mw.util.getParamValue('debug') ? window.console : window.console; //XXX: the nondebug version of console should be a dull object;

function processLink(link) {
	try {
		if (link._ORANGED === link.href) // XXX: eliminate this hack
			return;

		if (/(un)?selectedTab/.test(link.parentNode.className)) // XXX: skip TabbedLanguages tabs; is there no other way?
			return;
		if (!link.href || /^javascript:/.test(link.href))
			return;
		var m, url = new mw.Uri(link.href);
		if (url.getAuthority() !== location.hostname)
			return;
		if (!url.fragment || !/^[A-Zǃ]/.test(url.fragment)) // XXX: "ǃ" is for nmn (Xoo); I hope there are no other such pathological language names...
			return;

		// XXX: exclude non-language headers
		if (/^(Noun|Proper_noun|Verb|Adjective|Adverb|Participle|Interjection|Particle|Suffix|Prefix|Symbol|Phrase|Prepositional_phrase|Han_[ct]|Hanja|Hanzi|Kanji|Romanization|Gismu|Rafsi|Brivla|Idiom|Acronym|Initialism)/.test(url.fragment))
			return;
		if (/^(Etymology|Pronunciation|Alternative_forms|See_also|External_links|Derived_terms|Related_terms|Coordinate_terms|Descendants|Inflection|Declension|Conjugation|Usage_notes|Translations|References|Anagrams|Synonyms|Antonyms|Meronyms|Holonyms|Hyponyms|Hypernyms|Quotations|Statistics)/i.test(url.fragment))
			return;
			
		// skip same-page links
		if (/^#/.test(link.getAttribute('href'))) {
			if (console) console.warn('skipping local ', link);
			return;
		}
        

		if (!(m = rxPage.exec(url.path)))
			return;
		var title = new mw.Title(decodeURIComponent(m[1] + '#' + url.fragment));
		if (title.getNamespaceId() !== 0)
			return;
        // skip external links
        if (title.getMain().indexOf(":") >= 0) {
            return;
        } 

		var cache = catcache[title.getPrefixedText()];
		if (cache) {
			link._ORANGED = link.href;
			var frag = title.fragment.replace(/-[a-z].*$/, ''); // XXX: {{senseid}} hack
			frag = decodeURIComponent(frag.replace(/\.([0-9A-Fa-f][0-9A-Fa-f])/g, '%$1'));
			for (var i = 0; i < cache.length; ++i) {
				if (cache[i].substr(0, frag.length) === frag) {
					// XXX: discount "German Low German", etc. but allow "Vietnamese Han tu" and "Vietnamese Nom" to count as an existing vi entry
					// XXX: use /^ (lemmas|non-lemma forms)$/ instead?
					if (/^ ([a-z]|Han tu|Nom)/.test(cache[i].substr(frag.length)))
						return;
				}
			}
			link.className += ' partlynew';
			if (console)
				console.info('partlynew ', link, '; cache=', cache, ' frag=', frag);
		} else {
			var entry = queue[title.getPrefixedText()];
			if (!entry) {
				entry = queue[title.getPrefixedText()] = [];
				fresh.push(title.getPrefixedText());
			}
			entry.push(link);
		}
	} catch (e) {
		if (window.console)
			console.error(e, 'while processing', link, ' href=', link.href);
	}
}

function processQueue(queue) {
	function collect(sl) {
		return jQuery.Deferred(function (d) {
			var query = {
				'action': 'query',
				'titles': sl.join('|'),
				'redirects': 1,
				'prop': 'categories',
				'cllimit': 100,
				'continue': ''
			};
			var data;
			
			function pluckResults(result) {
				if (console)
					console.info('result', result);
				for (var pageid in result.query.pages) {
					var titl = (new mw.Title(result.query.pages[pageid].title)).getPrefixedText();
					var cats = result.query.pages[pageid].categories || [];
					var cache = catcache[titl];
					if (!cache)
						cache = catcache[titl] = [];
					
					for (var i = 0; i < cats.length; ++i) {
						cache.push(cats[i].title.replace(/^Category:/, ''));
					}

					if (console)
						console.info('cache for', titl, 'is', cache);
				}
				
				if (result.query.redirects) {
					var redr = result.query.redirects;
					for (var j = 0; j < redr.length; ++j) {
						var fromt = (new mw.Title(redr[j].from)).getPrefixedText();
						var targt = (new mw.Title(redr[j].to)).getPrefixedText();
						catcache[fromt] = catcache[targt];
					}
				}
				
				if (result['continue']) {
					for (var key in result['continue'])
						query[key] = result['continue'][key];
					api.get(query).then(pluckResults, fail);
				} else
					d.resolve(sl);
			}
			
			function fail(code, details, xhr) {
				d.reject(code, details, xhr);
			}

			api.get(query).then(pluckResults, fail);
		});
	}
	
	for (var i = 0; i < fresh.length; i += 25) {
		collect(fresh.slice(i, i + 25)).then(function (slice) {
			for (var i = 0; i < slice.length; ++i) {
				var links = queue[slice[i]];
				for (var j = 0; j < links.length; ++j) {
					processLink(links[j]);
				}
				delete queue[slice[i]];
			}
		}, function (code, details, xhr) {
			console.error(code, details, xhr);
		});
	}
	fresh = [];
}

var links = document.getElementsByTagName('a');
for (var i = 0; i < links.length; ++i) {
	processLink(links[i]);
}
processQueue(queue);

var MutationObserver = window.MutationObserver || window.WebKitMutationObserver;

if (mw.util.getParamValue('@orangelinks.no_live'))
	MutationObserver = null;

if (MutationObserver) {
	var mo = new MutationObserver(function (events) {
		for (var i = 0; i < events.length; ++i) {
			if (events[i].type === 'childList') {
				for (var j = 0; j < events[i].addedNodes.length; ++j) {
					if (events[i].addedNodes[j].tagName === 'A')
						processLink(events[i].addedNodes[j]);
					if (!events[i].addedNodes[j].getElementsByTagName)
						continue;
					var links = events[i].addedNodes[j].getElementsByTagName('a');
					for (var k = 0; k < links.length; ++k) {
						processLink(links[k]);
					}
				}
			}
			if ((events[i].type === 'attributes') && (events[i].target.tagName === 'A') && (events[i].attributeName === 'href')) {
				processLink(events[i].target);
			} else if ((events[i].type === 'attributes') && (events[i].target.tagName === 'A') && (events[i].attributeName === 'class')) {
				processLink(events[i].target);
			}
		}
		processQueue(queue);
	});

	mo.observe(document, {
		attributes: true,
		childList: true,
		subtree: true
	});
}

})();

Doesn't work on mobile edit

This gadget works perfectly on the computer version of the site (en.wiktionary.org) but it doesn't on the mobile version (en.m.wiktionary.org). Please, can someone fix this minor bug ? @Erutuon can you if it doesn't bother you ? Malku H₂n̥rés (talk) 15:31, 29 August 2020 (UTC)Reply

@Malku H₂n̥rés: It doesn't even run on mobile because its definition in MediaWiki:Gadgets-definition doesn't have targets = desktop, mobile. It might work on mobile without any changes, but needs to be tested beforehand. — Eru·tuon 16:59, 29 August 2020 (UTC)Reply
Ok thank you to have found the cause of this. I activated the aforementioned gadget yesterday in Special:Preferences and it works only if I remove manually ".m" from the url. Malku H₂n̥rés (talk) 18:43, 29 August 2020 (UTC)Reply

Logged-out user edit

Enabled this gadget as a logged-out user using Wiktionary:Preferences/V2 and the index.php links here aren't turned orange, though the rest are. — Eru·tuon 20:42, 22 July 2021 (UTC)Reply

Yellow instead of blue when links to sense? edit

See {{desctree|ar|رِجْل|g=f|id=leg|noalts=1}} in Reconstruction:Proto-Semitic/rigl-. The Arabic term shows as yellow for me, but should be blue. Kritixilithos (talk) 10:05, 16 August 2021 (UTC)Reply

@Kritixilithos: Fixed! Thanks for the report. — Eru·tuon 19:08, 16 August 2021 (UTC)Reply
Return to "Gadget-OrangeLinks.js" page.