/* small library for MW API requests */
var apl = new function(){
//initialization
var wgServerTime
mw.util.addCSS('span.sort {display:none}')
//-------------------API
var queryType =
{rc:'list=recentchanges'
,uc:'list=usercontribs'
,ap:'list=allpages'
,rv:'prop=revisions'
,le:'list=logevents'
}
// Usage: var myQ = new simpleQuery('rc', {limit:20}, myFunc)
// then myQ.call(); ... if (myQ.isMore) myQ.call(50)
this.simpleQuery = function(tp, params, cbfunc){
var shortName = tp // 'rc'
var longName = queryType[shortName].split('=')[1] // 'recentcontribs'
var url = wgScriptPath+'/api.php?action=query&format=json&rawcontinue=&' + queryType[shortName]
var request = {}, callback = cbfunc, next
for (var k in params) addParam(k, params[k])
this.isMore = false
function addParam(key, val){
if (!/titles|pageids|revids|redirects|indexpageids|requestid/.test(key))
key = shortName + key
request[key] = val
}
this.call = function(params){
if (typeof params == 'number') request[shortName+'limit'] = params
else if (typeof params == 'object') for (var k in params) addParam(k, params[k])
$.getJSON(url, $.extend({}, request, next), recv)
}
this.isMore = function() {
return next
}
var recv = function(data, textStatus, jqXHR){
updateServerTime(jqXHR)
//save continue values
if (next = data['query-continue']) next = next[longName]
if (!data.query) return dispMsg('Server returned empty data')
callback(data.query[longName], data)
}
}
this.updateServerTime = updateServerTime = function(xhr){
if (xhr) wgServerTime = new Date( xhr.getResponseHeader('Date') )
}
this.parseTimestamp = parseTS
this.getChild = function(obj, path){ //example: getSomeChild( 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
obj = obj[key]
}
return obj
}
//---------------------------- HTML OUTPUT
this.toggleCSS = (function (){ //example: toggleCSS( 'p{display:none}', true )
var sheet = {}
return function(css, isOn){
if (!sheet[css]) sheet[css] = mw.util.addCSS(css)
sheet[css].disabled = ! isOn
}
})()
this.spinner = function (el){
if (el)
$(el).append('<img class=spinner style="margin-left:1em" src="'
+ stylepath +'/common/images/spinner.gif" alt="..." title="..." />')
else
$('img.spinner').remove()
}
this.checkbox = function (name, id, val, txt){
return '<input type=checkbox name='+name+' id='+id + ' value="'+val+'">'
+ '<label for='+id+'>' + txt + '</label>'
}
this.icon = function(src, size, attr){ //returns <img ...> from Commons
if (size) src = 'thumb/'+src+'/'+size+'px-'+src.split('/')[2]+'.png' //for svg
return '<img src="http://upload.wikimedia.org/wikipedia/commons/'
+ src + '" ' + (attr||'')+'>'
}
this.output = function (val, type){
switch ( type ){
case 'title': return this.outputPage(val, simplifyTitle(val) )
case 'user': return this.outputPage('Special:Contributions/'+val, val)
case 'touched':
case 'timestamp': return inHours(val)
//case 'size': case 'oldlen': case 'newlen':
default:
return val
}
}
this.outputPage = function (page, name){
name = name || page
if (name.length > 40) name = name.substr(0, 37) + '…'
var tip = ''
if (page != name) tip = ' title="'+page.replace(/"/g,'"') + '"'
page = encodeURI(page.replace(/ /g,'_')).replace(/\?/g,'%3F')
// could use encodeURIComponent(page).replace(/%2F/g,'/') ?
return '<a href="' + wgArticlePath.replace('$1', '') + page + '"'
+ tip + '>'+name+'</a>'
}
this.outputCell = function (val, key){
var attr = '', a1 = '', a2 = '', clss = key
if( typeof val == 'object' ){
if( key == 'title' && typeof val.redirect == 'string' ) clss += ' redirect'
val = val[key]
}
if ( key == 'timestamp'){ //handle timestamp
attr = ' title="' + val + '"'
a1 = '<span class=sort>' + val + '</span><span class=hours>'
a2 = '</span>'
}
return '<td class="' + clss + '"' + attr + '>' + a1 + this.output( val, key ) + a2
}
//----------- AUX Functions
function pad0(v, len){ // 6 -> '06'
v = v.toString()
while (v.length < len) v = '0'+v
return v
}
function diffSize(n){
return '<span class='
+ 'mw-plusminus-'+ (n>0 ? 'pos' : (n<0?'neg':'null'))
+ (n < - 500 ? ' style="font-weight:bold"' : '')
+ '>' + n.toString() + '</span>'
}
function inHours(ts, fromTime){ //timestamp -> "2:30" or 5,06 or 21
var ms = ( fromTime || wgServerTime ) - parseTS(ts)
var mm = Math.floor(ms/60000)
var hh = Math.floor(mm/60); mm = mm % 60
var dd = Math.floor(hh/24); hh = hh % 24
if (dd) return dd + (dd<10?'<small>,'+pad0(hh,2)+'</small>':'')
else return '<small>'+hh + ':' + pad0(mm,2)+'</small>'
}
//20081226220605 or 2008-01-26T06:34:19Z -> date
function parseTS(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]) )
}
//---------- RU ONLY
var simplerTitles =
{'Википедия:Проект:Инкубатор/Статьи/': 'Инк:'
,'Обсуждение Википедии:': 'ОВ:'
,'Википедия:':'ВП:'
}
function simplifyTitle(ttl){
for (var tt in simplerTitles)
if ( ttl.substring (0, tt.length) == tt )
ttl = simplerTitles[ tt ] + ttl.substring(tt.length)
return ttl
}
}//library
//add popup to element
$.fn.extend({
addPopup: function( htm ){
$(this)
.data( 'popup', htm )
.mouseenter ( function(){
$('#popup').remove()
var el = $(this)
var pp = $('<div id=popup style="position:absolute; background:#f5f5f5; max-width:400px; border:1px outset gray; padding:5px" />')
.appendTo( document.body )
.offset( el.offset() )
.html( el.data( 'popup' ) )
.bind('click mouseleave', function(){ $(this).remove() } )
//position
pp.offset( el.offset() ) // need this again for Opera 11 ?
if( pp.offset().left + pp.width() > $(window).width() ) //move left if needed
pp.css( 'left', $(window).width() - pp.width() - 50 + 'px' )
})
}
})