MediaWiki:Gadget-OrangeLinks.js
Catatan: Selepas menyiarkan perubahan, anda mungkin perlu memintas cache pelayar untuk melihatnya.
- Firefox / Safari: Tahan Shift sambil mengklik Reload, atau tekan sama ada Ctrl-F5 atau Ctrl-R (⌘-R pada Mac)
- Google Chrome: Tekan Ctrl-Shift-R (⌘-Shift-R pada Mac)
- Internet Explorer / Edge: Tahan Ctrl sambil mengklik Refresh, atau tekan Ctrl-F5
- Opera: Tekan Ctrl-F5.
/*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 (/^(Kata_nama|Kata_nama khas|Kata_kerja|Kata_sifat|Adjektif|Adverba|Kata_keterangan|Partisipel|Kata_seru|Partikel|Akhiran|Awalan|Simbol|Frasa|Frasa_sendi_nama|[ct]_Han|Hanja|Hanzi|Kanji|Perumian|Gismu|Rafsi|Brivla|Simpulan_bahasa|Akronim|Parapan)/.test(url.fragment))
return;
if (/^(Etimologi|Sebutan|Bentuk_alternatif|Lihat_juga|Pautan_luar|Terbitan|Istilah_terbitan|Istilah_berkaitan|Istilah_setara|Keturunan|Infleksi|Tasrif_nama|Deklensi|Kata_hubung|Nota_penggunaan|Terjemahan|Rujukan|Anagram|Sinonim|Antonim|Meronim|Holonim|Hiponim|Hipernim|Petikan|Statistik)/i.test(url.fragment))
return;
// skip local links
if (/^#/.test(link.getAttribute('href'))) {
if (console) console.warn('melangkau ', link, ' tempatan');
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, 'semasa memproses', 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(/^Kategori:/, ''));
}
if (console)
console.info('cache bagi', titl, 'adalah', 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
});
}
})();