MediaWiki talk:Gadget-OrangeLinks.js

From Wiktionary, the free dictionary
Latest comment: 2 years ago by Erutuon in topic Yellow instead of blue when links to sense?
Jump to navigation Jump to search

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