User:Alex Smotrov/logpage.js
Appearance
Code that you insert on this page could contain malicious content capable of compromising your account. If you import a script from another page with "importScript", "mw.loader.load", "iusc", or "lusc", take note that this causes you to dynamically load a remote script, which could be changed by others. Editors are responsible for all edits and actions they perform, including by scripts. User scripts are not centrally supported and may malfunction or become inoperable due to software changes. A guide to help you find broken scripts is available. If you are unsure whether code you are adding to this page is safe, you can ask at the appropriate village pump. This code will be executed when previewing this page. |
Documentation for this user script can be added at User:Alex Smotrov/logpage. |
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: ' <span title="Registered users also blocked">'
+ '<img src='+imcomm+'thumb/c/cc/Nuvola_apps_kdmconfig.png/15px-Nuvola_apps_kdmconfig.png>'
+ '</span>',
YesReg: '<span title="Registration is ok"><img src='+imuser+'></span>',
NoAuto: '<s>autoblock</s>',
NoEmail: '<img src='+imcomm+'thumb/3/3e/Email_delete.png/12px-Email_delete.png>',
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 = '<br>'
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 = '<tr>'
+'<th><img src=' + imcomm + 'thumb/a/af/Relogio07_15.svg/15px-Relogio07_15.svg.png></th>'
+'<th width=10px class=unsortable> </th>'
+'<th><img src=' + imcomm + '/3/3c/A_help_text.gif></th>'
if (user){ //no need for user column
columns--
tbody = '<caption style="text-align:left; padding-left:20%"><img src='+imuser+'>: '
+user.replace(/\+/,' ')+'</caption>'+tbody
}else{
tbody += '<th><img src=' + imuser + '></th>'
}
tbody += '<th><img src=' + imcomm + '8/80/Icons-mini-comment_blue.gif></th></tr>'
//parse entries
for (var i=0; i<lis.length; i++){
try {
parseRow(lis[i].innerHTML)
} catch(e) { //put without parsing
tbody += '<td colspan='+columns+'>' + lis[i].innerHTML + '</td>'
jsMsg('<b>logPage:</b> ' + e.lineNumber + ': ' + e.name + ': ' + e.message + ' ; please <a href="http://en.wikipedia.org/wiki/user_talk:Alex_Smotrov">report</a>')
}
}
//insert table
logTable = document.createElement('div')
logTable.innerHTML = '<table class=wikitable width=100% id=logTable>' + tbody + '</table>'
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(/([^<]+)(<a.+?>) (\(<a.+?<\/a>\)) /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(/>(.)(.*?)</g, '>$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 = ' <small>(version)</small>'
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 = ' <i>('+word.split(' ')[0] + ')</i>'
case 'protected':
what = getLink()
if (ma = comment.match(/\(\S+ (.+? \(UTC\))\)$/)){ //expiration date
until = '<small> / ' + ma[1] + '</small>'
//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 + '<br>' + 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+' <small>('+talkContribLinks.replace(/>(.)(.*?)</g, '>$1<')+')</small>'
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 = '<b>'+what+'</b>' //range block
if (options.indexOf(m.mwAnonOnly) == -1) opt += m.NotAnonOnly //registered users blocked too
}else{ //user block
// what += ' <small>(<a title="' + m.NewUserLog + '" href="/w/index.php?title=Special:Log&type=newusers&user=' +encodeURIComponent(blockedUser) + '">?</a>)</small>'
if (options.indexOf(m.mwNoAuto) != -1)
opt += ' <span title="' + m.mwNoAuto + '">'+ m.NoAuto + '</span>'
if (options.indexOf(m.mwNoEmail) != -1)
opt += ' <span title="' + m.mwNoEmail + '">' + m.NoEmail + '</span>'
}
opt = '<small title="'+options+'">'+opt+'</small>'
what += logBlDivider + length + ' ' + opt
//' <span style="white-space:nowrap" title="' + options + '">' + '</span>'
//reason = reason.replace(/<span class="comment">\(/,'').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] + ' <small>' + ma[2].replace(/>(.)(.*?)</g, '>$1<') + '</small>' //shorten into (t | c | b)
break
case 'moved':
ma = row.match(/<a[^<]+<\/a>/ig)
what = ma[0] + '<br>' + 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 = '<s>bot: ' + getShortLink() + '</s>'
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 = '<br />' + 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,'') + '</td>'
+'<td class=logicon>'+icon+'</td>'
+'<td class=logcontent><div>'+what+'</div></td>'
+(user ? '' : '<td class=loguser>'+who+'</td>')
+'<td class=logcomment><div>'+comment + '</div></td></tr>'
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]+'<br/>'+ma[2].replace(/ /,' ')
return '<td class=logtime title="'+when+'"><small>'+when2+'</small></td>'
}
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 += '<span style="white-space:nowrap">' + htm + ')</span>'
}
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)