User:Alex Smotrov/logpage.js

var logPage = new function{

var imcomm = 'http://upload.wikimedia.org/wikipedia/commons/' var imuser = '/skins-1.5/monobook/user.gif'

var m = {

//Mediawiki messages: considered default for IP blocks mwAnonOnly: 'anon. only', //considered default for IP blocks mwNoReg: 'account creation blocked', //considered default //Mediawiki messages: considered unusual for user blocks mwNoAuto: 'autoblock disabled', mwNoEmail: 'e-mail blocked', //output messages NotAnonOnly: ' ' + '' + ' ', YesReg: '  ', NoAuto: ' autoblock ', NoEmail: '', NewUserLog: 'account creation log', ShowTable: '[show table]', ShowList: '[show list]' }

var type, user, ul, lis, logTable, logLink, tbody, isTable = false var thisYear = (new Date).getFullYear

this.onLoad = function{

//get page structure var content = document.getElementById('content') || document.body ul = content.getElementsByTagName('ul')[0] if (!ul) return //log is empty //create and attach switching link logLink = document.createElement('a') logLink.href = 'javascript:logPage.switchTable' logLink.style.marginLeft = '10px'; logLink.style.fontSize = '85%' ul.parentNode.insertBefore(logLink, ul) //create table lis = ul.getElementsByTagName('li') if (window.logMaxRows && lis.length > logMaxRows) isTable = true //surpress creation if too many rows logPage.switchTable addEvent (logTable, 'mouseup', click) }

this.switchTable = function{ if (isTable){ ul.style.display = 'block' if (logTable) logTable.style.display = 'none' logLink.innerHTML = m.ShowTable }else{ if (!logTable) createTable ul.style.display = 'none' logTable.style.display = 'block' logLink.innerHTML = m.ShowList } isTable = !isTable }

function createTable{ if (!window.logDateIn) logDateIn = /(\d\d:\d\d), (\d\d?) (\S\S\S)\S* (\d\d\d\d)/ if (!window.logDateOut) logDateOut = '$1 $2 $3 $4' if (!window.logBlDivider) logBlDivider = ' ' logPageCSS = '.logcomment div {overflow:auto} .logtime {width:15px}' + (window.logPageCSS?logPageCSS:'') addCSS(logPageCSS) if (type = document.URL.match(/&type=([^&]+)/)) type = type[1] //"move", "block", etc. or just empty if (user = document.URL.match(/&user=([^&]+)/)) user = document.getElementById('user').value var columns = 5 tbody = ' ' +'  ' +' ' +'  ' if (user){ //no need for user column columns-- tbody = ': ' +user.replace(/\+/,' ')+' '+tbody }else{ tbody += '  ' } tbody += '  ' //parse entries for (var i=0; i' + lis[i].innerHTML + ' ' jsMsg('logPage: ' + e.lineNumber + ': ' + e.name + ': ' + e.message + ' ; please report') } } //insert table logTable = document.createElement('div') logTable.innerHTML = ' ' ul.parentNode.insertBefore(logTable, ul) ts_makeSortable(document.getElementById('logTable')) }

function parseRow(row){ //modifies tbody var

var icon=, when, what, who, comment=, ma, word, lastLink='' var r1, r2, opt = , extra=, until=, trstyle= //extract date, user and userlinks (talk | cotrib | block) ma = row.match(/([^<]+)() (\(\)) /i) //date, user and user links when = ma[1] who = ma[2] row = row.substring(ma[0].length) //get the rest if (!window.logNoUserLinks) //add talk/contib links who += ' ' + ma[3].replace(/>(.)(.*?)$1<').replace(/> </,'> <') //shorten into (t | c | b)

//possibly get a link at the end if (ma = row.match(/\((<a[^<]+<\/a>)\) ?$/i)){ lastLink = ma[1] row = row.substring(0, row.length - ma[0].length) } //possibly get a comment at the end if (ma = row.match(/<span class="?comment"?>\((.*)\)<\/span> ?$/i)){ comment = ma[1] row = row.substring(0, row.length - ma[0].length) } var tooltip = row.replace(/<[^>]+>/g, '').replace(/"/g, '`') tooltip = tooltip.substring(0, tooltip.length-2) //get rid of last char, visible in IE // or .replace(/<a[^>]+>/g, '«').replace(/<\/a>/g, '»')

//get the «action» word //ma = row.match(/^[a-zA-Z]+/) //everything before link or quotes ma = row.match(/^[^"<«#]+/) //" everything before link or quotes if (ma) word = ma[0].replace(/\s+$/, '') //trim spaces at the end

what = row //just in case and for default in switch

//workaround: some weird characters at the end of this string if (row.length < 20) word = 'New user account'

switch (word){

case 'marked': what = row.match(/<a.+<\/a>/i)[0] putIcon('thumb/7/73/U2713.svg/10px-U2713.svg.png') break

case 'deleted': what = row.match(/<a[^<]+<\/a>/i)[0] putIcon('thumb/0/0b/Cancel.png/10px-Cancel.png') break

case 'restored': what = row.match(/<a[^<]+<\/a>/i)[0] putIcon('thumb/a/a7/Add.png/10px-Add.png') if (type == 'delete') trstyle = ' style="background-color:#EEFFEE"' break

case 'uploaded a new version of': extra = ' (version) '

case 'uploaded': what = getShortLink + extra putIcon('thumb/c/cc/Icons-mini-image.gif/15px-Icons-mini-image.gif') break

case 'New user account': putIcon(imuser) what = who who = '' break

case 'created new account': case 'created account for': putIcon(imuser) ma = row.match(/(<a.+?>) (.+)/i) what = ma[1] + ma[2].replace(/>(.)(.*?)</g, '>$1<') if (type == 'newusers') trstyle = ' style="background-color:#FFEEEE"' break

case 'changed protection level for': extra = ' ('+word.split(' ')[0] + ')'

case 'protected': what = getLink if (ma = comment.match(/\(\S+ (.+? \(UTC\))\)$/)){ //expiration date until = ' / ' + ma[1] + ' ' //period = getPeriod(when, until) comment = comment.replace(ma[0],'') }  if (ma=comment.match(/\[(edit=[a-z]+)?:?(move=[a-z]+)?\]/)){ //edit/move protection if (ma[0].indexOf('sysop') != -1) //is sysop protection at all putIcon('thumb/5/59/Padlock.svg/20px-Padlock.svg.png') //yellow else putIcon('thumb/f/fa/Padlock-silver-medium.svg/20px-Padlock-silver-medium.svg.png') //gray if (ma[1]) opt += (ma[1].indexOf('sysop')!=-1) ? 'sysop' : 'user' opt += ' :: ' if (ma[2]) opt += (ma[2].indexOf('sysop')!=-1) ? 'sysop' : 'user' }else if (ma=comment.match(/\[(create=[a-z]+)?\]/)){ //create protection if (ma[0].indexOf('sysop') != -1){ putIcon('thumb/4/4f/Padlock-purple.svg/20px-Padlock-purple.svg.png') opt = 'sysop' }else{ putIcon('thumb/7/70/Padlock-pink.svg/20px-Padlock-pink.svg.png') opt = 'user' }  }   comment = opt + extra + ' ' + until + ' ' + comment.replace(ma[0],'') break

case 'unprotected': what = getLink putIcon('thumb/5/5e/Padlock-lightolive.svg/15px-Padlock-lightolive.svg.png') if (type == 'protect') trstyle = ' style="background-color:#EEFFEE"' break

case 'blocked': putIcon('thumb/4/4f/Blocked_user.svg/18px-Blocked_user.svg.png') var length //get user and user links ma = row.match(/.*(<a.+?>) \((<a.+?>)\)(.+)$/i) if (!ma) { what = row.substring(word.length + 1); break } var blockedLink = ma[1] var talkContribLinks = ma[2] var blockedUser = blockedLink.match(/>(.+?)<\/a>/i)[1] row = ma[3] //get options var options = row.match(/\(.*\)/) options = options ? options[0] : '' //get period ma = row.match(/<span .*>(.+)<\/span>/i) if (ma) length = ma[1] else length = row.match (/\d+ \S+/)[0] //custom length without span, then it always starts with a number what = blockedLink+' ('+talkContribLinks.replace(/>(.)(.*?)</g, '>$1<')+') ' if (options.indexOf(m.mwNoReg) == -1) opt += m.YesReg //registration is allowed if (blockedUser.match(/^\d\d?\d?\.\d\d?\d?\.\d\d?\d?\.\d\d?\d?/)) {//IP block //what += ' style="background-color:white"' if (blockedUser.match(/\/\d\d?$/)) what = +what+ //range block if (options.indexOf(m.mwAnonOnly) == -1) opt += m.NotAnonOnly //registered users blocked too }else{ //user block // what += ' (<a title="' + m.NewUserLog + '" href="/w/index.php?title=Special:Log&type=newusers&user=' +encodeURIComponent(blockedUser) + '">?</a>) ' if (options.indexOf(m.mwNoAuto) != -1) opt += ' <span title="' + m.mwNoAuto + '">'+ m.NoAuto + ' ' if (options.indexOf(m.mwNoEmail) != -1) opt += ' <span title="' + m.mwNoEmail + '">' + m.NoEmail + ' ' } opt = '<small title="'+options+'">'+opt+' ' what += logBlDivider + length + ' ' + opt //' <span style="white-space:nowrap" title="' + options + '">'     + ' ' //reason = reason.replace(/ \(/,).replace(/\)<\/span>/,) //remove break

case 'unblocked': putIcon('thumb/2/23/Nuvola_apps_edu_languages.svg/20px-Nuvola_apps_edu_languages.svg.png') if (type == 'block') trstyle = ' style="background-color:#EEFFEE"' if (ma = row.match(/(<a.+?>) (\(<a.+?<\/a>\))/i)) //date, user and user links; otherwise it's "unlocked #7773" what = ma[1] + ' ' + ma[2].replace(/>(.)(.*?)</g, '>$1<') + ' ' //shorten into (t | c | b)  break

case 'moved': ma = row.match(/<a[^<]+<\/a>/ig) what = ma[0] + ' ' + ma[1] icon = '→' break // !!!  over redirect

//bot status

case 'granted bot status to': putIcon('thumb/a/a9/Wikiactividade_bot_bronze.png/16px-Wikiactividade_bot_bronze.png') what = 'bot: ' + getShortLink break

case 'removed bot status from': putIcon('thumb/1/16/Wikiactividade_bot_prata.png/16px-Wikiactividade_bot_prata.png') what = ' bot: ' + getShortLink + ' ' break

//user rights case 'Для участника':

case 'changed rights for': what = row.match(/<\/a> (.*) \u200E/i)[1] //devs, why use \u200E ? what = what.replace(/\([^\)]+\)/g,)  ma = what.match(/from (.*) to (.*)/)    if (!ma) {     what = getShortLink + ': ' + what     putIcon('thumb/b/b3/Kgpg_key3.png/15px-Kgpg_key3.png')     break   }   r1 = ma[1]; r2 = ma[2]    if (r1 == r2)     putIcon('thumb/8/80/Keyring.png/12px-Keyring.png')   else if (r1.length < r2.length){ //added flags     if ((r1 ==  && r2 == 'rollbacker') || (r1 + ', rollbacker' == r2))       putIcon('thumb/4/40/Wrench.svg/10px-Wrench.svg.png')      else       putIcon('thumb/5/53/Kgpg_key1.png/15px-Kgpg_key1.png') //visible vertical key   }else{ //removed flags     if ((r1 == 'rollbacker' && r2 == '') || (r1 == 'rollbacker, '+r2) || (r1 == r2+', rollbacker'))       putIcon('thumb/4/40/Wrench.svg/6px-Wrench.svg.png')     else       putIcon('thumb/8/82/Kgpg_key2.png/15px-Kgpg_key2.png') //grey and yellow keys   }   //   putIcon('thumb/4/43/Crystal_Clear_app_password.png/17px-Crystal_Clear_app_password.png') //clear keys what = ' ' + r1 + ' → ' + r2  what = getShortLink + ': ' + what break

case 'renamed': putIcon('thumb/e/ee/Crystal_Clear_app_kdmconfig.png/15px-Crystal_Clear_app_kdmconfig.png') what = row break

default: icon = '?' }

if (lastLink) icon = lastLink.replace(/>[^<]+</,'>'+icon+'<') //use icon as undo/protect/etc. link

tbody += '<tr' + trstyle + ' title="' + tooltip + '">' + '<td class=logtime title="'+when+'">' + when.replace(logDateIn, logDateOut).replace(thisYear,'') + ' ' +' '+icon+' ' +' '+what+' ' +(user ? '' : ' '+who+' ') +' '+comment + '  '

function putIcon(src){ if (src.substring(0,1) != '/') src = imcomm + src icon = '<img src=' + src + '>' } function getProtect(txt){ if (!txt) return ' ' else if (txt.indexOf('sysop') != -1) return 'sysop' else return 'anon' }

function getLink{ //get first link from the row return row.match(/<a[^<]+<\/a>/i)[0] } function shortLink(htm){ //returns a link without namespace in the text return htm.replace(/>.+?:(.+?)</, '>$1<') } function getShortLink{ //combination of above return row.match(/<a[^<]+<\/a>/i)[0].replace(/>.+?:(.+?)</, '>$1<') }

} //parseRow

function shortDate(when){ var ma = when.match(/(\d\d:\d\d), (\d\d?) (\S ...)/) var when2 = when if (ma) when2 = ma[1]+' '+ma[2].replace(/ /,' ') return '<td class=logtime title="'+when+'"> '+when2+' ' }

function addCSS(text){ //could use createStyleSheet for IE as well var s = document.createElement('style') s.setAttribute('type', 'text/css') if (s.styleSheet) s.styleSheet.cssText = text //IE else s.appendChild(document.createTextNode(text)) document.getElementsByTagName('head')[0].appendChild(s) return s }

function click(e){ //table onclick event: show additional links e = e || window.event var targ = e.srcElement || e.target if (targ.nodeName == 'DIV') targ = targ.parentNode if (targ.nodeName != 'TD' || !targ.className.match(/^(loguser|logcontent)/)) return var link = targ.getElementsByTagName('a')[0] if (!link) return if (/&redirect=no$/.test(link.href)) link = targ.getElementsByTagName('a')[1] //when move if (targ.className.indexOf('info')!=-1){ //remove info targ.className = targ.className.replace(' info', '') link.parentNode.removeChild(link.parentNode.lastChild) return } var page = link.title, user, htm = ' (' if (user=page.match(/:Contributions\/([\d\.]+)/)){ //IP address  user = user[1]    page = 'user:'+user }else if (user=page.match(/^(User|Участник):(.*)/))   user = user[2] if (user)    htm += showLink('Special:Logs?user=' + user, 'user', 'Logs by this user') + ' ' htm += showLink('Special:Logs?page=' + page, 'logs', 'Page logs') if (link.className != 'new' && !user)    htm += ' ' + showLink(page + '?action=history', 'hist', 'Page history') targ.className += ' info' link.parentNode.innerHTML += ' ' + htm + ') ' }

function showLink(page, name, tip){ return '<a href="' + mw.config.get('wgArticlePath').replace('$1',page) + '" title="' + tip + '">'+name+'</a>' }

}//obj

if (mw.config.get('wgCanonicalNamespace') == 'Special' && mw.config.get('wgCanonicalSpecialPageName') == 'Log') addOnloadHook (logPage.onLoad)