Khác biệt giữa các bản “MediaWiki:Gadget-popups.js”

(Cập nhật danh sách tiền tố liên kết liên wiki)
(Cập nhật theo w:MediaWiki:Gadget-navpop.js (67160451))
 
// Trying to shove as many of these as possible into the pg (popup globals) object
var pg = {
api: {}, // MediaWiki API requests
re: {}, // regexps
ns: {}, // namespaces
};
/* Bail if the gadget/script is being loaded twice */
/* An element with id "pg" would add a window.pg property, ignore such property */
if( window.pg ) {
if (window.pg && !(window.pg instanceof HTMLElement)) {
return;
}
/* Export to global context */
window.pg = pg;
 
/// Local Variables: ///
/// mode:c ///
}
 
// FIXME: Only used once here, confusing with native (and more widely-used) unescape, should probably be replaced
// Then again, unescape is semi-soft-deprecated, so we should look into replacing that too
function unEscape(str, sep) {
return str.split('\\\\').join('\\').split('\\'+sep).join(sep).split('\\n').join('\n');
if (!this.http) { return null; }
this.http.open(this.method, this.url, this.async);
this.http.setRequestHeader( 'Api-User-Agent', pg.miscapi.userAgent );
};
/** Gets the state of the download. */
newDownload(url, id, callback, onfailure - 1);
}
} else if ($.isFunction(typeof onfailure) === "function") {
onfailure(d,url,id,callback);
}
 
// define constants
Insta.BLOCK_IMAGE = new RegExp('^\\[\\[(?:File|Image|Tập.\\s*tin|Hình|'+Insta.conf.locale.image+
')\\s*:.*?\\|.*?(?:frame|thumbnail|thumb|none|right|left|center|khung|nhỏ|phải|trái|giữa)', 'i');
 
}
o = '', // output
p = 0, // para flag
$r; // result of passing a regexp to $compareLineStringOrReg()
 
// some shorthands
// compare current line against a string or regexp
// if passed a string it will compare only the first string.length characters
// if passed a regexp the result is stored in $r
function compareLineStringOrReg(c) {
function $(c) { return (typeof c == 'string') ? (ll[0].substr(0,c.length)==c) : ($r = ll[0].match(c)); }
return (typeof c == 'string') ? (ll[0] && ll[0].substr(0,c.length)==c) : (r = ll[0] && ll[0].match(c));
}
 
function $$compareLineString(c) { return ll[0]==c; } // compare current line against a string
function _charAtPoint(p) { return ll[0].charAt(p); } // return char at pos p
 
function endl(s) { ps(s); sh(); }
var prev='';
 
while (remain() && $compareLineStringOrReg(/^([*#:;]+)(.*)$/)) {
 
var l_match = $r;
 
sh();
function parse_table()
{
endl(f('<table>', $compareLineStringOrReg(/^\{\|( .*)$/)? $r[1]: ''));
 
for (;remain();) if ($compareLineStringOrReg('|')) switch (_charAtPoint(1)) {
case '}':
endl('</table>');
return;
case '-':
endl(f('<tr>', $compareLineStringOrReg(/\|-*(.*)/)[1]));
break;
default:
parse_table_data();
}
else if ($compareLineStringOrReg('!')) { parse_table_data(); }
else { sh(); }
}
while (remain()) {
td.push(sh());
if ($compareLineStringOrReg('|')) {
if (!tc) break; // we're at the outer-most level (no nested tables), skip to td parse
else if (_charAtPoint(1)=='}') tc--;
}
else if (!tc && $compareLineStringOrReg('!')) break;
else if ($compareLineStringOrReg('{|')) tc++;
}
 
ps('<pre>');
do {
endl(parse_inline_nowiki(ll[0].substring(1)) + "\n");
if (ll[0]) {
} while (remain() && compareLineStringOrReg(' '));
endl(parse_inline_nowiki(ll[0].substring(1)) + "\n");
}
} while (ll[0] && remain() && $(' '));
ps('</pre>');
}
 
replace('__NOTOC__','').
replace('__NOINDEX__','').
replace('__INDEX__','').
replace('__NOEDITSECTION__','');
}
 
// begin parsing
for (;remain();) if ($compareLineStringOrReg(/^(={1,6})(.*)\1(.*)$/)) {
p=0;
endl(f('<h?>?</h?>?', $r[1].length, parse_inline_nowiki($r[2]), $r[1].length, $r[3]));
 
} else if ($compareLineStringOrReg(/^[*#:;]/)) {
p=0;
parse_list();
 
} else if ($compareLineStringOrReg(' ')) {
p=0;
parse_pre();
 
} else if ($compareLineStringOrReg('{|')) {
p=0;
parse_table();
 
} else if ($compareLineStringOrReg(/^----+$/)) {
p=0;
endl('<hr />');
 
} else if ($compareLineStringOrReg(Insta.BLOCK_IMAGE)) {
p=0;
parse_block_image();
 
// handle paragraphs
if ($$compareLineString('')) {
p = (remain()>1 && ll[1]===(''));
if (p) endl('<p><br>');
var split=this.anchor.parenSplit(/((?:[.][0-9A-F]{2})+)/);
var len=split.length;
var value;
for (var j=1; j<len; j+=2) {
// FIXME s/decodeURI/decodeURIComponent/g ?
value = split[j].split('.').join('%')
try {
split[j] value = decodeURIComponent(split[j].split('.').join('%')).split('_').join(' 'value);
} catch (e) {
// cannot decode
}
split[j] = value.split('_').join(' ');
}
return split.join('');
// no more special cases to check --
// hopefully it's not a disguised user-related or specially treated special page
// Includes references
var m=pg.re.main.exec(h);
if(m === null) { this.value=null; }
};
Title.prototype.decodeNasties=function(txt) {
// myDecodeURI uses decodeExtras, which removes _,
var ret= this.decodeEscapes(decodeURI(txt));
// thus ruining citations previews, which are formated as "cite_note-1"
ret = ret.replace(/[_ ]*$/, '');
try {
return ret;
var ret= decodeURI(this.decodeEscapes(txt));
ret = ret.replace(/[_ ]*$/, '');
return ret;
} catch ( e ) {
return txt; // cannot decode
}
};
// Decode valid %-encodings, otherwise escape them
Title.prototype.decodeEscapes=function(txt) {
var split=txt.parenSplit(/((?:[%][0-9A-Fa-f]{2})+)/);
var len=split.length;
// No %-encoded items found, so replace the literal %
if (len===1) {
return split[0].replace(/%(?![0-9a-fA-F][0-9a-fA-F])/g, "%25");
}
for (var i=1; i<len; i=i+2) {
// FIXME is split[i]=decodeURIComponent better?(split[i]);
split[i]=unescape(split[i]);
}
return split.join('');
 
function fixVectorMenuPopups() {
$('divnav.vectorMenuvector-menu h3:first a:first').prop('inNopopupSpan', true);
}
// ENDFILE: titles.js
log( json_ret.warnings[w]['*'] );
} else {
log( json_ret.warnings[w]['.warnings'] );
}
}
function isObject(x) { return x instanceof Object; }
function isFunction(x) {
//return Must!isRegExp(x) use&& jQuery(typeof duex to L1473=== "function" || x $instanceof definitionFunction);
return !isRegExp(x) && (jQuery.isFunction(x) || x instanceof Function);
}
/* eslint-enable no-unused-vars */
}
var structurefn=structure[spans[i]];
if ( structurefn === undefined ) {
// nothing to do for this structure part
continue;
}
var setfn = setPopupHTML;
if (getValueOf('popupActiveNavlinks') &&
if (typeof structure.popupLayout != 'function') { return 'Bad layout'; }
pg.misc.layout=structure.popupLayout();
if ($.isFunction(typeof structure.popupRedirSpans) === "function") { pg.misc.redirSpans=structure.popupRedirSpans(); }
else { pg.misc.redirSpans=[]; }
return makeEmptySpans(pg.misc.layout, a.navpopup);
return ret;
}
 
 
function emptySpanHTML(name, id, tag, classname) {
var callback=function(d){
log( "callback of API functions was hit" );
if ( queryType === 'userinfo' ) {
// We need to do another API request
fetchUserGroupNames( d.data ).then( function() {
showAPIPreview(queryType, htmlGenerator(article,d,navpop), navpop.idNumber, navpop, d);
} );
return;
}
showAPIPreview(queryType, htmlGenerator(article,d,navpop), navpop.idNumber, navpop, d);
};
// New format
return parseInt(tz.split('|')[1],10);
} else if ( tz.indexOf(':') > -1 ) {
// Old format
return( parseInt(tz,10)*60 + parseInt(tz.split(':')[1],10) );
}
}
return 0;
}
 
function getTimeZone() {
if ( !pg.user.timeZone ) {
var tz = mw.user.options.get('timecorrection');
pg.user.timeZone = 'UTC';
if(tz) {
var tzComponents = tz.split('|');
if( tzComponents.length === 3 && tzComponents[0] === 'ZoneInfo') {
pg.user.timeZone = tzComponents[2];
} else {
errlog( 'Unexpected timezone information: ' + tz );
}
}
}
return pg.user.timeZone
}
 
/*
* Should we use an offset or can we use proper timezones
*/
function useTimeOffset() {
if ( typeof Intl.DateTimeFormat.prototype.formatToParts === 'undefined' ) {
// IE 11
return true;
}
var tz = mw.user.options.get('timecorrection');
if(tz && tz.indexOf('ZoneInfo|') === -1 ) {
// System| Default system time, default for users who didn't configure timezone
// Offset| Manual defined offset by user
return true;
}
return false;
}
 
/*
* Array of locales for the purpose of javascript locale based formatting
* Filters down to those supported by the browser. Empty [] === System's default locale
*/
function getLocales() {
if ( !pg.user.locales ) {
var userLanguage = document.querySelector('html').getAttribute('lang'); // make sure we have HTML locale
if ( getValueOf( 'popupLocale' ) ) {
userLanguage = getValueOf( 'popupLocale' );
}
else if ( userLanguage === 'en' ) {
// en.wp tends to treat this as international english / unspecified
// but we have more specific settings in user options
if ( getMWDateFormat() === 'mdy' ) {
userLanguage = 'en-US';
} else {
userLanguage = 'en-GB';
}
}
pg.user.locales = Intl.DateTimeFormat.supportedLocalesOf( [userLanguage, navigator.language] );
}
return pg.user.locales;
}
 
/*
* Retrieve configured MW date format for this user
* These can be
* default
* dmy: time, dmy
* mdy: time, mdy
* ymd: time, ymd
* dmyt: dmy, time
* dmyts: dmy, time + seconds
* ISO 8601: YYYY-MM-DDThh:mm:ss (local time)
*
* This isn't too useful for us, as JS doesn't have formatters to match these private specifiers
*/
function getMWDateFormat() {
return mw.user.options.get( 'date' );
}
 
* @param {boolean} reallyContribs - true only if we're displaying user contributions
*/
function editPreviewTable(article, h, reallyContribs, timeOffset) {
var html=['<table>'];
var day=null;
}
var minor = h[i].minor ? '<b>m </b>' : '';
var editDate = adjustDate(getDateFromTimestampnew Date(h[i].timestamp), timeOffset);
var thisDay = dayFormatformattedDate(editDate);
var thisTime = timeFormatformattedTime(editDate);
if (thisDay == day) {
thisDay = '';
html.push('</table>');
return html.join('');
}
 
function getDateFromTimestamp(t) {
var s=t.split(/[^0-9]/);
switch(s.length) {
case 0: return null;
case 1: return new Date(s[0]);
case 2: return new Date(s[0], s[1]-1);
case 3: return new Date(s[0], s[1]-1, s[2]);
case 4: return new Date(s[0], s[1]-1, s[2], s[3]);
case 5: return new Date(s[0], s[1]-1, s[2], s[3], s[4]);
case 6: return new Date(s[0], s[1]-1, s[2], s[3], s[4], s[5]);
default: return new Date(s[0], s[1]-1, s[2], s[3], s[4], s[5], s[6]);
}
}
 
}
 
/*
function dayFormat(editDate, utc) {
* This relies on the Date parser understanding en-US dates,
if (utc) { return map(zeroFill, [editDate.getUTCFullYear(), editDate.getUTCMonth()+1, editDate.getUTCDate()]).join('-'); }
* which is pretty safe assumption, but not perfect.
return map(zeroFill, [editDate.getFullYear(), editDate.getMonth()+1, editDate.getDate()]).join('-');
*/
function convertTimeZone(date, timeZone) {
return new Date(date.toLocaleString("en-US", {timeZone: timeZone}));
}
 
function timeFormatformattedDateTime(editDate, utcdate) {
// fallback for IE11 and unknown timezones
if (utc) { return map(zeroFill, [editDate.getUTCHours(), editDate.getUTCMinutes(), editDate.getUTCSeconds()]).join(':'); }
if ( useTimeOffset() ) {
return map(zeroFill, [editDate.getHours(), editDate.getMinutes(), editDate.getSeconds()]).join(':');
return formattedDate( date ) + ' ' + formattedTime( date )
}
 
if ( getMWDateFormat() === 'ISO 8601' ) {
var d2 = convertTimeZone(date, getTimeZone());
return map(zeroFill, [d2.getFullYear(), d2.getMonth()+1, d2.getDate()]).join('-') + 'T' + map(zeroFill, [d2.getHours(), d2.getMinutes(), d2.getSeconds()]).join(':');
}
 
var options = getValueOf('popupDateTimeFormatterOptions');
options['timeZone'] = getTimeZone();
return date.toLocaleString( getLocales(), options );
}
 
function formattedDate(date) {
// fallback for IE11 and unknown timezones
if ( useTimeOffset() ) {
// we adjust the UTC time, so we print the adjusted UTC, but not really UTC values
var d2 = adjustDate(date, getTimeOffset());
return map(zeroFill, [d2.getUTCFullYear(), d2.getUTCMonth()+1, d2.getUTCDate()]).join('-');
}
 
if ( getMWDateFormat() === 'ISO 8601' ) {
var d2 = convertTimeZone(date, getTimeZone());
return map(zeroFill, [d2.getFullYear(), d2.getMonth()+1, d2.getDate()]).join('-');
}
 
var options = getValueOf('popupDateFormatterOptions');
options['timeZone'] = getTimeZone();
return date.toLocaleDateString( getLocales(), options );
}
 
function formattedTime(date) {
// fallback for IE11 and unknown timezones
if ( useTimeOffset() ) {
// we adjust the UTC time, so we print the adjusted UTC, but not really UTC values
var d2 = adjustDate(date, getTimeOffset());
return map(zeroFill, [d2.getUTCHours(), d2.getUTCMinutes(), d2.getUTCSeconds()]).join(':');
}
 
if ( getMWDateFormat() === 'ISO 8601' ) {
var d2 = convertTimeZone(date, getTimeZone());
return map(zeroFill, [d2.getHours(), d2.getMinutes(), d2.getSeconds()]).join(':');
}
 
var options = getValueOf('popupTimeFormatterOptions');
options['timeZone'] = getTimeZone();
return date.toLocaleTimeString( getLocales(), options );
}
 
// Get the proper groupnames for the technicalgroups
function fetchUserGroupNames( userinfoResponse ) {
var queryObj=getJsObj(userinfoResponse).query;
var user = anyChild( queryObj.users );
var messages = [];
if( user.groups ) {
user.groups.forEach( function ( groupName ) {
if( ["*", "user", "autoconfirmed", "extendedconfirmed"].indexOf( groupName ) === -1 ) {
messages.push( 'group-' + groupName + '-member' );
}
} );
}
if( queryObj.globaluserinfo && queryObj.globaluserinfo.groups ) {
queryObj.globaluserinfo.groups.forEach( function ( groupName ) {
messages.push( 'group-' + groupName + '-member' );
} );
}
return getMwApi().loadMessagesIfMissing( messages );
}
 
page.revisions[0].contentmodel === 'wikitext'
) ? page.revisions[0].content : null;
if( typeof content === 'string' && pg && pg.current && pg.current.link && pg.current.link.navpopup )
{
/* Not entirely safe, but the best we can do */
queryobj=getJsObj(download.data).query;
} catch(someError) { return 'Userinfo preview failed :('; }
 
var user=anyChild(queryobj.users);
if (user) {
if( getValueOf('popupShowGender') && user.gender ) {
switch( user.gender ) {
case "male": ret.push( popupString( "\u2642he/him" ) + ' · ' ); break;
case "female": ret.push( popupString( "\u2640she/her" ) + ' · ' ); break;
}
}
if( user.groups ) {
user.groups.forEach( function ( groupName ) {
for( var j=0; j < user.groups.length; j++) {
if( ["*", "user", "autoconfirmed", "extendedconfirmed"].indexOf( groupName ) === -1 ) {
var currentGroup = user.groups[j];
ret.push( pg.escapeQuotesHTML(
if( ["*", "user", "autoconfirmed", "extendedconfirmed"].indexOf( currentGroup ) === -1 ) {
mw.message( 'group-' + groupName + '-member', user.gender ).text()
ret.push( pg.escapeQuotesHTML(user.groups[j]) );
) );
}
} );
}
if( globaluserinfo && globaluserinfo.groups ) {
globaluserinfo.groups.forEach( function ( groupName ) {
for( var k=0; k < globaluserinfo.groups.length; k++) {
ret.push( '<i>'+pg.escapeQuotesHTML(globaluserinfo.groups[k])+'</i>' );
mw.message( 'group-' + groupName + '-member', user.gender ).text()
}
)+'</i>' );
} );
}
if( user.registration )
ret.push( pg.escapeQuotesHTML((user.editcount?user.editcount:'0') + popupString(' edits since: ') + (user.registration?dayFormatformattedDate(getDateFromTimestampnew Date(user.registration)):'')) );
}
 
if (queryobj.usercontribs && queryobj.usercontribs.length) {
ret.push( popupString('last edit on ') + dayFormatformattedDate(getDateFromTimestampnew Date(queryobj.usercontribs[0].timestamp)) );
}
ret.push( popupString( 'IP user') ); //we only request list=blocks for IPs
for (var l=0; l<queryobj.blocks.length; l++) {
console.log(queryobj);
var rbstr = queryobj.blocks[l].rangestart === queryobj.blocks[l].rangeend ? 'BLOCK' : 'RANGEBLOCK';
rbstr = (!Array.isArray(queryobj.blocks[l].restrictions) ? 'Has ' + rbstr.toLowerCase() + 's' : rbstr + 'ED');
ret.push('<b>' + popupString(rbstr) + '</b>' );
}
}
 
// if any element of ret ends with ' · ', merge it with the next element to avoid
// the .join(', ') call inserting a comma after it
for (var m=0; m<ret.length - 1; m++) {
if ((ret[m].length > 3) && (ret[m].substring(ret[m].length - 3) === ' · ')) {
ret[m] = ret[m] + ret[m+1];
ret.splice(m+1, 1); // delete element at index m+1
m--;
}
}
ret = '<hr />' + ret.join( ', ' );
}
 
var ret=editPreviewTable(article, edits, reallyContribs, getTimeOffset());
return ret;
} catch (someError) {
'bg': [ r, 'пренасочване', 'виж' ],
'bs': [ r, 'Preusmjeri', 'preusmjeri', 'PREUSMJERI' ],
'bn': [ R, 'পুনর্নির্দেশ'],
'cs': [ R, 'PŘESMĚRUJ' ],
'cy': [ r, 'ail-cyfeirio' ],
'mk': [ r, 'пренасочување', 'види' ],
'nds': [ r, 'wiederleiden' ],
'nds-nl': [ R, 'DEURVERWIEZING', 'DUURVERWIEZING' ],
'nl': [ R, 'DOORVERWIJZING' ],
'nn': [ r, 'omdiriger' ],
function setInterwiki() {
if (pg.wiki.wikimedia) {
// From https://vi.wiktionary.org/w/api.php?action=sitematrix&format=json&smtype=language&smlangprop=code&formatversion=2
// From [[Đặc biệt:Ma trận trang]]
pg.wiki.interwiki='aa|ab|ace|ady|af|ak|als|alt|am|ami|an|ang|ar|arc|ary|arz|as|ast|atj|av|avk|awa|ay|az|azb|ba|ban|bar|bat-smg|bcl|be|be-tarask|be-x-old|bg|bh|bi|bjn|bm|bn|bo|bpy|br|bs|bug|bxr|ca|cbk-zam|cdo|ce|ceb|ch|cho|chr|chy|ckb|co|cr|crh|cs|csb|cu|cv|cy|da|dag|de|din|diq|dsb|dty|dv|dz|ee|el|eml|en|eo|es|et|eu|ext|fa|ff|fi|fiu-vro|fj|fo|fr|frp|frr|fur|fy|ga|gag|gan|gcr|gd|gl|glk|gn|gom|gor|got|gu|gv|ha|hak|haw|he|hi|hif|ho|hr|hsb|ht|hu|hy|hyw|hz|ia|id|ie|ig|ii|ik|ilo|inh|io|is|it|iu|ja|jam|jbo|jv|ka|kaa|kab|kbd|kbp|kg|ki|kj|kk|kl|km|kn|ko|koi|kr|krc|ks|ksh|ku|kv|kw|ky|la|lad|lb|lbe|lez|lfn|lg|li|lij|lld|lmo|ln|lo|lrc|lt|ltg|lv|mad|mai|map-bms|mdf|mg|mh|mhr|mi|min|mk|ml|mn|mni|mnw|mo|mr|mrj|ms|mt|mus|mwl|my|myv|mzn|na|nah|nap|nds|nds-nl|ne|new|ng|nia|nl|nn|no|nov|nqo|nrm|nso|nv|ny|oc|olo|om|or|os|pa|pag|pam|pap|pcd|pdc|pfl|pi|pih|pl|pms|pnb|pnt|ps|pt|pwn|qu|rm|rmy|rn|ro|roa-rup|roa-tara|ru|rue|rw|sa|sah|sat|sc|scn|sco|sd|se|sg|sh|shi|shn|shy|si|simple|sk|skr|sl|sm|smn|sn|so|sq|sr|srn|ss|st|stq|su|sv|sw|szl|szy|ta|tay|tcy|te|tet|tg|th|ti|tk|tl|tn|to|tpi|tr|trv|ts|tt|tum|tw|ty|tyv|udm|ug|uk|ur|uz|ve|vec|vep|vi|vls|vo|wa|war|wo|wuu|xal|xh|xmf|yi|yo|yue|za|zea|zh|zh-classical|zh-min-nan|zh-yue|zu';
pg.re.interwiki=RegExp('^'+pg.wiki.interwiki+':');
} else {
Mousetracker.prototype.disable = function () {
if (!this.active) { return; }
if ($.isFunction(typeof this.savedHandler) === "function") {
document.onmousemove=this.savedHandler;
} else { delete document.onmousemove; }
pg.wiki.hostname = location.hostname; // use in preference to location.hostname for flexibility (?)
}
pg.wiki.wikimedia=RegExp('(wiki([pm]edia|source|books|news|quote|versity|species|voyage|data)|metawiki|wiktionary|mediawiki)[.]org').test(pg.wiki.hostname);
pg.wiki.wikia=RegExp('[.]wikia[.]com$', 'i').test(pg.wiki.hostname);
pg.wiki.isLocal=RegExp('^localhost').test(pg.wiki.hostname);
 
function setUserInfo() {
var api = new mw.Api( {
ajax: {
headers: { 'Api-User-Agent': pg.misc.userAgent }
}
} );
var params = {
action: 'query',
pg.user.canReview = false;
if (getValueOf('popupReview')) {
apigetMwApi().get(params).done(function(data){
var rights = data.query.users[0].rights;
pg.user.canReview = rights.indexOf('review') !== -1; // TODO: Should it be a getValueOf('ReviewRight') ?
});
}
}
 
function fetchSpecialPageNames() {
var params = {
action: 'query',
meta: 'siteinfo',
siprop: 'specialpagealiases',
formatversion: 2,
// cache for an hour
uselang: 'content',
maxage: 3600
};
return getMwApi().get( params ).then( function ( data ) {
pg.wiki.specialpagealiases = data.query.specialpagealiases;
} );
}
 
var reEnd='(' + preTitles + ')([^&?#]*)[^#]*(?:#(.+))?';
pg.re.main = RegExp(reStart + literalizeRegex(pg.wiki.sitebase) + reEnd);
}
 
function buildSpecialPageGroup( specialPageObj ) {
var variants = [];
variants.push( mw.util.escapeRegExp(specialPageObj['realname']));
variants.push( mw.util.escapeRegExp(encodeURI(specialPageObj['realname'])));
specialPageObj.aliases.forEach( function( alias ) {
variants.push( mw.util.escapeRegExp(alias) );
variants.push( mw.util.escapeRegExp(encodeURI(alias)) );
} );
return variants.join('|');
}
 
function setRegexps() {
// TODO: We shoud use an api call to get the aliases for special pages, now it does not work for non-English wikipedias:
// E.g., https://ru.wikipedia.org/w/api.php?action=query&meta=siteinfo&siprop=specialpagealiases&formatversion=2
setMainRegex();
var sp=nsRe(pg.nsSpecialId);
pg.re.urlNoPopup=RegExp('((title=|/)' + sp + '(?:%3A|:)|section=[0-9]|^#$)') ;
 
pg.re.contribs =RegExp('(title=|/)' + sp + '(?:%3A|:)Contributions' + '(&target=|/|/' + nsRe(pg.nsUserId)+':)(.*)') ;
pg.wiki.specialpagealiases.forEach( function( specialpage ) {
pg.re.email =RegExp('(title=|/)' + sp + '(?:%3A|:)EmailUser' + '(&target=|/|/(?:' + nsRe(pg.nsUserId)+':)?)(.*)') ;
if( specialpage.realname === 'Contributions' ) {
pg.re.backlinks =RegExp('(title=|/)' + sp + '(?:%3A|:)WhatLinksHere' + '(&target=|/)([^&]*)');
pg.re.specialdiffcontribs = RegExp('(title=|/)' + sp + '(?:%3A|:)Diff/([^?#]*)');
'(?:%3A|:)(?:' + buildSpecialPageGroup(specialpage) + ')' +
'(&target=|/|/' + nsRe(pg.nsUserId)+':)(.*)', 'i') ;
} else if ( specialpage.realname === 'Diff' ) {
pg.re.specialdiff = RegExp('/' + sp +
'(?:%3A|:)(?:' + buildSpecialPageGroup(specialpage) + ')' +
'/([^?#]*)', 'i' );
} else if ( specialpage.realname === 'Emailuser' ) {
pg.re.email = RegExp( '(title=|/)' + sp +
'(?:%3A|:)(?:' + buildSpecialPageGroup(specialpage) +
')' + '(&target=|/|/(?:' + nsRe(pg.nsUserId)+':)?)(.*)', 'i') ;
} else if ( specialpage.realname === 'Whatlinkshere' ) {
pg.re.backlinks = RegExp( '(title=|/)' + sp +
'(?:%3A|:)(?:' + buildSpecialPageGroup(specialpage) +
')' + '(&target=|/)([^&]*)', 'i');
}
} );
 
//<NOLITE>
{from: '%26', to: '&' } // no ,
];
}
 
function getMwApi() {
pg.misc.userAgent = 'Navigation popups/1.0 (' + mw.config.get( 'wgServerName' ) +')';
if ( !pg.api.client ) {
pg.api.userAgent = 'Navigation popups/1.0 (' + mw.config.get( 'wgServerName' ) +')';
pg.api.client = new mw.Api( {
ajax: {
headers: {
'Api-User-Agent': pg.api.userAgent
}
}
} );
}
return pg.api.client;
}
 
function setupPopups( callback ) {
if ( setupPopups.completed ) {
if ( $.isFunction(typeof callback )=== "function" ) {
callback();
}
return;
}
// These dependencies areshould alsoalse be enforced from the gadget,
// but not everyone loads this as a gadget, so double check
mw.loader.using( ['mediawiki.util', 'mediawiki.user', 'user.options'] ).then( function() {
'mediawiki.util',
'mediawiki.api',
'mediawiki.user',
'user.options',
'mediawiki.jqueryMsg'
] )
.then( fetchSpecialPageNames )
.then( function() {
// NB translatable strings should be set up first (strings.js)
// basics
 
setupPopups.completed = true;
if ( $.isFunction(typeof callback )=== "function" ) {
callback();
}
case 'userSpace': this.print=specialLink; this.specialpage='PrefixIndex'; this.sep='&namespace=2&prefix='; break;
case 'search': this.print=specialLink; this.specialpage='Search'; this.sep='&fulltext=Search&search='; break;
case 'thank': this.print=specialLink; this.specialpage='Thanks'; this.sep='/'; this.article.value = (this.diff !== 'prev' ? this.diff : this.oldid); break;
case 'unwatch': case 'watch':
this.print=magicWatchLink; this.action=this.id+'&autowatchlist=1&autoimpl=' + popupString('autoedit_version') + '&actoken='+autoClickToken(); break;
navpop.diffData={ oldRev: {}, newRev: {} };
mw.loader.using( 'mediawiki.api' ).then( function() {
var api = new mw.ApigetMwApi( {);
ajax: {
headers: { 'Api-User-Agent': pg.misc.userAgent }
}
} );
var params = {
action: 'compare',
}
 
// Put a "mark patrolled" link to an element target
pendingNavpopTask(navpop);
// TODO: Allow patrol a revision, as well as a diff
getWiki(article, doneDiffOld, oldRev, navpop);
function addReviewLink (navpop, target) {
 
if (! pg.user.canReview) return;
var tz = Cookie.read('popTz');
// If 'newRev' is older than 'oldRev' than it could be confusing, so we do not show the review link.
if ( true && getValueOf('popupAdjustDiffDates') && tz===null) {
if (navpop.diffData.newRev.revid <= navpop.diffData.oldRev.revid) return;
pendingNavpopTask(navpop);
var params = {
getPageWithCaching(pg.wiki.apiwikibase + '?format=json&action=query&meta=userinfo&uiprop=options',
action: 'query',
function(d) {
prop: 'info|flagged',
completedNavpopTask(navpop);
revids: navpop.diffData.oldRev.revid,
setTimecorrectionCookie(d);
formatversion : 2
if (diffDownloadsComplete(navpop)) { insertDiff(navpop); }
};
}, navpop);
getMwApi().get(params).then(function(data){
var stable_revid = data.query.pages[0].flagged && data.query.pages[0].flagged.stable_revid || 0;
// The diff can be reviewed if the old version is the last reviewed version
// TODO: Other possible conditions that we may want to implement instead of this one:
// * old version is patrolled and the new version is not patrolled
// * old version is patrolled and the new version is more recent than the last reviewed version
if (stable_revid == navpop.diffData.oldRev.revid) {
var a = document.createElement('a');
a.innerHTML = popupString('mark patrolled');
a.title=popupString('markpatrolledHint');
a.onclick = function() {
var params = {
action: 'review',
revid: navpop.diffData.newRev.revid,
comment: tprintf('defaultpopupReviewedSummary', [navpop.diffData.oldRev.revid, navpop.diffData.newRev.revid])
};
api.postWithToken('csrf',params).done(function(){
a.style.display = "none";
// TODO: Update current page and other already constructed popups
} ).fail(function(){
alert(popupString('Could not marked this edit as patrolled'));
});
};
setPopupHTML(a, target, navpop.idNumber,null,true);
}
});
var txt='';
var lastModifiedDate = new Date(revision.timestamp);
 
var datePrint=getValueOf('popupDiffDatePrinter');
iftxt = formattedDateTime(typeof lastModifiedDate[datePrint] == 'function') {;
var d2 = adjustDate(lastModifiedDate, getTimeOffset());
txt = dayFormat(d2, true) + ' ' + timeFormat(d2, true);
} else {
txt = tprintf('Invalid %s %s', ['popupDiffDatePrinter', datePrint]);
}
var revlink = generalLink({url: mw.config.get('wgScript') + '?oldid='+revision.revid,
text: label, title: label});
if ( action === 'unwatch' ) reqData.unwatch = true;
 
var api = new mw.Api( {
ajax: {
headers: { 'Api-User-Agent': pg.misc.userAgent }
}
} );
// Load the Addedwatchtext or Removedwatchtext message and show it
var mwTitle = mw.Title.newFromText( title );
}
$.when(
apigetMwApi().postWithToken( 'watch', reqData ),
mw.loader.using( [ 'mediawiki.api', 'mediawiki.jqueryMsg' ] ).then( function () {
return api.loadMessagesIfMissing( [ messageName ] );
newOption('popupDraggable', true);
newOption('popupReview', false);
newOption('popupLocale', false);
newOption('popupDateTimeFormatterOptions', {
year: 'numeric',
month: 'long',
day: 'numeric',
hour12: false,
hour: '2-digit',
minute: '2-digit',
second: '2-digit'
} );
newOption('popupDateFormatterOptions', {
year: 'numeric',
month: 'long',
day: 'numeric'
} );
newOption('popupTimeFormatterOptions', {
hour12: false,
hour: '2-digit',
minute: '2-digit',
second: '2-digit'
} );
 
//<NOLITE>
newOption('popupDiffContextCharacters', 40);
newOption('popupDiffDates', true);
newOption('popupDiffDatePrinter', 'toLocaleString'); // no longer in use
 
// edit summaries. God, these are ugly.
newOption('popupContribsPreviewLimit',25);
newOption('popupRevDelUrl', '//en.wikipedia.org/wiki/Wikipedia:Revision_deletion');
newOption('popupShowGender', truefalse);
//</NOLITE>
 
'space': 'không gian', // short form for userSpace link
'PrefixIndexHint': 'Xem các trang trong không gian thành viên %s',
'count': 'đếm', ///// contributions, log
'edit counter': 'đếm sửa đổi',
'editCounterLinkHint': 'Đếm đóng góp của %s',
'user log': 'nhật trình thành viên',
'userLogHint': 'Xem nhật trình của %s',
'arin': 'tra ARIN', ///// ARIN lookup, block user or IP
'Look up %s in ARIN whois database': 'Tra %s trong dữ liệu whois ARIN',
'unblockShort': 'bỏ',
'BLOCKED': 'CẤM',
'Has blocks': 'Bị cấm sửa đổi',
' edits since: ': ' sửa đổi từ: ',
'last edit on ': 'sửa đổi cuối vào ',
'he/him': 'anh ấy',
'she/her': 'cô ấy',
/////////////////////////////////////
// Autoediting