ميډياويکي:Gadget-OrangeLinks.js

يادښت: د غوره توبونو د خوندي کولو وروسته، خپل د کتنمل (بروزر) ساتل شوې حافظه تازه کړی.

  • فايرفاکس/ سفري: په دې کتنمل کې د Reload د ټکوهلو په وخت د Shift تڼۍ نيولې وساتی، او يا هم Ctrl-F5 يا Ctrl-Rتڼۍ کېښکاږۍ (په Apple Mac کمپيوټر باندې ⌘-R کېښکاږۍ)
  • گووگل کروم: په دې کتنمل کې د Ctrl-Shift-R تڼۍ کېښکاږۍ (د مک لپاره ⌘-Shift-R)
  • انټرنټ اېکسپلورر: په دې کتنمل کې د Refresh د ټکوهلو په وخت کې د Ctrl تڼۍ کېښکاږلې ونيسۍ، او يا هم د Ctrl-F5 تڼۍ کېښکاږۍ
  • اوپرا: په دې کتنمل کې د خپل براوزر ساتل شوې حافظه پدې توگه سپينولی شی Tools→Preferences
/*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 : null;

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 local 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;

		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
	});
}

})();