MediaWiki:Tool/RightsLog.js

Материал из Викимультии — энциклопедии мультипликации
Перейти к навигации Перейти к поиску

Возможно, этот код документирован.

//"AJAX log" for [[special:log/rights]]; called from [[MediaWiki:Log.js]]

mw.loader.using('mediawiki.util').done(function () {

//on script load
if( mw.config.get('wgCanonicalSpecialPageName') == 'Log' && /&type=rights|\/rights/.test(document.URL) ){
  mw.loader.load('jquery.spinner')
  $(rightsLog)
}

});

function rightsLog(){

mw.util.addCSS('\
#log-form {font-size: 13px}\
td.timestamp, td.sysop, td.parsedcomment {font-size:smaller}\
td.timestamp {white-space:nowrap}\
span.button {cursor:pointer; color: #2F6FAB}\
.added {color:green}\
.removed {color:red}\
.removed.useless {font-size:smaller; color:gray; text-decoration:line-through}\
.same {font-size:smaller; color:gray}\
.same.useless {color:#a0a}\
')

var uselessFlags = {
  autoeditor: ['editor', 'bot', 'sysop'],
  uploader:   ['filemover', 'closer', 'sysop'],
  suppressredirect: ['filemover', 'closer', 'sysop'],
  rollbacker: ['sysop'],    
  filemover: ['sysop'], 
  closer: ['sysop']
}  

var flagName = 
{uploader: 'загружающий'
,autoeditor: 'автопатрулируемый'
,editor: 'патрулирующий'
,rollbacker: 'откатывающий'
,closer: 'итогоподводящий'
,suppressredirect: 'переим-без-перенапр.'
,filemover: 'переим-файлы'
,sysop: 'администратор'
,bureaucrat: 'бюрократ'
}

var msg =
{legend:'Альтернативный журнал присвоения прав  ' 
 + aLink('MediaWiki talk:Tool/RightsLog.js', '(документация)') 
 + '  <span id=log-close class=button>[закрыть]</span>'
,count:'Показано записей: <span id=log-count></span>'
,next:'Добавить 50 следующих (200 | 500)'
}
var mm = function (txt){ return msg[txt] || txt }

var rcvCount

var api = apiList(
  { list: 'logevents', 
    leaction : 'rights/rights', 
    leprop: 'timestamp|title|user|details|parsedcomment'
  },
  receive
 )

//hide old content
var frm = $('#mw-log-user').closest('form')
var oldContent  = $( document.getElementById('mw-content-text') || frm.parent() ).hide()

//clone existing form
frm = frm.clone(true)
var newContent = $('<div />')
.insertAfter(oldContent)
.append( frm.attr('id','log-form'), '<div id=log-output />' )

//modify form
frm.find('select[name="type"]').remove()
frm.find('label[for="tagfilter"]').closest('p').remove()
frm.find('legend').html( mm('legend') )
$('#log-close').click(function(){  newContent.remove(); oldContent.show() })
frm.find('input[type="submit"]').click(clickSubmit)
 
//start
frm.find('input[type="submit"]').click()
 
return

function clickSubmit(e){
 e.preventDefault()

 //<input name=page>: prepend 'user:' if omitted
 var p = inp('page')
 if( p && ! /:/.test(p) ) inp('page', 'user:' + p) 

 //get params from the form
 var params = {lelimit: mw.user.options.get('rclimit') || 20 }
 p = inp('user');  if( p ) params.leuser  = p
 p = inp('page');  if( p ) params.letitle = p
 //and timestamp
 var ts, mo = inp('month'), yr = inp('year')
 if( mo > 0 )  ts = ( yr || new Date().getUTCFullYear().toString() ) + pad0(mo) // !!!
 else if( yr ) ts = yr + '01'
 if( ts ) params.lestart = ts + '00000000'
 
 //start
 rcvCount = 0
 $('#log-output').empty()
 api.getFirst(params)

 function inp(nm, vv){ //set/get input value
   var el = frm.find('input[name="'+nm+'"]')
   if( vv ) el.val(vv)
   else return $.trim( el.val() )
  }
 
} 

function receive(events) {

 if ( ! $('#log-table').length ){ //create table header
  $('#log-output').append(
   '<table class=wikitableX id=log-table cellspacing=10><tr>'
   + aTH('Time', '2/26/Clock_simple.svg')
   + ( api.params.letitle ? '' :
     aTH('User', '1/12/User_icon_2.svg') )
   + aTH('Rights', '2/2d/Flag_green.png')
   + ( api.params.leuser ? '' :
     aTH('Sysop') )
   + aTH('Comment')
   + '</tr></table>'
   + '<div>' + mm('count') + '</div>'
   + '<div id=log-next>' + mm('next').replace(/\d+/g, '<span class=more>$&</span>') + '</div>'
  )
  $('span.more')
  .addClass('button')
  .click( function(){  api.getNext( {lelimit: $(this).text()} )   })
 }
 
 
 var htm = '', rOld, rNew, right
 $.each(events, function(i, ev){
   //calc added/removed rights
   rOld = ev.rights['old'].split(', ')
   rNew = ev.rights['new'].split(', ')
   right = {}
   $.each( rOld, function(j, r){  right[r] = 'removed'   })
   $.each( rNew, function(j, r){  right[r] = right[r] ? 'same' : 'added' })
   //output row
   htm += '<tr>'
    + aTD( ev, 'timestamp' )
    + ( api.params.letitle ? '' :
      aTD( ev.title.replace(/^[^:]+:/,''), 'user' ) )
    + aTD( listR('added') + listR('removed') + listR('same'), 'rights' )
    + ( api.params.leuser ? '' :
      aTD( ev, 'user', 'sysop' ) )
    + aTD( ev, 'parsedcomment')
    + '</tr>'    
 })
 $('#log-table').append('<tbody>'+htm+'</tbody>')
 
 //update count and 'next' links
 rcvCount += events.length
 $('#log-count').text( rcvCount )
 $('#log-next').toggle( !!api.cont )

 function listR(what){
   var s = ''
   $.each( right, function(r, type){
     if( type == what ) 
       s += '<span class="' + type + isUseless(r) + '">' + ( flagName[r] || r ) + '</span> '
   })
   return s
 }
 
 function isUseless(r){ //using rNew[]
   var uf = uselessFlags[r] || []
   for( var i=0; i<uf.length; i++ )
     if( $.inArray(uf[i], rNew) != -1 ) return ' useless'
   return ''
 }
 
}
}//rightsLog
 

// =================================================================================

function wait(isWait){ //spinner and hourglass cursor
 document.body.style.cursor =  isWait ? 'wait' : ''
 if( ! $.createSpinner ) return //module not loaded yet
 if( isWait ) $.createSpinner({ id:'rl', size:'large', type:'block' }).appendTo('#log-output')
 else         $.removeSpinner('rl')
}

//Usage:
// api = apiList ( defaultParams, callback );      api.getFirst ( [params] ) ;      if( api.cont ) api.getNext ( [params] )  
function apiList(defParams, callback){
 var name = defParams.list
 var api = new mw.Api( {parameters: defParams} )  
 var recv = function (resp, textStatus, jqXHR){
   wait()
   //updateServerTime(jqXHR)
   api.cont = getChild(resp, 'query-continue.' + name) //save query-continue
   callback( getChild(resp, 'query.' + name) ) //return only data
 }
 // api.cont = null; api.params = {}
 api.getFirst = function(p){ wait(true); api.params = p; this.get( api.params).done(recv) }
 api.getNext =  function(p){ wait(true); this.get( $.extend({}, api.params, p, api.cont)).done(recv) }
 return api
}


function getChild(obj, path){ //example:  getChild( data , 'query.pages..somekey' )
 path = path.split('.')
 for( var i=0; i<path.length; i++ ){
   var key = path[i]
   if( key == '' ) for (key in obj) break //get any child
   if( obj ) obj = obj[key]
 }
 return obj
} 

function aTD(obj, key, clss){
  return '<td class="' + (clss || key) + '">' + aVal( obj, key ) + '</td>'
}

function aTH(tip, ico, clss){
  return '<th title="' + tip + '" class="' + (clss||tip).toLowerCase() + '" >' 
  + (ico ? aIcon(ico, 15) : '') + '</th>'
}

function aVal (obj, key){
 var val =  typeof obj == 'object' ? obj[key] : obj
 switch ( key ){
   case 'title': case 'page': return aLink(val)
   case 'user':  return aLink('Special:Contributions/'+val, val)
   case 'touched': case 'timestamp': return Ts2String(val)
   //return inHours( wgServerTime - Ts2Date(val) )
   case 'hours': return inHours(val)
   //case 'size': case 'oldlen': case 'newlen':
   default:  return val
 }
}

function aLink (page, name, attr){
 name = name || page
 if( name.length > 40) name = name.substr(0, 37) + '…'
 attr = $.extend(   
   { href: mw.util.getUrl(page),
     title: page == name  ?  ''  :  page.replace(/"/g,'"')
   },
   attr 
 )
 return mw.html.element( 'a', attr, name )
}

function aIcon(src, size, attr){ //returns <img ...> from Commons
 if( size ) src = 'thumb/'+src+'/'+size+'px-'+src.split('/')[2] + ( /\.svg$/.test(src) ? '.png' : '' )
 return '<img src="http://upload.wikimedia.org/wikipedia/commons/'
 + src + '" ' + (attr||'')+'>'
}

function pad0(v, len){ // 6 -> '06'
 len = len || 2
 v = v.toString()
 while (v.length < len) v = '0'+v
 return v
}

function Ts2String(ts){
 var m = ts.replace(/\D/g,'').match(/(\d\d\d\d)(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)/)
 //var window.wmDateOutput = 'hh:mm, dd mon yy' // ?
 return '<small>hh:mm,</small> dd mon yy'
 .replace('yy', m[1])
 .replace('mon', wgMonthNamesShort[parseInt(m[2],10)])
 .replace('dd', m[3])
 .replace('hh', m[4])
 .replace('mm', m[5])
 .replace('ss', m[6])
} 

//20081226220605  or  2008-01-26T06:34:19Z   -> date
function Ts2Date(ts){
 var m = ts.replace(/\D/g,'').match(/(\d\d\d\d)(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)/)
 return new Date ( Date.UTC(m[1], m[2]-1, m[3], m[4], m[5], m[6]) )
}