User:Richwales/markusers.js

function Richwales_markUsers { var users = [] var userLinks = [] var userBlocked = {} var userToolTips = {} var userSysops = {} var userSysopsPlus = {} var userArbs = {} var userUnconfirmed = {} var userEdits = {} var userStyle = {}

if (!window.mbTempStyle) mbTempStyle = 'opacity: 0.7; text-decoration: line-through' if (!window.mbIndefStyle) mbIndefStyle = 'opacity: 0.4; font-style: italic; text-decoration: line-through' if (!window.mbTipBoxStyle) mbTipBoxStyle = 'font-size:smaller; background:#FFFFF0; ' + 'border:1px solid #FEA; padding:0 0.3em; color:#AAA' if (!window.mbTooltip) { i18n = { //    'dsb': '(blokěrowany wót $2 za traśe wót $1: $3)', 'en': '(blocked by $2 with an expiry time of $1: $3)', //     'eo': '(forbarita de $2 por daŭro de $1: $3)', //     'hsb': '(zablokowany wot $2 za traće wot $1: $3)', //     'ja': '($2によるブロック. 期限:$1 理由:$3)', //     'pt': '(bloqueado por $2 até $1: $3)', //     'ru': '(блокировка $2 на срок $1: $3)', //     'sv': '(har blockerats av $2 till $1: $3)', //     'uk': '(блокування $2 на термін $1: $3)' }   mbTooltip = /* i18n[mw.config.get('wgUserLanguage')] || */ i18n.en  } appendCSS('.user-blocked-temp   {' + mbTempStyle   + '}\n' +            '.user-blocked-indef   {' + mbIndefStyle  + '}\n' +            '.user-blocked-tipbox  {' + mbTipBoxStyle + '}\n' +            '.user-not-blocked      { }\n' +            '.user-is-unconfirmed  { background-color: #ddd }\n' +            '.user-is-new          { background-color: #fdd }\n' +            '.user-is-sysop        { background-color: #cff }\n' +            '.user-is-sysop-plus   { background-color: #cfc }\n' +            '.user-may-be-arb      { background-color: #fddd77 }\n' +            '.user-is-ordinary  { }\n');

function apiRequest(params, callback) { var aj = sajax_init_object aj.onreadystatechange = function { if (aj.readyState != 4 || aj.status != 200) return callback(eval('(' + aj.responseText + ')')) }   aj.open('GET', mw.config.get('wgServer') + mw.config.get('wgScriptPath') + '/api.php?format=json&' + params, false) aj.send('') }

function target(link) { var hr = link.href; if (!hr || hr == '') hr = link.baseURI; if (hr.match(/&action=edit/) && !hr.match(/&action=edit&redlink=1/)) return ''; hr = hr.replace(/^.*\/(wiki\/|w\/index\.php\?title=)/, ''); hr = hr.replace(/[?&].*$/, ''); hr = hr.replace(/_/g, ' '); hr = decodeURIComponent(hr); if (hr.match(/#/)) hr = ''; if (hr.match(/\//) && !hr.match(/Special:Contributions\//)) hr = ''; return hr; }

function checkLinks(namespaces) { var content = document.getElementById('content') || document.getElementById('mw_content') || document.body var links = content.getElementsByTagName('a') var ns = namespaces.query.namespaces var ca   for (var i = 0; i < namespaces.query.specialpagealiases.length; i++) { if (namespaces.query.specialpagealiases[i].realname == 'Contributions') ca = namespaces.query.specialpagealiases[i].aliases }   if (!namespaces.fromcookie) { document.cookie = 'mbNamespaces=' + escape([ns[-1]['*'], ns[2]['*'], ns[3]['*'], ca.join('|')].join(':')) + '; expires=' + (new Date((new Date).getTime + Math.exp(20))).toGMTString }   //   User:   User_talk:   Special:Contributions/   in canonical form, as they are in hrefs var isUser = new RegExp('^((' + ns[2]['*'] + '|' + ns[3]['*'] + '):|' + ns[-1]['*'] + ':(' + ca.join('|').replace(/_/g, ' ') + ')\\/)([^\\/#]*)$') var j = 0 for (i = 0; i < links.length; i++) { var li = links[i] var tli = target(li) if (!tli || tli == '') continue if (tli.match(isUser)) { users[j] = tli.replace(isUser, '$4') userLinks[j++] = li       li.style.opacity = window.mbLoadingOpacity || 0.65 // a way to mark that the data is loading }   }    if (j == 0) return // nobody to mark // performing sort and duplicate cleanup, otherwise we risk of some users being marked twice var usersTemp = users.join('|').split('|') usersTemp.sort var u = [] u[0] = usersTemp[0] if (usersTemp[1]) { j = 1 for (i = 1; i < usersTemp.length; i++) { if (usersTemp[i] != usersTemp[i-1]) u[j++] = usersTemp[i] }   }    usersTemp = null

for (i = 0; i < links.length; i++) links[i].style.opacity = '';

// do API requests to find blocked and special users, in batches of no more than about 1000 characters each var query = '' for (i = 0; i < u.length; i++) { query += (query ? '|' : '') + encodeURIComponent(u[i]) if (query.length > 1000) { apiRequest('action=query&list=users&usprop=groups|editcount&ususers=' + query, findSysops) apiRequest('action=query&list=blocks&bkprop=user|expiry|by|reason&bkusers=' + query, findBlocked) query = '' }   }

// take care of API request for any final, leftover batch of users if (query) { apiRequest('action=query&list=users&usprop=groups|editcount&ususers=' + query, findSysops) apiRequest('action=query&list=blocks&bkprop=user|expiry|by|reason&bkusers=' + query, findBlocked) }

// mark everyone according to results of API requests doUserMarking } function findBlocked(ulist) { if (!ulist || !ulist.query) return; var ul = ulist.query.blocks; if (!ul) return; for (var i = 0; i < ul.length; i++) { var u = ul[i] if (u.expiry) { var name = u.user userToolTips[name] = ' ' + mbTooltip.replace('$1', u.expiry.replace(/(.*)T(.*)Z/, '$1 $2 UTC')) .replace('$2', u.by) .replace('$3', u.reason) userBlocked[name] = (u.expiry.substr(0,2) == 'in') ? 'indef' : 'temp' // alert ('findBlocked: user ' + name + ': blocked (' + userBlocked[name] + ')') }   }  }  function findSysops(ulist) { if (!ulist || !ulist.query) return; var ul = ulist.query.users; if (!ul) return; var name; for (var i = 0; i < ul.length; i++) { name = ul[i].name; var usergroups = []; var gl = ul[i].groups; if (gl) { for (var gi = 0; gi < gl.length; gi++) usergroups[gl[gi]] = 1; if (usergroups['sysop']) userSysops[name] = 1; if (usergroups['checkuser'] && usergroups['oversight']) userArbs[name] = 1; if (usergroups['checkuser'] || usergroups['oversight'] ||            usergroups['steward'] || usergroups['bureaucrat']) userSysopsPlus[name] = 1; if (! usergroups['autoconfirmed'] && ! usergroups['confirmed']) userUnconfirmed[name] = 1; }     userEdits[name] = ul[i].editcount;

//     var alertString = 'findSysops: user ' + name + ': ' + userEdits[name] + ' edits' //     if (userSysops[name]) alertString += '; sysop' //     if (userArbs[name]) alertString += '; arb?' //     if (userSysopsPlus[name]) alertString += '; func' //     if (userUnconfirmed[name]) alertString += '; unconfirmed' //     alert (alertString) } }

function doUserMarking { var span for (var i = 0; i < users.length; i++) { var name = users[i]

if (userStyle[name]) { userLinks[i].className += userStyle[name] continue }

var us = ''

if (userBlocked[name]) { us += ' user-blocked-' + userBlocked[name] if (window.mbTipBox) { span = document.createElement('span') span.title = name + userToolTips[name] span.className = 'user-blocked-tipbox' span.innerHTML = '#' userLinks[i].parentNode.insertBefore(span, ul) }       else userLinks[i].title += tips[name] }     else us += ' user-not-blocked'

if (userArbs[name]) us += ' user-may-be-arb' else if (userSysopsPlus[name]) us += ' user-is-sysop-plus' else if (userSysops[name]) us += ' user-is-sysop' else if (userUnconfirmed[name]) us += ' user-is-unconfirmed' else if (userEdits[name] < 100) us += ' user-is-new' else us += ' user-is-ordinary'

// alert ('doUserMarking: user ' + name + ': ' + us); userLinks[i].className += us     userStyle[name] = us    } }

if (ca = document.getElementById('ca-showblocks')) ca.parentNode.removeChild(ca) var cookie = document.cookie.match(/mbNamespaces=(.*?);/) if (cookie) { cookie = unescape(cookie[1]).split(':') checkLinks({     'query': {        'namespaces': { '-1': { '*': cookie[0] }, '2': { '*': cookie[1] }, '3': { '*': cookie[2] } },        'specialpagealiases': [{'realname': 'Contributions', 'aliases': cookie[3].split('|')}]      },      'fromcookie': 1    }) } else { apiRequest('action=query&meta=siteinfo&siprop=namespaces|specialpagealiases', checkLinks) } } // alert ('hooking Richwales_markUsers') $(Richwales_markUsers);