User:Splarka/ajaxrecentchanges.js

/* Ajax recent changes and patrolling framework, version [0.0.5a]
Originally from: http://en.wikipedia.org/wiki/User:Splarka/ajaxrecentchanges.js

Note:
* Patrol flags/links will sometimes show up where patrolling is not enabled.
** This was a bug in the API that generated patrol tokens too often.
** Fixed in http://svn.wikimedia.org/viewvc/mediawiki?view=rev&revision=49000

Todo:
* Checkbox for batch patrolling

Wontdo:
* Parse comments
* Add (talk|contribs|block) links, click their name, lazy
* Localize error messages or focus on the log message 'logaction' (wrong tense, but it works fine).
*/

if(!window.arc_i18n) {
  var arc_i18n = { 
  'title'	:'Ajax recent changes',
  'desc'	:'Paginated enhanced ajax recent changes and patrolling.',
  'mypatrol'	:'My patrol log',
  'startstamp'	:'Start timestamp (8601)',
  'limit'	:'Limit',
  'showapb'	:'Show ajax patrol buttons',
  'filterflag'	:'Filter by flag',
  'minor'	:'Minor',
  'bot'		:'Bot',
  'anon'	:'Anon',
  'redirect'	:'Redirect',
  'patrolled'	:'Patrolled',
  'all'		:'All',
  'filtertype'	:'Filter by type',
  'edit'	:'Edits',
  'new'		:'New pages',
  'log'		:'Logs',
  'filterns'	:'Filter by namespace',
  'fetch'	:'Fetch',
  'noresults'	:'Nothing found.',
  'diff'	:'diff',
  'hist'	:'hist',
  'patrolbtn'	:'Patrol',
  'logsuffix'	:' log',
  'patroldone'	:'done',
  'nsmain'	:'MAIN'
  }
}

$(function() {
  mw.util.addPortletLink('p-tb','/wiki/Special:BlankPage?blankspecial=ajaxrc',arc_i18n['title'],'t-ajax-rc',arc_i18n['desc']);
});

if(wgCanonicalSpecialPageName && wgCanonicalSpecialPageName.toLowerCase() == 'blankpage' && queryString('blankspecial') == 'ajaxrc') {
  document.title = arc_i18n['title'];
  addOnloadHook(ajaxRcForm);
}

function ajaxRcForm() {
  mw.util.addPortletLink('p-tb','/wiki/Special:Log/patrol?user=' + encodeURIComponent(wgUserName),arc_i18n['mypatrol']);
  //subvert this Special: page to our own needs.
  var con = document.getElementById('content') || document.getElementById('mw_content');
  var bcon = document.getElementById('bodyContent') || document.getElementById('mw_contentholder');
  var fh = getElementsByClassName(con,'h1','firstHeading')[0];
  while(fh.firstChild) fh.removeChild(fh.firstChild)
  fh.appendChild(document.createTextNode(arc_i18n['title']));
  for(var i=0;i<bcon.childNodes.length;i++) {
    bcur = bcon.childNodes[i];
    if(bcur.id != 'siteSub' && bcur.id != 'contentSub' && bcur.className != 'visualClear') {
      while(bcur.firstChild) bcur.removeChild(bcur.firstChild)
      if(bcur.nodeType == 3) bcur.nodeValue = '';
    }
  }

  appendCSS(
    '#arc-form {border:1px solid black;padding:.5em;margin:2em;} #arc-out {border:1px solid black;padding:.5em;margin:.5em;}'
  + '#arc-fetch {padding:0 1em;margin:0 .5em;} .clear {clear:both;} .arc-box {border:1px solid #bbbbbb;padding:.2em;margin:.5em;}'
  + '.arc-cbox {display:block;float:left;width:11em;white-space:nowrap;overflow:hidden;font-size:80%;margin:0 .f2em;}'
  + '.arc-box-label {text-align:center;border-bottom:1px solid #bbbbbb;margin-bottom:.3em} .spacer {border:1px solid transparent;margin-right:.5em;}'
  + '.arc-patrol {border:2px outset #bbbbbb;background-color:#bbbbbb;color:black;padding:2px;margin:3px;text-decoration:none;}'
  );

  var form = '<form id="arc-form" action="javascript:void(0)">'
    + '<label for="arc-start">' + arc_i18n['startstamp'] + ':</label> <input type="text" name="arc-start" id="arc-start" value="" size="25" maxlength="20"/><span class="spacer"></span>'
    + '<label for="arc-limit">' + arc_i18n['limit'] + ':</label> <input type="text" name="arc-limit" id="arc-limit" value="50" size="5" maxlength="3"/><span class="spacer"></span>'
    + '<input type="checkbox" name="arc-patrol-enable" id="arc-patrol-enable" /><label for="arc-patrol-enable">' + arc_i18n['showapb'] + '</label><br/>'
    + '<div class="arc-box" id="arc-f-boxen">' + arc_i18n['filterflag'] + ': <span class="spacer"></span>'
    + '<label for="arc-f-minor">' + arc_i18n['minor'] + ':</label> <input type="button" name="arc-f-minor" id="arc-f-minor" value="' + arc_i18n['all'] + '" onclick="ajaxRcFlagChange(this)" /><span class="spacer"></span>'
    + '<label for="arc-f-bot">' + arc_i18n['bot'] + ':</label> <input type="button" name="arc-f-bot" id="arc-f-bot" value="!bot" onclick="ajaxRcFlagChange(this)" /><span class="spacer"></span>'
    + '<label for="arc-f-anon">' + arc_i18n['anon'] + ':</label> <input type="button" name="arc-f-anon" id="arc-f-anon" value="' + arc_i18n['all'] + '" onclick="ajaxRcFlagChange(this)" /><span class="spacer"></span>'
    + '<label for="arc-f-redirect">' + arc_i18n['redirect'] + ':</label> <input type="button" name="arc-f-redirect" id="arc-f-redirect" value="' + arc_i18n['all'] + '" onclick="ajaxRcFlagChange(this)" /><span class="spacer"></span>'
    + '<label for="arc-f-patrolled">' + arc_i18n['patrolled'] + ':</label> <input type="button" name="arc-f-patrolled" id="arc-f-patrolled" value="' + arc_i18n['all'] + '" onclick="ajaxRcFlagChange(this)" />'
    + '</div>'
    + '<div class="arc-box" id="arc-t-boxen">' + arc_i18n['filtertype'] + ': <span class="spacer"></span>'
    + '<input type="checkbox" name="arc-t-edit" id="arc-t-edit" checked="checked" value="edit" /><label for="arc-t-edit">' + arc_i18n['edit'] + '</label><span class="spacer"></span>'
    + '<input type="checkbox" name="arc-t-new" id="arc-t-new" checked="checked" value="new" /><label for="arc-t-new">' + arc_i18n['new'] + '</label><span class="spacer"></span>'
    + '<input type="checkbox" name="arc-t-log" id="arc-t-log" checked="checked" value="log" /><label for="arc-t-log">' + arc_i18n['log'] + '</label><span class="spacer"></span>'
    + '</div>'
    + '<div class="arc-box" id="arc-ns-boxen"><div class="arc-box-label">' + arc_i18n['filterns'] + '</div></div>'
    +  ''
    + '<input type="button" name="fetch" value="' + arc_i18n['fetch'] + '" id="arc-fetch" onclick="ajaxRcFetch()" /><div class="clear"></div>'
    + '</form>'

  bcon.innerHTML += form + '<div id="arc-out"></div>';
  mw.loader.load(wgScriptPath + '/api.php?action=query&meta=siteinfo&siprop=namespaces&format=json&callback=ajaxRcFormNamespacesCB&smaxage=2678400&maxage=2678400');
}

function ajaxRcFetch(timestamp,direction) {
  document.getElementById('arc-fetch').setAttribute('disabled','disabled');
  var nav = document.getElementById('arc-fetchnav');
  if(nav) nav.style.visibility = 'hidden'
  injectSpinner(document.getElementById('arc-fetch'),'arc-spin');

  //direction
  var rcdir = '';
  if(direction) rcdir = '&rcdir=' + direction + '&requestid=' + direction

  //start
  var rcstart = timestamp || document.getElementById('arc-start').value;
  rcstart = rcstart.replace(/[^\d]*/g,'');
  if(rcstart != '' && /^\d{14}$/.test(rcstart)) {
    rcstart = '&rcstart=' + rcstart;
  } else {
    rcstart = '';
  }

  //limit
  var rclimit = parseInt(document.getElementById('arc-limit').value);
  if(isNaN(rclimit)) rclimit = 100
  rclimit = '&rclimit=' + rclimit;

  //type
  var tb = document.getElementById('arc-t-boxen').getElementsByTagName('input');
  var rctype = [];
  for(var i=0;i<tb.length;i++) if(tb[i].checked) rctype.push(tb[i].value)
  if(rctype.length > 0) {
    rctype = '&rctype=' + rctype.join('|');
  } else {
    rctype = '';
  }

  //show (flags)
  var fb = document.getElementById('arc-f-boxen').getElementsByTagName('input');
  var rcshow = [];
  for(var i=0;i<fb.length;i++) if(fb[i].value != arc_i18n['all']) rcshow.push(fb[i].value) 
  if(rcshow.length > 0) {
    rcshow = '&rcshow=' + rcshow.join('|');
  } else {
    rcshow = '';
  }

  //namespace
  var nsb = document.getElementById('arc-ns-boxen').getElementsByTagName('input');
  var rcnamespace = [];
  for(var i=0;i<nsb.length;i++) if(nsb[i].checked) rcnamespace.push(nsb[i].value)
  if(rcnamespace.length > 0) {
    rcnamespace = '&rcnamespace=' + rcnamespace.join('|');
  } else {
    rcnamespace = '';
  }

  //prop & token
  var rcprop = '&rcprop=user|comment|flags|timestamp|title|ids|sizes|redirect|patrolled|loginfo';
  var rctoken = '&rctoken=patrol';

  var url = wgScriptPath + '/api.php?action=query&rawcontinue=&format=json&list=recentchanges' + rcdir + rcstart + rclimit + rctype + rcshow + rcnamespace + rcprop + rctoken;
  var req = sajax_init_object();
  req.open('GET', url, true);
  req.onreadystatechange = function() {
    if(req.readyState == 4 && req.status == 200) {
      eval("ajaxRcFetchHandler(" + req.responseText + ",'" + req.responseText.replace(/\'/g,"`") + "')");
    }
  }
  req.send(null);
}

function ajaxRcFetchHandler(obj,txt) {
  document.getElementById('arc-fetch').removeAttribute('disabled');
  removeSpinner('arc-spin');
  var out = document.getElementById('arc-out');
  var ajaxpatrol = document.getElementById('arc-patrol-enable').checked;
  while(out.firstChild) out.removeChild(out.firstChild)
  if(obj['error']) {
    out.appendChild(document.createTextNode('Api error: ' + obj['error']['code'] + ' - ' + obj['error']['info'] + '\n'));
    return;
  }
  if(!obj['query'] || !obj['query']['recentchanges']) {
    out.appendChild(document.createTextNode('Unexpected response: ' + txt + '\n'));
    return;
  }
  var rc = obj['query']['recentchanges'];
  if(rc.length == 0) {
    out.appendChild(document.createTextNode(arc_i18n['noresults']));
    return;
  }

  var backwards = false;
  if(obj['requestid'] && obj['requestid'] == 'newer') backwards = true

  var nav = document.createElement('div');
  nav.setAttribute('id','arc-fetchnav');
  if(obj['query-continue'] && obj['query-continue']['recentchanges'] && obj['query-continue']['recentchanges']['rcstart']) {
    var rcstart = obj['query-continue']['recentchanges']['rcstart'];
    var rcstartnewer = rcstart;
    var rcstartolder = rcstart;
    if(!backwards) {
      rcstartnewer = rc[0]['timestamp'];
    } else {
      rcstartolder = rc[0]['timestamp'];
    }
    addLinkChild(nav,'javascript:ajaxRcFetch("' + rcstartnewer + '","newer")','Newer');
    addText(nav,' | ');
    addLinkChild(nav,'javascript:ajaxRcFetch("' + rcstartolder + '","older")','Older');
  } else if(backwards) {
    addLinkChild(nav,'javascript:ajaxRcFetch()','Older');
  }
  out.appendChild(nav);

  var ul = document.createElement('ul');
  for(var i=0;i<rc.length;i++) {
    var r = rc[i];
    var li = document.createElement('li');
    if(r['type'] == 'edit') {
      var rcid = ''
      if(typeof r['patrolled'] == 'undefined' && r['rcid'] && r['patroltoken']) rcid = '&rcid=' + r['rcid']
      addText(li,'(');
      addLinkChild(li,wgScript + '?oldid=' + r['old_revid'] + '&diff=' + r['revid'] + rcid,arc_i18n['diff']);
      addText(li,') (');
      addLinkChild(li,wgScript + '?curid=' + r['pageid'] + '&action=history',arc_i18n['hist']);
      addText(li,') . . ');
      if(typeof r['bot'] != 'undefined') addText(li,'b','span','bot')
      if(typeof r['minor'] != 'undefined') addText(li,'m','span','minor')
      if(rcid != '' && r['patroltoken'])addText(li,'!','span','unpatrolled');
      addText(li,' ');
      addLinkChild(li,wgScript + '?curid=' + r['pageid'],r['title']);
      var size = '' + (parseInt(r['newlen']) - parseInt(r['oldlen']));
      if(size.substring(0,1) != '-') size = '+' + size
      addText(li,'; ' + r['timestamp'].replace(/[TZ]/ig,' ') + ' . . (' + size + ') . . ' );
      addLinkChild(li,wgScript + '?title=Special:Contributions&target=' + encodeURIComponent(r['user']),r['user']);
      if(r['comment']) addText(li,' (' + r['comment'] + ')','i')
      if(ajaxpatrol == true && rcid != '' && r['patroltoken']) addLinkChild(li,'javascript:ajaxRcDoPatrol("' + r['rcid'] + '","' + encodeURIComponent(encodeURIComponent(r['patroltoken'])) + '")',arc_i18n['patrolbtn'],'arc-patrol-' + r['rcid'],'arc-patrol');
    } else if(r['type'] == 'new') {
      var rcid = ''
      if(typeof r['patrolled'] == 'undefined' && r['rcid']) rcid = '&rcid=' + r['rcid']
      addText(li,'(' + arc_i18n['diff'] + ') (');
      addLinkChild(li,wgScript + '?curid=' + r['pageid'] + '&action=history',arc_i18n['hist']);
      addText(li,') . . ');
      addText(li,'N','span','newpage');
      if(rcid != '' && r['patroltoken']) addText(li,'!','span','unpatrolled');
      addText(li,' ');
      addLinkChild(li,wgScript + '?curid=' + r['pageid'] + rcid,r['title']);
      addText(li,'; ' + r['timestamp'].replace(/[TZ]/ig,' ') + ' . . (+' + r['newlen'] + ') . . ' );
      addLinkChild(li,wgScript + '?title=Special:Contributions&target=' + encodeURIComponent(r['user']),r['user']);
      if(r['comment']) addText(li,' (' + r['comment'] + ')','i')
      if(ajaxpatrol == true && rcid != '' && r['patroltoken']) addLinkChild(li,'javascript:ajaxRcDoPatrol("' + r['rcid'] + '","' + encodeURIComponent(encodeURIComponent(r['patroltoken'])) + '")',arc_i18n['patrolbtn'],'arc-patrol-' + r['rcid'],'arc-patrol');
    } else if(r['type'] == 'log') {
      addText(li,'(');
      addLinkChild(li,wgScript + '?title=Special:Log&type=' + r['logtype'],r['logtype'] + arc_i18n['logsuffix']);
      addText(li,'); ' + r['timestamp'].replace(/[TZ]/ig,' ') + ' . . ' );
      addLinkChild(li,wgScript + '?title=Special:Contributions&target=' + encodeURIComponent(r['user']),r['user']);
      addText(li,' ' + r['logaction'] + ' ');
      addLinkChild(li,wgScript + '?title=' + encodeURIComponent(r['title']),r['title']);
      if(r['comment']) addText(li,' (' + r['comment'] + ')','i')
    }
    if(backwards && ul.firstChild) { 
      ul.insertBefore(li,ul.firstChild);
    } else { 
      ul.appendChild(li);
    }
  }
  out.appendChild(ul);
}

function ajaxRcDoPatrol(rcid,token) {
  var params = 'action=patrol&format=json&requestid=' + rcid + '&rcid=' + rcid + '&token=' + token;
  var url = wgScriptPath + '/api.php';
  var req = sajax_init_object();
  req.open('POST', url, true);
  req.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
  req.setRequestHeader('Content-length', params.length);
  req.setRequestHeader('Connection', 'close');
  req.onreadystatechange = function() {
    if(req.readyState == 4 && req.status == 200) {
      eval("ajaxRcDidPatrol(" + req.responseText + ",'" + req.responseText.replace(/\'/g,"`") + "')");
    }
  }
  req.send(params);
}

function ajaxRcDidPatrol(obj,txt) {
  if(!obj['requestid']) return;
  if(obj['error']) {
    alert('Api error in patrolling rcid=' + obj['requestid'] + ' : ' + obj['error']['code'] + '\n' + obj['error']['info']);
    return;
  }
  var button = document.getElementById('arc-patrol-' + obj['requestid']);
  if(!button || !obj['patrol']) return
  button.setAttribute('href','javascript:alert("(' + arc_i18n['patroldone'] + ')");');
  addText(button,' (' + arc_i18n['patroldone'] + ')');
  //{"requestid":"80879","error":{"code":"permissiondenied","info":"Permission denied"}}
  //{"requestid":"80871","patrol":{"rcid":80871,"ns":2,"title":"Page Title Here"}}
}

function ajaxRcFlagChange(obj) {
  var type = obj.getAttribute('id').substring(6);
  var val = obj.value;
  if(val == type) {
    obj.value = '!' + type;
  } else if(val == '!' + type) {
    obj.value = arc_i18n['all'];
  } else {
    obj.value = type;
  }
}

function ajaxRcFormNamespacesCB(obj) {
  if(!obj['query'] || !obj['query']['namespaces']) return
  var ns = obj['query']['namespaces'];
  var nsb = document.getElementById('arc-ns-boxen');
  for(var i in ns) {
    if(typeof i != 'string' || ns[i]['id'] < 0) continue
    var title = ns[i]['*'];
    if(ns[i]['id'] == '') title = arc_i18n['nsmain']
    var canon = ns[i]['canonical'] || '';
    addCheckboxChild(nsb,'arc-ns-' + ns[i]['id'],i,false,'arc-ns-' + ns[i]['id'],title,'arc-cbox',ns[i]['id'] + ' => ' + canon);
    //nsb.appendChild(document.createElement('br'));
  }
  var div = nsb.appendChild(document.createElement('div'));
  div.setAttribute('class','clear');
}

function queryString(p) {
  var re = RegExp('[&?]' + p + '=([^&]*)');
  var matches;
  if (matches = re.exec(document.location)) {
    try { 
      return decodeURI(matches[1]);
    } catch (e) {
    }
  }
  return null;
}

function addText(obj,txt,elem,classes) {
  if(elem) {
    var e = document.createElement(elem);
    e.appendChild(document.createTextNode(txt));
    if(classes) e.setAttribute('class',classes);
    obj.appendChild(e);
    return e;
  } else {
    obj.appendChild(document.createTextNode(txt));
  }
}

function addLinkChild(obj,href,text,id,classes,title) {
  if(!obj || !href || !text) return false;
  var a = document.createElement('a');
  a.setAttribute('href',href);
  a.appendChild(document.createTextNode(text));
  if(id) a.setAttribute('id',id);
  if(classes) a.setAttribute('class',classes);
  if(title) a.setAttribute('title',title);
  obj.appendChild(a);
  return a;
}

function addCheckboxChild(obj,name,value,checked,id,label,classes,title) {
  if(!obj || !name) return false;
  var span = document.createElement('span');
  var c = document.createElement('input');
  c.setAttribute('name',name);
  c.setAttribute('type','checkbox');
  if(value) c.setAttribute('value',value)
  if(checked) c.setAttribute('checked','checked')
  if(title) c.setAttribute('title',title)
  span.appendChild(c);
  if(id) {
    c.setAttribute('id',id);
    if(label) {
      var l = document.createElement('label');
      l.setAttribute('for',id);
      l.appendChild(document.createTextNode(label));
      if(title) l.setAttribute('title',title)
      span.appendChild(l);
    }
  }
  if(classes) span.setAttribute('class',classes);
  obj.appendChild(span);
  return span;
}

Content Disclaimer

Informasi ini disarikan dari Wikipedia dan disajikan kembali untuk tujuan edukasi. Konten tersedia di bawah lisensi CC BY-SA 3.0. Kami tidak bertanggung jawab atas ketidakakuratan data yang bersumber dari kontribusi publik tersebut.

  1. The information displayed on this website is sourced in part or in whole from Wikipedia and has been adapted for the purpose of restating it. We strive to provide accurate and relevant information, however:
  2. There is no guarantee of absolute accuracy. Wikipedia is an open, collaborative project that can be edited by anyone, so information is subject to change.
  3. It is not intended to constitute professional advice. The content displayed is for informational and educational purposes only. For important decisions (e.g., medical, legal, or financial), please consult a professional.
  4. Content copyright. Wikipedia is licensed under the Creative Commons Attribution-ShareAlike License (CC BY-SA). This means that content may be reused with appropriate attribution and shared under a similar license.
  5. Responsible use. Any risk arising from the use of information from this website is entirely the responsibility of the user.