Jump to content
 







Main menu
   


Navigation  



Main page
Contents
Current events
Random article
About Wikipedia
Contact us
Donate
 




Contribute  



Help
Learn to edit
Community portal
Recent changes
Upload file
 








Search  

































Create account

Log in
 









Create account
 Log in
 




Pages for logged out editors learn more  



Contributions
Talk
 

















User:Nick Moyes/recent2test.js

















User page
Talk
 

















Read
View source
View history
 








Tools
   


Actions  



Read
View source
View history
 




General  



What links here
Related changes
User contributions
User logs
View user groups
Upload file
Special pages
Permanent link
Page information
Get shortened URL
Download QR code
 




Print/export  



Download as PDF
Printable version
 
















Appearance
   

 






From Wikipedia, the free encyclopedia
 

< User:Nick Moyes

Note: After saving, you have to bypass your browser's cache to see the changes. Google Chrome, Firefox, Microsoft Edge and Safari: Hold down the ⇧ Shift key and click the Reload toolbar button. For details and instructions about other browsers, see Wikipedia:Bypass your cache.
/**
 * Anti-Vandal Tool
 *
 * This tool hits the RSS feed for recent changes every 30 seconds or
 * so and checks for common vandalism. It does not make a separate
 * server request for every edit.
 * @author: [[en:User:Lupin]]
 * @author: Helder (https://github.com/he7d3r)
 * @source: [[en:User:Lupin/recent2.js]]
 * Modified by [[en:User:Nick_Moyes]] to run for 1000 cycles, not 200 (Line 1224 modified) and with different autosummary text (Line 874 modified)
 * Dual license:
 * @license CC-BY 3.0 <http://creativecommons.org/licenses/by/3.0>
 * @license GFDL 1.2 or any later version <http://www.gnu.org/copyleft/fdl.html>
 */
/*jshint
camelcase: false, curly: true, eqeqeq: false, immed: true, latedef: true,
newcap: true, noarg: true, noempty: true, nonew: true, quotmark: single,
trailing: true, undef: false, unused: false, bitwise: false, forin: false,
onevar: false,

boss: true, eqnull: true, evil: true, funcscope: true,
laxbreak: true, scripturl: true, shadow: true,

wsh: true, nonstandard: true
*/
/*global mw, $, wikEdUseWikEd, WikEdUpdateFrame, setupTooltips,
grabRecentChanges, processRecentChangesSingle, processRecentChanges,
feedFailed, newOutputDiv, processRecentChangesDisplay, getFirstTagContent,
nextChangeSoon, diffCellRe, badWords, spellRe, formatTime, maybeStart,
showHideDetailRange, outputDivs, showHideDetail, loopRecentChanges,
saveBundle, vandalColour, linkmaker, spelldict, hideSysopEdits, marvin,
addMarvin, AVTAutoEdit, self
*/

// <pre><nowiki>

mw.messages.set( {
 'avt-all-rc': 'All recent changes',
 'avt-auto-click': 'The "$1" button has been automatically clicked. ' +
  'Please wait for the next page to load.',
 'avt-auto-click-button-missing': 'Anti-Vandal Tool\n\nautoclick: could not find button "$1".',
 'avt-block': 'block',
 'avt-continue-question': 'Continue monitoring recent changes?',
 'avt-contribs': 'contribs',
 'avt-done': 'done up to $1',
 'avt-entry-not-found': 'Could not find an entry for $1.',
 'avt-error-HTTP-rollback': 'HTTP failed when trying to get rollback link in url\n$1' +
  '\n\nHTTP status text: $2',
 'avt-error-JSON': 'JSON business failed.\n\n$1\n\nCannot rollback.',
 'avt-error-no-bundle': 'No bundle! Please tell Lupin how to reproduce this error - it should not really happen.',
 'avt-error-no-rollback-link': 'No rollback link found.\n' +
  'Maybe you should try the non-admin rollback by checking the checkbox above?\n' +
  'Alternatively, this may be a bug.',
 'avt-error-sysop-list': 'Could not process admin list.\n\n"$1"',
 'avt-error-unable-to-rollback': 'Could not rollback - someone else has edited since the vandal.\n\n' +
  'Page: $1\nVandal: $2\nLast editor: $3\nEdit summary: $4',
 'avt-except-templates': '... except for the Template namespace',
 'avt-expand-content': 'Automatically expand new content',
 'avt-failed': 'failed: $1',
 'avt-failed-badly': 'failed badly: $1',
 'avt-filter-rc': 'Filter recent changes',
 'avt-hide': 'Hide',
 'avt-hist': 'hist',
 'avt-ignore-my-edits': 'Ignore my edits',
 'avt-ignore-outside-main': 'Ignore pages outside the article namespace',
 'avt-ignore-safe-pages': 'Ignore safe pages',
 'avt-ignore-sysop-edits': 'Hide admin edits',
 'avt-ignore-talk-pages': 'Ignore talk pages',
 'avt-ip-rc': 'Recent IP edits',
 'avt-last': 'last',
 'avt-matched': ' matched <b>$1</b>',
 'avt-missing-div': 'no such div: diff_div_$1',
 'avt-non-admin-rollback': 'Use non-admin rollback',
 'avt-only-unchanged': 'Only show edits unchanged after four updates',
 'avt-pause': 'Pause updates',
 'avt-remove-output': 'remove earlier output',
 'avt-resume': 'Resume updates',
 'avt-reverted-edits': 'Reverted edits by [[Special:Contributions/$1|$1]] ([[User talk:$1|talk]]) to last version by $2',
 'avt-rollback': 'rollback',
 'avt-rollback-aborted': '$1 seems to be the only editor to $2.\n\nRollback aborted.',
 'avt-rolled-back': '[Previously rolled back this editor] $1',
 'avt-select-correction': 'Which correction should I use?\nPlease either type a number or another correction.\n',
 'avt-show': 'Show',
 'avt-show-new': 'show new output',
 'avt-spelling-rc': 'Live spellcheck',
 'avt-talk': 'talk',
 'avt-toggle-details': 'toggle these details',
 'avt-unknown-position': 'Unknown position $1 in recent2.js, newOutputDiv.',
 'avt-updating': '($1) updating...',
 'avt-uw-test': 'uw-test',
 'avt-uw-vand': 'uw-vand',
 'avt-warning-regex': 'Warning: ignoring odd-looking regexp on line $1 ' +
  'of [[$2|badwords]]:'
  // FIXME: Remove this hack once [[bugzilla:47395]] is fixed
  .replace( /\$2/g, 'User:Lupin/badwords' ),
 'avt-watched-rc': 'Monitor my watchlist'
} );

var recent2={
 // Edit these to your liking.
 // Make sure there's a comma at the end of each line.
 badwordsPage:         'User:Lupin/badwords',
 filterPage:           'User:Lupin/Filter_recent_changes',
 allRecentPage:        'User:Lupin/All_recent_changes',
 recentIPPage:         'User:Lupin/Recent_IP_edits',
 monitorWatchlistPage: 'User:Lupin/Monitor_my_watchlist',
 spelldictPage:        'Wikipedia:Lists_of_common_misspellings/For_machines',
 liveSpellcheckPage:   'User:Lupin/Live_spellcheck',
 safePages:            '([Ww]ikipedia:([Ii]ntroduction|[Ss]andbox|[Tt]utorial[^/]*/sandbox)|[Tt]emplate:(X[1-9]|Template sandbox))',
 linkify:              true,
 updateSeconds:        30,
 // FIXME: Use <ul> and add a border to each <li>'s
 outputSeparator:      '<hr>',
 apiAulimitUser:        500,
 apiAulimitSysop:       5000,
 backgroundWindowsMax:  10,
 // leave this last one alone
 dummy: null
};

/**
 * Downloads some data
 *
 * @param {Object} bundle Object with the following properties:
 * @param {string} bundle.url
 * @param {Function} [bundle.onSuccess] (xmlhttprequest, bundle) Function to be executed when the download is done
 * @param {Function} [bundle.onFailure] (xmlhttprequest, bundle) Function to be executed when the download fails
 * @param {string} [bundle.otherStuff] OK too, passed to onSuccess and onFailure
 * @return {Object} Object with a close function to close the notification
 * FIXME: Use jQuery and/or mw.Api
 */
recent2.download=function(bundle) {
 var x = window.XMLHttpRequest ? new XMLHttpRequest()
  : window.ActiveXObject ? new ActiveXObject('Microsoft.XMLHTTP')
  : false;

 if (x) {
  x.onreadystatechange=function() {
   if( x.readyState==4 ) {
    recent2.downloadComplete(x,bundle);
   }
  };
  x.open('GET',bundle.url,true);
  x.send(null);
 }
 return x;
};

recent2.downloadComplete=function(x,bundle) {
 if(x.status==200){
  if(bundle.onSuccess){
   bundle.onSuccess(x,bundle);
  }
 } else {
  if(bundle.onFailure){
   bundle.onFailure(x,bundle);
  } else {
   alert(x.statusText);
  }
 }
};

if (! recent2.outputPosition) { recent2.outputPosition=''; }
window.gettingBadWords=false;
window.badWords=null;

// paths
if ( typeof(mw.config.get('wgServer'))!='string' ||
  typeof(mw.config.get('wgArticlePath'))!='string' ||
  typeof(mw.config.get('wgScriptPath'))!='string') {
 recent2.articlePath= '//' + document.location.hostname + '/wiki/';
 recent2.scriptPath= '//' + document.location.hostname + '/w/';
} else {
 recent2.articlePath=mw.config.get('wgServer')+mw.config.get('wgArticlePath').replace(/\$1/, '');
 recent2.scriptPath=mw.config.get('wgServer')+mw.config.get('wgScriptPath')+'/';
}

recent2.getBadWords=function() {
 window.gettingBadWords=true;
 recent2.download({ url: recent2.scriptPath + 'index.php?title=' +
 // reload every 2 h
 recent2.badwordsPage + '&action=raw&ctype=text/css&max-age=7200',
 onSuccess: recent2.processBadWords,
 onFailure: function () { setTimeout(recent2.getBadWords, 15000); return true;}});
};

window.diffCellRe=/<td class="diff-marker">\+<\/td>\s*<td\b[^>]*>\s*<div>\s*(.*?)\s*<\/div>\s*<\/td>/gi;


// processBadWords: generate the badWords RegExp from
// the downloaded data.
// d is the xmlhttprequest object from the download
recent2.processBadWords=function(d) {
 var data=d.responseText.split('\n');
 var phrase=[];
 var string=[];
 for (var i=0; i<data.length; ++i) {
  var s=data[i];

  // ignore empty lines, whitespace-only lines and lines starting with '<'
  if (/^\s*$|^</.test(s)) { continue; }

  // lines beginning and ending with a (back-)slash (and possibly trailing
  // whitespace) are treated as regexps
  if (/^([\\\/]).*\1\s*$/.test(s)) {
   var isPhrase=(s.charAt(0)=='/');
   // remove slashes and trailing whitespace
   s=s.replace(/^([\\\/])|([\\\/]\s*$)/g, '');
   // escape opening parens: ( -> (?:
   s=s.replace(/\(?!\?/g, '(?:');
   // check that s represents a valid regexp
   try { var r=new RegExp(s); }
   catch (err) {
    var errDiv=newOutputDiv('recent2_error', recent2.outputPosition);
    $( errDiv )
     .html(
      mw.message(
       'avt-warning-regex',
       i,
       recent2.badwordsPage
      ).parse()
     )
     .append( $( '<pre>' ).text( s ) );
    continue;
   }
   if (isPhrase) {
    phrase.push(s);
   } else {
    string.push(s);
   }
  } else {
   // treat this line as a non-regexp and escape it.
   phrase.push( mw.util.escapeRegExp(s) );
  }
 }
 //                      123                                3       2|4                        4|5         56                        67        71
 //                      (((    repeated char               )       )|(   ... | strings | ...  )|( border  )(   ... | phrases | ...  )( border ))
 window.badWords=new RegExp('((([^\\-\\|\\{\\}\\].\\s\'=wI:*#0-9a-f])\\3{2,})|(' + string.join('|') + ')|(^|[^/\\w])(' + phrase.join('|') + ')(?![/\\w]))', 'gi');
};

window.gettingWatchlist=false;
recent2.watchlist=null;

recent2.getWatchlist=function() {
 window.gettingWatchlist=true;
 // FIXME: Use the MediaWiki API (action=query&list=watchlistraw)
 recent2.download({url: recent2.articlePath + 'Special:Watchlist/raw',
 onSuccess: recent2.processWatchlist,
 onFailure: function () { setTimeout(recent2.getWatchlist, 15000); return true; }});
};

recent2.processWatchlist=function(req, bundle) {
 var watchlist={};
 var lines=req.responseText.split('\n');
 var inList=false;
 var article = '';
 for (var i=0; i < lines.length; ++i) {
  if (inList || lines[i].indexOf('<textarea id="mw-input-wpTitles"') !== -1) {
   if (inList && lines[i].indexOf('</textarea>') !== -1) {
    window.watchlist =  watchlist;
    return;
   }
   if (!inList) {
    inList = true;
    article = lines[i].replace (/^.*>/, '');
   } else {
    article=lines[i];
   }
   watchlist[article] = true;
  }
 }
};

window.gettingSpelldict=false;
window.spelldict=null;

recent2.getSpelldict=function() {
 window.gettingSpelldict=true;
 // FIXME: Get this in JSON from API
 recent2.download({url: recent2.scriptPath + 'index.php?title=' + recent2.spelldictPage + '&action=raw&ctype=text/css',
 onSuccess: recent2.processSpelldict,
 onFailure: function () { setTimeout(recent2.getSpelldict, 15000); return true; }});
};

recent2.processSpelldict=function(req, bundle) {
 var spelldict={};
 var lines=req.responseText.split('\n');
 var a=[];
 // Parse each line, remove unnecessary spaces and discard those lines which have an invalid format
 for (var i=0; i<lines.length; ++i) {
  var split=lines[i].split('->');
  if (split.length<2) { continue; }
  split[1]=split.slice(1).join('->').split(/, */);
  split[0]=split[0].toLowerCase().replace(/^\s*/, '');
  spelldict[split[0]]=split[1];
  a.push(mw.util.escapeRegExp(split[0]));
 }
 window.spelldict=spelldict;
 window.spellRe=new RegExp('\\b(' + a.join('|') + ')\\b', 'i');
};

recent2.feed=recent2.scriptPath + 'index.php?title=Special:Recentchanges&feed=rss&action=purge';

window.newOutputDiv=function(klass, position, immortal) {
 var h1=document.getElementsByTagName('h1')[0];
 var ret=document.createElement('div');
 if (klass) { ret.className=klass; }
 if (!position) { position='bottom'; }
 switch(position) {
 case 'top':
  h1.parentNode.insertBefore(ret, h1.nextSibling);
  break;
 case 'bottom':
  h1.parentNode.appendChild(ret);
  break;
 default:
  if (!newOutputDiv.alerted) {
   alert( mw.msg( 'avt-unknown-position', position ) );
   window.newOutputDiv.alerted=true;
  }
  return newOutputDiv(klass, 'bottom');
 }
 if (!immortal) { ret.id=newOutputDiv.uid++; }
 window.outputDivs.push(ret);
 return ret;
};
window.newOutputDiv.alerted=false;
window.newOutputDiv.uid=0;
window.outputDivs=[];
var greyFont='<span style="color:#777">';

window.grabRecentChanges=function(feed) {
 if (! window.badWords && recent2.filter_badwords ) {
  if ( ! window.gettingBadWords ) {
   recent2.getBadWords();
  }
  return setTimeout(function(){grabRecentChanges(feed);}, 500);
 }
 if (! window.watchlist && recent2.filter_watchlist) {
  if (! window.gettingWatchlist ) {
   recent2.getWatchlist();
  }
  return setTimeout(function(){grabRecentChanges(feed);}, 500);
 }
 if (! window.spelldict && recent2.filter_spelling) {
  if (! window.gettingSpelldict) {
   recent2.getSpelldict();
  }
  return setTimeout(function(){grabRecentChanges(feed);}, 500);
 }
 if (typeof(recent2.sysopRegExp) == 'undefined') {
  if (! recent2.gettingSysops) {
   recent2.getSysops();
  }
  return setTimeout(function(){grabRecentChanges(feed);}, 500);
 }

 var pos=recent2.outputPosition;
 var output;
 var status;
 if (pos=='top') {
  output=newOutputDiv('recent2.lines', pos);
  status=newOutputDiv('recent2.status', pos);
 } else {
  status=newOutputDiv('recent2.status', pos);
  output=newOutputDiv('recent2.lines', pos);
 }
 status.style.borderStyle='solid';
 status.style.borderColor='orange';
 status.innerHTML=greyFont + mw.msg( 'avt-updating', recent2.count ) + '</span>';

 // this abort stuff doesn't work properly for some reason...
 // recent2.lastFeedDownload && recent2.lastFeedDownload.abort();
 // } catch (summatNasty) { /* do nothing */ }
 recent2.lastFeedDownload=recent2.download({url: feed,
 onSuccess: processRecentChanges,
 output: output, status: status, onFailure: feedFailed});
};

window.feedFailed=function(x,bundle) {
 try {
  bundle.status.innerHTML+=greyFont + mw.msg( 'avt-failed', x.statusText ) + '</span>';
 } catch (err) {
  // FIXME: Is this even possible?
  bundle.status.innerHTML+=greyFont + mw.msg( 'avt-failed-badly', err ) + '</span>';
 }
 return true;
};

recent2.newWindows=true;

window.linkmaker=function(url, text) {
 var s='<a href="' + url + '"';
 if( recent2.newWindows ){
  s += ' target="_blank"';
 }
 s += '>' + text + '</a>';
 return s;
};

recent2.delayedLines={};
recent2.delay=0;

window.processRecentChanges=function(req, bundle){
 recent2.initialId=processRecentChanges.id;
 recent2.latest=processRecentChanges.lastDate;
 var doc=req.responseXML.documentElement;
 if (doc) {
  if (recent2.items=doc.getElementsByTagName('item')) {
   if ((recent2.itemsCurrent=recent2.items.length) > 0) {
    recent2.bundleRef = bundle;
    // start processing one diff every 50 ms
    processRecentChangesSingle();
    return;
   }
  }
 }
 processRecentChangesDisplay(bundle);
 return;
};

recent2.safePagesRe=new RegExp('^' + recent2.safePages + '$');
// delay between processing each diff, in ms
recent2.changeDelay=50;

window.nextChangeSoon=function(rightNow) {
 setTimeout(processRecentChangesSingle, rightNow ? 0 : recent2.changeDelay);
};

// process single diff items delayed by a short timespan
window.processRecentChangesSingle=function(){
 recent2.itemsCurrent--;
 var i = recent2.itemsCurrent;
 var items = recent2.items;
 if (i < 0) { processRecentChangesDisplay(recent2.bundleRef); return; }

 var timestamp = Date.parse(getFirstTagContent(items[i],'pubDate'));
 if (timestamp <= processRecentChanges.lastDate) { nextChangeSoon(true); return; }
 recent2.latest = (timestamp > recent2.latest) ? timestamp : recent2.latest;

 var diffText=getFirstTagContent(items[i],'description').split('</tr>').join('</tr>\n');
 var editSummary=diffText.replace( /^<p>(.*?)<\/p>[\s\S]*/, '$1');
 var editor=getFirstTagContent(items[i], 'creator') || getFirstTagContent(items[i], 'dc:creator');

 if (recent2.ignore_my_edits && mw.config.get('wgUserName')==editor) { return; }

 var article;
 var articleTitle;
 // NB article is the link attribute - a fully qualified URL
 // strip out the &diff=...&oldid=...  bit to leave only ?title=...
 article=getFirstTagContent(items[i], 'link').split('&')[0];
 if (recent2.delayedLines[article] && recent2.delayedLines[article].editor != editor) {
  delete recent2.delayedLines[article];
 }

 if (recent2.filter_anonsOnly && !mw.util.isIPAddress(editor)) {
  nextChangeSoon(true);
  return;
 }

 // articleTitle is the wgTitle thingy with spaces and all that
 articleTitle=getFirstTagContent(items[i], 'title');
 // console.info('articleTitle=%s', articleTitle);

 if (recent2.ignore_safe_pages && recent2.safePagesRe.test(articleTitle)) {
  // console.warn('Ignoring safe page %s', article);
  nextChangeSoon(true); return;
 }

 if (recent2.hideNonArticles) {
  var nsName=articleTitle.replace(/:.*/, '').replace( / /g, '_' ).toLowerCase();
  if (mw.config.get('wgNamespaceIds')[nsName] &&
 ( ( recent2.showTemplates && mw.config.get('wgNamespaceIds')[nsName] !== /* Template */ 10 ) ||
  ! recent2.showTemplates )) {
   nextChangeSoon(true); return;
  }
 }

 // perhaps ignore talk pages
 if (! recent2.show_talkpages && articleTitle
   && /^Talk:|^[^:]*?[_ ]talk:/.test(articleTitle)) {
  nextChangeSoon(true); return;
 }

 // perhaps restrict to watchlist articles
 if (recent2.filter_watchlist && articleTitle &&
   ! window.watchlist[articleTitle.replace(/^Talk:/, '').replace(/[ _]talk:/, ':')]) {
  nextChangeSoon(true); return;
 }

 // filter against badwords regexp
 if (recent2.filter_badwords) {
  var badMatch=null;
  var diffCell=null;
  var previousVandal= window.vandals[editor];
  var matchesRe='';
  var matchesPlain='';
  diffCellRe.lastIndex=0;
  while (diffCell=diffCellRe.exec(diffText)) {
   // get content of addition table cells, faster than direct fulltext search
   badWords.lastIndex=0;
   // .test() is meant to be faster than a full match
   if (badMatch=badWords.test(diffCell[1])) {
    break;
   }
  }
  if (badMatch===true || previousVandal) {
   badWords.lastIndex=0;
   var reMatch;
   while (diffCell && (reMatch=badWords.exec(diffCell[1]))) {
    var badWord=reMatch[2] || reMatch[4] || reMatch[6] || '';
    // avoid legit article title occurrences
    if (articleTitle.toLowerCase().indexOf(badWord.toLowerCase())<0) {
     badWord=badWord.replace(/^\s+|\s+$/g, '');
     if (badWord!=='') {
      matchesPlain+=badWord+', ';
      badWord=badWord.replace(/([^\w ])/g, '\\$1');
      matchesRe+=badWord+'|';
     }
    }
   }
   matchesRe=matchesRe.replace(/\|$/, '');
   matchesPlain=matchesPlain.replace(/, $/, '');
   if (!previousVandal && matchesRe==='') { nextChangeSoon(); return; }
   // highlighting
   var highlighted=diffCell && diffCell[1];
   if (matchesRe) {
    highlighted=highlighted.replace(new RegExp('('+matchesRe+')', 'g'),
     '<span style="background-color: #FF6">$1</span>');
   }
   articleTitle=getFirstTagContent(items[i], 'title');
   // linkify
   highlighted=recent2.doLinkify(highlighted);
   diffText=recent2.doLinkify(diffText);

   if (previousVandal) {
    matchesPlain = mw.msg( 'avt-rolled-back', matchesPlain );
   }

   recent2.delayedLines[article]={
    timestamp: timestamp, article:article, count:recent2.count, articleTitle:articleTitle,
    editor:editor, badWord:matchesPlain, badDiffFragment:highlighted, diff:diffText, summary:editSummary
   };
  }
 } else if (recent2.filter_spelling) {
  var splMatch=null;
  while (diffCell=diffCellRe.exec(diffText)) {
   if (splMatch=spellRe.test(diffCell[1])) {
    break;
   }
  }
  if (splMatch) {
   splMatch = diffCell[1].match(spellRe);
   // .replace(/^\s*/, '');
   var misspelling = splMatch[1];
   var badWord = '<a href=\'javascript:recent2.correctSpelling("' + articleTitle.split('\'').join('%27') +
    '","'+misspelling.split('\'').join('%27')+'")\'>'+ misspelling + '</a>';
   diffText = diffText.replace(new RegExp('('+misspelling+')', 'gi'),
    '<span style="background-color: #FF6">$1</span>');
   // linkify
   diffText=recent2.doLinkify(diffText);
   recent2.delayedLines[article] = {
    timestamp: timestamp, article:article, count:recent2.count, articleTitle:articleTitle,
    editor:editor, badWord:badWord, badDiffFragment:'', diff:diffText, summary: editSummary
   };
  }
 } else {
  article=getFirstTagContent(items[i], 'link');
  articleTitle=getFirstTagContent(items[i], 'title');
  if (recent2.CustomFilter &&
   ! recent2.CustomFilter({timestamp:timestamp, article:article, articleTitle:articleTitle,
   editor:editor, diff:diffText, summary:editSummary})) { nextChangeSoon(); return; }
   // linkify
   diffText=recent2.doLinkify(diffText);
   recent2.delayedLines[article]={
   timestamp: timestamp, article:article, count:recent2.count, articleTitle:articleTitle,
   editor:editor, diff:diffText, summary:editSummary
  };
 }
 // schedule next iteration
 nextChangeSoon();
 return;
};



window.processRecentChangesDisplay=function(bundle){
 var output=recent2.getDelayedLineOutput();
 // console.log(output);
 var outputString='';
 if (recent2.outputPosition=='top') {
  outputString=output.join(recent2.outputSeparator);
 }
 else {
  for (var i=output.length-1; i>=0; --i) {
   outputString+=output[i] + (i>0 ? recent2.outputSeparator : '') ;
  }
 }
 bundle.output.innerHTML+=outputString;
 if (recent2.wait_for_output) { recent2.pauseOutput(); }
 setTimeout(function() {recent2.doPopups(bundle.output);}, 300);
 // overlap better than missing some out, i think; FIXME do this properly
 // - 1;
 processRecentChanges.lastDate=recent2.latest;
 var statusTail=greyFont + mw.msg( 'avt-done', formatTime( recent2.latest ) ) + '</span>';
 if (processRecentChanges.id > recent2.initialId) {
  statusTail+=' <a href="javascript:showHideDetailRange(' + recent2.initialId + ',' +
   processRecentChanges.id  + ')">' + mw.msg( 'avt-toggle-details' ) + '</a> |';
  if (recent2.autoexpand) {
   setTimeout( function() {
   /* document.title=initialId+' '+processRecentChanges.id; */
   showHideDetailRange(recent2.initialId, processRecentChanges.id); }, 250 );
  }
 }
 statusTail += ' <a href="javascript:deleteEarlierOutputDivs(' + bundle.status.id + ')">' + mw.msg( 'avt-remove-output' ) + '</a>';
 if (recent2.wait_for_output) {
  statusTail += ' | <a href="javascript:recent2.unpauseOutputOnce()">' + mw.msg( 'avt-show-new' ) + '</a>';
 }
 statusTail+='<br>';
 bundle.status.innerHTML+=statusTail;
 return;
};

// linkify and popupsify wikilinks
recent2.doLinkify=function(txt) {
 if (!txt || !recent2.linkify) { return txt; }

 var inheritColor='color:inherit;color:expression(parentElement.currentStyle.color)';
 var externalLinkStyle='text-decoration:none;';
 var internalLinkStyle='text-decoration:none;';

 externalLinkStyle=internalLinkStyle='text-decoration:none;border-bottom: 1px dotted;';

 txt=txt.replace(/((https?|ftp):(\/\/[^\[\]\{\}\(\)<>\s&=\?#%]+|<[^>]*>)+)/g, function (p,p1) {
  p1=p1.replace(/<[^>]*>/g, '');
  var url=encodeURI(p1);
  url=url.replace(/\"/g, '%22');
  url=url.replace(/\'/g, '%27');
  url=url.replace(/#/g, '%23');
  var ti=p1.replace(/\"/g, '&quot;');
  return('<a href="'+url+'" style="' + externalLinkStyle + inheritColor + '" title="'+ti+'">'+p+'</a>');
 });

 // BUG: doLinkify('[[123<span style="color:red">]] badword</span> blah blah')
 // gives '<a href=/wiki/123 ... >[[123<span style="color:red">]]</a> badword</span> blah blah'
 // and the browser closes the <span> inside the </a>, so the badword is not red!

 txt=txt.replace(/((\[\[)([^\|\[\]\{\}\n]*)([^\]\n]*)(\]\]))/g, function (p,p1,p2,p3) {
  p3=p3.replace(/<[^>]*>/g, '');
  var url=encodeURI(p3);
  url=url.replace(/\"/g, '%22');
  url=url.replace(/\'/g, '%27');
  url=url.replace(/#/g, '%23');
  url=recent2.articlePath+url;
  var ti=p3.replace(/\"/g, '&quot;');
  return('<a href="'+url+'" style="' + internalLinkStyle + inheritColor + '" title="'+ti+'">'+p+'</a>');
 });
 return(txt);
};

processRecentChanges.lastDate=0;
processRecentChanges.id=0;

recent2.getDelayedLineOutput=function() {
 var ret=[];
 var id=processRecentChanges.id;
 for (var a in recent2.delayedLines) {
  if (recent2.delayedLines[a] && typeof recent2.delayedLines[a].count == typeof 1 &&
   recent2.count - recent2.delayedLines[a].count >= recent2.delay) {
   recent2.delayedLines[a].id=id++;
   var line=(recent2.doLine(recent2.delayedLines[a]));
   if (line) { ret.push(line); }
   delete recent2.delayedLines[a];
  }
 }
 processRecentChanges.id=id;
 return ret;
};

window.deleteEarlierOutputDivs=function(cur) {
 for(var i=0; i<outputDivs.length; ++i) {
  if (!outputDivs[i] || !outputDivs[i].id) {
   continue;
  }
  if (outputDivs[i].id >= 0 && outputDivs[i].id < cur) {
   // FIXME BUG: if we go from the bottom up, then we'll delete one too many or too few, or something :-)
   outputDivs[i].parentNode.removeChild(outputDivs[i]);
   outputDivs[i]=null;
  }
 }
 // scroll to the top if we're appending output to the bottom, to keep the div we've clicked visible after the deletions
 if (recent2.outputPosition!='top') {
  document.location='#';
 }
};

window.showHideDetailRange=function(start,end) {
 // use the first div to see if we should show or hide
 var div=document.getElementById('diff_div_' + start);
 if (!div) {
  alert( mw.msg( 'avt-missing-div', start ) );
  return;
 }
 // hide
 var state=false;
 if (div.style.display=='none') {
  // show
  state=true;
 }
 for (var i=start; i<end; ++i) {
  showHideDetail(i, true, state);
 }
};

window.hideSysopEdits=function(hide) {
 var divs=document.getElementsByTagName('div');
 for (var i=0; i<divs.length; ++i) {
  if (divs[i].className=='sysop_edit_line') {
   divs[i].style.display= ( hide ? 'none' : 'inline' );
  }
 }
};

window.bundles={};

window.vandalColour = function(vandal) {
 var num=window.vandals[vandal];
 if (!num) {
  return '';
 }
 switch (num) {
 case 1: return '#DDFFDD';
 case 2: return '#BBFFBB';
 }
 var i= 9-(num - 3) *2;
 if (i < 0) {
  i=0;
 }
 return '#' + i + i + 'FF' + i + i;
};

recent2.pendingLines=[];

recent2.unpauseOutputOnce=function() {
 // console.log('unpausing once');
 if (recent2.pausedOutput) {
  recent2.togglePausedOutput();
  recent2.togglePausedOutput();
 }
};

recent2.pauseOutput=function() {
 // console.log('pausing');
 if (!recent2.pausedOutput) { recent2.togglePausedOutput(); }
 // console.log(recent2.pausedOutput);
};

recent2.unpauseOutput=function() {
 // console.log('unpausing');
 if (recent2.pausedOutput) { recent2.togglePausedOutput(); }
 // console.log(recent2.pausedOutput);
};

recent2.togglePausedOutput=function() {
 if (!recent2.pausedOutput) {
  recent2.pausedOutput = true;
  return true;
 } else {
  recent2.pausedOutput=false;
 }
 var outputBuffer='';
 while (recent2.pendingLines.length) {
  outputBuffer+=recent2.doLine(recent2.pendingLines.pop());
  if (recent2.pendingLines.length) { outputBuffer+=recent2.outputSeparator; }
 }
 var pos=recent2.outputPosition;
 var output=newOutputDiv('recent2.lines', pos);
 output.innerHTML=outputBuffer;
 setTimeout(function() {recent2.doPopups(output);}, 300);
 return false;
};

recent2.togglePaused=function() {
 if(!recent2.paused) { recent2.paused=true; return true; }
 recent2.paused=false;
 loopRecentChanges(loopRecentChanges.url, loopRecentChanges.iterations);
 return false;
};

recent2.doLine=function(bundle) {
 if (recent2.pausedOutput) {
  recent2.pendingLines.push(bundle);
  return '';
 }
 // if (recent2.filter_spelling) {
  // return recent2.doSpellLine(bundle);
 // }
 var sysop = null;
 if (typeof(recent2.sysopRegExp != 'undefined')) {
  sysop=recent2.sysopRegExp.test(bundle.editor);
 }
 var lastDiffPage=bundle.article + '&diff=cur&oldid=prev';
 bundle.url=lastDiffPage;
 saveBundle(bundle);

 var div='';
 var group='';
 if (window.vandals[bundle.editor]) {
  if (window.vandals[bundle.editor] > 0) {
   div='<div style="background-color:' + vandalColour(bundle.editor) + '">';
  }
 }
 else if (sysop) {
  group = ' <i>(Admin)</i>';
  if (recent2.hide_sysop_edits) {
   div='<div class="sysop_edit_line" style="display: none;">';
  }
  else {
   div='<div class="sysop_edit_line">';
  }
 }
 return(
  div +
  '<li>' +
  '[<a href="javascript:showHideDetail(' + bundle.id + ')" id="showdiff_link_' + bundle.id + '">' + mw.msg( 'avt-show' ) + '</a>] ' +
  formatTime(bundle.timestamp) + ' ' +
  // latest + ' ' + processRecentChanges.lastDate + ' ' +
  '(' + linkmaker( lastDiffPage, mw.msg( 'avt-last' ) ) + ')' +
  ' (' + linkmaker( bundle.article + '&action=history', mw.msg( 'avt-hist' ) ) + ')' +
  ' ' + linkmaker(bundle.article, bundle.articleTitle) +
  ( bundle.badWord ? mw.msg( 'avt-matched', bundle.badWord ) : '') + ' . . ' +
  linkmaker(recent2.articlePath + 'User:' + bundle.editor, bundle.editor) +
  group + ' (' +
  linkmaker(recent2.articlePath + 'User_talk:' + bundle.editor, mw.msg( 'avt-talk' ) ) + ' | ' +
  linkmaker(recent2.articlePath + 'User_talk:' + bundle.editor + '?action=edit' +
   '&avtautoedit=s♫$♫\\n{'+'{subst:uw-test1|' + bundle.articleTitle +
   '}}%20~~' + '~~♫&avtautosummary=Your%20recent%20edits%20to%20[[' + bundle.articleTitle + ']]',
   mw.msg( 'avt-uw-test' ) ) + ' | ' +
  linkmaker(recent2.articlePath + 'User_talk:' + bundle.editor + '?action=edit' +
   '&avtautoedit=s♫$♫\\n{'+'{subst:uw-vandalism1|' + bundle.articleTitle +
   '}}%20~~' + '~~♫&avtautosummary=Your%20recent%20edits%20to%20[[' + bundle.articleTitle + ']]',
   mw.msg( 'avt-uw-vand' ) )     + ' | ' +
  linkmaker(recent2.articlePath + 'Special:Contributions/' + bundle.editor, mw.msg( 'avt-contribs' ) ) + ' | ' +
  linkmaker(recent2.articlePath + 'Special:Blockip/' + bundle.editor, mw.msg( 'avt-block' ) ) + ') . . ' +
  ( bundle.summary ? '<i>('+bundle.summary+')</i> . . ' : '') +
  '[<a href="javascript:tryRollback(' + bundle.id + ')" class="recent2_rollback">' + mw.msg( 'avt-rollback' ) + '</a>]' +
  '<p><div id="diff_div_' + bundle.id + '" style="display: none">' +
  '</div></li>' +
  ( div ? '</div>' : '')
 );
};

recent2.correctSpelling=function (article, badword) {
 var url=recent2.articlePath + article + '?action=edit&avtautoclick=wpDiff&avtautominor=true';
 var wl=badword.toLowerCase();
 var cor=spelldict[wl];
 var c0, wl0, b;
 if (!cor|| !cor.length) {
  alert( mw.msg( 'avt-entry-not-found', wl ) );
  return;
 }
 if (cor.length > 1) {
  var q= mw.msg( 'avt-select-correction' );
  for (var i=0; i<cor.length; ++i) { q += '\n' + i + ': ' + cor[i]; }
  var ans=prompt(q);
  if (!ans) {return;}
  var num=parseInt(ans, 10);
  if (num > -1 && num < cor.length) { cor = cor[num]; }
  else { cor = ans; }
 } else {
  cor = cor[0];
 }
 cor=cor.replace(/^ *| *$/g, '');
 url += '&avtautosummary=Randomly%20fixing%20recent%20typos%20with%20Lupins%20spellchecking%20tool:%20' + wl + '->' + cor;
 url += '&avtautoedit=';
 c0=cor.charAt(0);
 wl0 = wl.charAt(0);
 b='\\b';
 // s♫\bexample\b♫test♫g;
 url += ['s', b + wl + b, cor, 'g;'].join('♫');
 wl=wl0.toUpperCase() + wl.substring(1);
 cor=c0.toUpperCase() + cor.substring(1);
 // s♫\bExample\b♫Test♫g;
 url += ['s', b + wl + b, cor, 'g;'].join('♫');
 wl=wl.toUpperCase();
 cor=cor.toUpperCase();
 // s♫\bEXAMPLE\b♫TEST♫g;
 url += ['s', b + wl + b, cor, 'g;'].join('♫');
 window.open(url);
};

window.saveBundle= function(bundle) {
 var z={};
 for (var prop in bundle) { z[prop]=bundle[prop]; }
 window.bundles[bundle.id]=z;
};

window.vandals={};

window.tryRollback=function(id) {
 if (recent2.non_admin_rollback) { recent2.tryNonAdminRollback(id); }
 else { recent2.tryAdminRollback(id); }
};

recent2.getBundleVandal=function(id) {
 var b=window.bundles[id];
 if (!b) {
  alert( mw.msg( 'avt-error-no-bundle' ) );
  return null;
 }
 var vandal=b.editor;
 if (window.vandals[vandal]===undefined) {
  window.vandals[vandal]=1;
 } else {
  window.vandals[vandal]++;
 }
 return b;
};

recent2.tryAdminRollback=function(id){
 var b=recent2.getBundleVandal(id);
 if (!b) { return; }
 var vandal=b.editor;
 var onSuccess=function (x, bundle) {
  // FIXME: This will fail if wgScript is not "/w/index.php" or if the link has a class before href, etc...
  // Use API instead?
  var rollRe=/<a href="(\/w\/index\.php[^"]*?action=rollback[^"]*?from=([^&]*)[^"]*?)".*?(<span class="comment">(.*?)<\/span>)?/;
  // match[0]: useless
  // match[1]: url (escaped)
  // match[2]: last editor (escaped)
  // match[4]: last edit summary (wikiText - FIXME strip this to plain text)
  var match=rollRe.exec(x.responseText);
  if (!match) {
   alert( mw.msg( 'avt-error-no-rollback-link' ) );
   return;
  }
  var lastEditor=match[2].split('+').join(' ');
  var lastSummary=match[4] || '';
  if (lastEditor != vandal) {
   var summary=lastSummary.replace( /<[^>]*?>/g, '' );
   if (!summary) {
    summary=lastSummary;
   }
   alert( mw.msg( 'avt-error-unable-to-rollback', b.articleTitle, vandal, lastEditor, summary ) );
   return;
  }
  var rollbackUrl=match[1].split('&amp;').join('&');
  recent2.openBackgroundWindow(rollbackUrl);
 };
 var onFailure = function(x,bundle) {
  alert( mw.msg( 'avt-error-HTTP-rollback', bundle.url, x.statusText ) );
  return true;
 };
 recent2.download({ url:b.url, onSuccess: onSuccess, id: b.id, onFailure:onFailure});
};

recent2.backgroundWindows = [];
recent2.openBackgroundWindow = function(url) {
 var newWindow = window.open(url);
 self.focus();
 recent2.backgroundWindows.push(newWindow);
 if (recent2.backgroundWindows.length > recent2.backgroundWindowsMax) {
  if (!recent2.backgroundWindows[0].closed) {
   recent2.backgroundWindows[0].close();
   recent2.backgroundWindows.shift();
  }
 }
 return;
};

recent2.tryNonAdminRollback=function(id) {
 var b=recent2.getBundleVandal(id);
 if (!b) { return; }
 var url=recent2.scriptPath + 'api.php?action=query&format=json&titles=' + b.articleTitle + '&prop=revisions&rvlimit=30';
 var onSuccess=function(x,y){ recent2.processHistoryQuery(x,y,b); };
 // fixme: onFailure
 recent2.download({ url: url, onSuccess: onSuccess, id: b.id});
};

recent2.processHistoryQuery=function(x,downloadBundle, bundle) {
 var json=x.responseText, edits;
 try {
  // FIXME: Eval is evil
  eval('var o='+json);
  // FIXME: Use indexpageids=1 on API
  edits=recent2.anyChild(o.query.pages).revisions;
 } catch ( someError ) {
  alert( mw.msg( 'avt-error-JSON', json.substring( 0, 200 ) ) );
  return;
 }
 var i;
 for (i=0; i<edits.length; ++i) {
  if (edits[i].user!=bundle.editor) { break; }
 }
 if (i===0) {
  alert( mw.msg( 'avt-error-unable-to-rollback', bundle.articleTitle, bundle.editor, edits[0].user, edits[0].comment ) );
  return;
 }
 if (i==edits.length) {
  alert( mw.msg( 'avt-rollback-aborted', bundle.editor, bundle.articleTitle ) ); return;
 }
 var prevEditor=edits[i].user;
 var prevRev=edits[i].revid;
 var summary= mw.msg( 'avt-reverted-edits', escape(bundle.editor), escape(prevEditor) );
 summary=summary.split(' ').join('%20');
 var url=bundle.article + '&action=edit&avtautosummary=' + summary + '&oldid=' + prevRev +
  '&avtautoclick=wpSave&avtautominor=true&avtautowatch=false';
 recent2.openBackgroundWindow(url);
};

recent2.anyChild=function(obj) {
 for (var p in obj) {
  return obj[p];
 }
 return null;
};

recent2.doPopups=function(div) {
 if (typeof(window.setupTooltips)!='undefined') { setupTooltips(div); }
};

window.formatTime=function(timestamp) {
 var date=new Date(timestamp);
 var nums=[date.getHours(), date.getMinutes(), date.getSeconds()];
 for (var i=0; i<nums.length; ++i) {
  if (nums[i]<10) {
   nums[i]='0'+nums[i];
  }
 }
 return nums.join(':');
};

window.showHideDetail = function(id, force, state) {
 var div=document.getElementById('diff_div_' + id);
 var lk=document.getElementById('showdiff_link_' + id);
 if (!div) {
  return;
 }
 var bundle=window.bundles[id];
 if (!div.innerHTML) {
  div.innerHTML= ( bundle.badDiffFragment ? bundle.badDiffFragment:'') + bundle.diff;
 }
 if ((force && state===true) || (!force && div.style.display=='none')) {
  div.style.display='inline';
  lk.innerHTML = mw.msg( 'avt-hide' );
 } else {
  div.style.display='none';
  lk.innerHTML = mw.msg( 'avt-show' );
 }

};

window.getFirstTagContent=function(parent, tag) {
 var e=parent.getElementsByTagName(tag);
 if (e && (e=e[0]) ) {
  var ret = e.firstChild.nodeValue || e.nodeValue;
  if (typeof ret != typeof '') {
   return '';
  }
  return ret;
 }
};

recent2.newCell=function() {
 var numCols=3;

 var c=recent2.controls;
 if (!c) { return; }
 if (!c.cellCount) {
  // start a table
  c.cellCount = 0;
  c.table=document.createElement('table');
  c.appendChild(c.table);
  c.tbody=document.createElement('tbody');
  c.table.appendChild(c.tbody);
 }
 if (c.cellCount % numCols === 0) {
  // start a row
  c.curRow=document.createElement('tr');
  c.tbody.appendChild(c.curRow);
 }
 // start a cell
 c.curCell=document.createElement('td');
 c.curRow.appendChild(c.curCell);
 ++c.cellCount;
};

recent2.newCheckbox=function(label, state, action, internalName, append) {
 // checkbox
 recent2.newCell();
 var ret=document.createElement('input');
 ret.type='checkbox';
 ret.checked = state;
 ret.onclick = function() { recent2.setBoxCookies(); this.setVariables(); };
 ret.setVariables = action;
 recent2.controls.curCell.appendChild(ret);
 if (internalName) { recent2.controls[internalName]=ret; }
 // label
 var l=document.createElement('label');
 l.innerHTML=label;
 l.onclick=function(){ ret.click(); };
 // recent2.controls.appendChild(l);
 recent2.controls.curCell.appendChild(l);
 recent2.checkboxes.push(ret);
 return ret;
};

recent2.checkboxes=[];

recent2.setBoxCookies=function() {
 var n=1;
 var val=0;
 for (var i=0; i<recent2.checkboxes.length; ++i) {
  val += n * (recent2.checkboxes[i].checked ? 1 : 0);
  n = n << 1;
 }
 document.cookie = 'recent2_checkboxes='+val+'; expires=Tue, 31-Dec-2030 23:59:59 GMT; path=/';
};

recent2.setCheckboxValuesFromCookie=function() {
 var val=recent2.readCookie('recent2_checkboxes');
 if (!val) { return; }
 val=parseInt(val, 10);
 for (var i=0; i<recent2.checkboxes.length; ++i) {
  if ( recent2.checkboxes[i].checked != (val & 1) ) {
   recent2.checkboxes[i].checked= (val & 1);
   recent2.checkboxes[i].setVariables();
  }
  val = val >> 1;
 }
};

recent2.readCookie=function(name) {
 var nameEQ = name + '=';
 var ca = document.cookie.split(';');
 for(var i=0;i < ca.length;i++) {
  var c = ca[i];
  while (c.charAt(0)==' ') { c = c.substring(1,c.length); }
  if (c.indexOf(nameEQ) === 0) { return c.substring(nameEQ.length,c.length); }
 }
 return null;
};

recent2.controlUI=function() {
 recent2.controls=newOutputDiv('recent2.controls', 'top', true);

 // control presets, will be changed by saved cookie settings
 recent2.show_talkpages = true;
 recent2.hideNonArticles = false;
 recent2.showTemplates = false;
 recent2.autoexpand = false;
 recent2.delay_preset = false;
 recent2.non_admin_rollback = !recent2.userIsSysop;
 recent2.ignore_my_edits = false;
 recent2.ignore_safe_pages = false;
 recent2.hide_sysop_edits = false;

 // create controls
 recent2.newCheckbox( mw.msg( 'avt-ignore-talk-pages' ), !recent2.show_talkpages,
   function() { recent2.show_talkpages=!this.checked; }, 'talk');
 recent2.newCheckbox( mw.msg( 'avt-ignore-outside-main' ), recent2.hideNonArticles,
   function() { recent2.hideNonArticles = this.checked; }, 'hidenonarticles');
 recent2.newCheckbox( mw.msg( 'avt-except-templates' ), recent2.showTemplates,
   function() { recent2.showTemplates = this.checked; }, 'showtemplates');
 recent2.newCheckbox( mw.msg( 'avt-expand-content' ), recent2.autoexpand,
   function() { recent2.autoexpand = this.checked; }, 'autoexpand');
 recent2.newCheckbox( mw.msg( 'avt-only-unchanged' ), recent2.delay_preset,
   function() { recent2.delay = (this.checked) ? 4 : 0; }, 'delayby4');
 recent2.newCheckbox( mw.msg( 'avt-non-admin-rollback' ), recent2.non_admin_rollback,
   function() { recent2.non_admin_rollback = this.checked; }, 'nonadminrollback');
 recent2.newCheckbox( mw.msg( 'avt-ignore-my-edits' ), recent2.ignore_my_edits,
   function() { recent2.ignore_my_edits = this.checked; }, 'ignoremyedits');
 recent2.newCheckbox( mw.msg( 'avt-ignore-safe-pages' ), recent2.ignore_safe_pages,
   function() { recent2.ignore_safe_pages = this.checked; }, 'ignoresafepages');
 recent2.newCheckbox( mw.msg( 'avt-ignore-sysop-edits' ), recent2.hide_sysop_edits,
   function() { recent2.hide_sysop_edits = this.checked; hideSysopEdits(recent2.hide_sysop_edits); }, 'hidesysopedits');

 var b=document.createElement('input');
 b.type='button';
 b.value = mw.msg( 'avt-pause' );
 b.onclick=function(){
  b.value = recent2.paused ? mw.msg( 'avt-pause' ) : mw.msg( 'avt-resume' );
  recent2.togglePaused();
 };
 recent2.newCell();
 recent2.controls.curCell.appendChild(b);
 recent2.setCheckboxValuesFromCookie();
};

recent2.count=0;
window.loopRecentChanges=function(url, iterations) {
 if (!iterations) {
  iterations=20;
 }
 loopRecentChanges.iterations=iterations;
 loopRecentChanges.url=url;
 grabRecentChanges(url);
 setTimeout(function () {
  if (recent2.paused) {++recent2.count; return; }
  if (++recent2.count >= iterations && ! confirm( mw.msg( 'avt-continue-question' ) ) ) {
   return;
  }
  recent2.count %= iterations; loopRecentChanges(url, iterations);
 }, recent2.updateSeconds * 1000);
};

window.marvin=function() {

 // check if user is a sysop
 recent2.userIsSysop = $.inArray('sysop', mw.config.get( 'wgUserGroups' )) !== -1;

 // set chunk size for sysop list
 if (recent2.userIsSysop) {
  recent2.apiAulimit = recent2.apiAulimitSysop;
 } else {
  recent2.apiAulimit = recent2.apiAulimitUser;
 }

 // setup checkboxes
 recent2.controlUI();

 // start fetching recent changes
 mw.loader.using( 'mediawiki.diff.styles', function(){
  loopRecentChanges(recent2.feed, 1000);
 } );
};

// get the full sysop list in chunks
recent2.getSysops = function(startUser) {
 recent2.gettingSysops = true;
 var param = '';
 if (typeof(startUser) == 'string') {
  param = '&aufrom=' + encodeURIComponent(startUser);
 }
 recent2.download({
  url: recent2.scriptPath + 'api.php?action=query&list=allusers&augroup=sysop&aulimit=' + recent2.apiAulimit + '&format=json' + param,
  onSuccess: recent2.processSysops,
  onFailure: function() { setTimeout(recent2.getSysopList, 15000); return true;}
 });
};

recent2.sysopList = '';
recent2.processSysops = function(s) {
 var json = s.responseText, users;
 try {
  // FIXME: Eval is evil
  eval('var o = ' + json);
  users = o.query.allusers;
 }
 catch(someError) {
  alert( mw.msg( 'avt-error-sysop-list', json.substring( 0, 400 ) ) );
  return;
 }
 for (var i = 0; i < users.length; i++) {
  if (recent2.sysopList !== '') {
   recent2.sysopList += '|';
  }
  recent2.sysopList += users[i].name.replace(/(\W)/g, '\\$1');
 }
 if (users.length < recent2.apiAulimit) {
  recent2.sysopRegExp = new RegExp( '\\b(' + recent2.sysopList + ')\\b' );
 }
 else {
  recent2.getSysops(users[recent2.apiAulimit - 1].name);
 }
 return;
};

// **************************************************
// Installation
// **************************************************

window.addMarvin=function() {
 mw.util.addPortletLink( 'p-tb', mw.util.getUrl( recent2.filterPage ),
  mw.msg( 'avt-filter-rc' ), 'toolbox_filter_changes');
 mw.util.addPortletLink( 'p-tb', mw.util.getUrl( recent2.allRecentPage ),
  mw.msg( 'avt-all-rc' ), 'toolbox_all_changes');
 mw.util.addPortletLink( 'p-tb', mw.util.getUrl( recent2.recentIPPage ),
  mw.msg( 'avt-ip-rc' ), 'toolbox_IP_edits');
 mw.util.addPortletLink( 'p-tb', mw.util.getUrl( recent2.monitorWatchlistPage ),
  mw.msg( 'avt-watched-rc' ), 'toolbox_watchlist_edits');
 mw.util.addPortletLink( 'p-tb', mw.util.getUrl( recent2.liveSpellcheckPage ),
  mw.msg( 'avt-spelling-rc' ), 'toolbox_spelling');
};

window.maybeStart=function() {
 switch (mw.config.get('wgPageName')) {
 case recent2.filterPage:
  recent2.filter_badwords=true;
  break;
 case recent2.allRecentPage:
  recent2.filter_badwords=false;
  break;
 case recent2.recentIPPage:
  recent2.filter_anonsOnly=true;
  break;
 case recent2.monitorWatchlistPage:
  recent2.filter_watchlist=true;
  break;
 case recent2.liveSpellcheckPage:
  recent2.filter_spelling=true;
  break;
 default:
  return;
 }
 setTimeout(marvin, 1000);
};

/**
 * autoedit code, streamlined from User:Lupin/autoedit.js, added autowatch
 * User:Lupin/autoedit.js is no longer needed
 */

recent2.substitute = function(data,cmdBody) {
 // alert('sub\nfrom: ' + cmdBody.from + '\nto: ' + cmdBody.to + '\nflags: ' + cmdBody.flags);
 var fromRe = new RegExp(cmdBody.from, cmdBody.flags);
 return data.replace(fromRe, cmdBody.to);
};

recent2.execCmds = function(data, cmdList) {
 for (var i = 0; i<cmdList.length; ++i) {
  data = cmdList[i].action(data, cmdList[i]);
 }
 return data;
};

recent2.parseCmd = function(str) {
 // returns a list of commands
 if (!str.length) {
  return [];
 }
 var p = false;
 switch (str.charAt(0)) {
 case 's':
  p = recent2.parseSubstitute(str);
  break;
 case 'j':
  p = recent2.parseJavascript(str);
  break;
 default:
  return false;
 }
 if (p) {
  return [p].concat(recent2.parseCmd(p.remainder));
 }
 return false;
};

recent2.unEscape = function(str, sep) {
 return str.split('\\\\').join('\\')
  .split('\\' + sep).join(sep)
  .split('\\n').join('\n');
};


recent2.runJavascript = function(data, argWrapper) {
 // flags aren't used (yet)

 // from the user's viewpoint,
 // data is a special variable may appear inside code
 // and gets assigned the text in the edit box

 // alert('eval-ing ' + argWrapper.code);

 return eval(argWrapper.code);
};

recent2.parseJavascript = function(str) {
 // takes a string like j/code/;othercmds and parses it

 var tmp, code, flags;

 if (str.length<3) {
  return false;
 }
 var sep = str.charAt(1);
 str = str.substring(2);

 tmp = recent2.skipOver(str, sep);
 if (tmp) {
  code = tmp.segment.split('\n').join('\\n');
  str = tmp.remainder;
 } else {
  return false;
 }

 flags = '';
 if (str.length) {
  tmp = recent2.skipOver(str, ';') || recent2.skipToEnd(str, ';');
  if (tmp) {flags = tmp.segment; str = tmp.remainder; }
 }

 return { action: recent2.runJavascript, code: code, flags: flags, remainder: str };
};

recent2.parseSubstitute = function(str) {
 // takes a string like s/a/b/flags;othercmds and parses it

 var from, to, flags, tmp;

 if (str.length<4) {
  return false;
 }
 var sep = str.charAt(1);
 str = str.substring(2);

 tmp = recent2.skipOver(str, sep);
 if (tmp) {
  from = tmp.segment;
  str = tmp.remainder;
 } else {
  return false;
 }

 tmp = recent2.skipOver(str, sep);
 if (tmp) {
  to = tmp.segment;
  str = tmp.remainder;
 } else {
  return false;
 }

 flags = '';
 if (str.length) {
  tmp = recent2.skipOver(str, ';') || recent2.skipToEnd(str, ';');
  if (tmp) {flags = tmp.segment; str = tmp.remainder; }
 }

 return {action: recent2.substitute, from: from, to: to, flags: flags, remainder: str};
};

recent2.skipOver = function(str, sep) {
 var endSegment = recent2.findNext(str, sep);
 if (endSegment<0) {
  return false;
 }
 var segment = recent2.unEscape(str.substring(0, endSegment), sep);
 return {segment: segment, remainder: str.substring(endSegment + 1)};
};

recent2.skipToEnd = function(str, sep) {
 return {segment: str, remainder: ''};
};

recent2.findNext = function(str, ch) {
 for (var i = 0; i<str.length; ++i) {
  if (str.charAt(i) == '\\') {
   i += 2;
  }
  if (str.charAt(i) == ch) {
   return i;
  }
 }
 return -1;
};

var AVTAutoEditLoader = function() {

 if (typeof(window.AVTAutoEdit) != 'undefined') {
  if (window.AVTAutoEdit.alreadyRan) {
   return false;
  }
 } else {
  window.AVTAutoEdit = {};
 }
 window.AVTAutoEdit.alreadyRan = true;
 var editbox, cmdString = mw.util.getParamValue('avtautoedit');
 if (cmdString) {
  try {
   editbox = document.editform.wpTextbox1;
  } catch (dang) { return; }
  var cmdList = recent2.parseCmd(cmdString);
  var input = editbox.value;
  var output = recent2.execCmds(input, cmdList);
  editbox.value = output;
  // wikEd user script compatibility
  if (typeof(wikEdUseWikEd) != 'undefined') {
   if (wikEdUseWikEd === true) {
    /*jshint newcap: false*/
    WikEdUpdateFrame();
    /*jshint newcap: true*/
   }
  }
 }

 var summary = mw.util.getParamValue('avtautosummary');
 if (summary) {
  document.editform.wpSummary.value = summary;
 }

 var minor = mw.util.getParamValue('avtautominor');
 if (minor) {
  switch (minor) {
  case '1':
  case 'yes':
  case 'true':
   document.editform.wpMinoredit.checked = true;
   break;
  case '0':
  case 'no':
  case 'false':
   document.editform.wpMinoredit.checked = false;
  }
 }

 var watch = mw.util.getParamValue('avtautowatch');
 if (watch) {
  switch (watch) {
  case '1':
  case 'yes':
  case 'true':
   document.editform.wpWatchthis.checked = true;
   break;
  case '0':
  case 'no':
  case 'false':
   document.editform.wpWatchthis.checked = false;
  }
 }

 var btn = mw.util.getParamValue('avtautoclick');
 if (btn) {
  if (document.editform && document.editform[btn]) {
   var headings = document.getElementsByTagName('h1');
   if (headings) {
    var div = document.createElement('div');
    var button = document.editform[btn];
    div.innerHTML = '<span style="font-size: 115%; font-weight: bold;">' +
     mw.msg( 'avt-auto-click', button.value ) + '</span>';
    document.title = '(' + document.title + ')';
    headings[0].parentNode.insertBefore(div, headings[0]);
    button.click();
   }
  } else {
   alert( mw.msg( 'avt-auto-click-button-missing', btn ) );
  }
 }
};

mw.loader.using( [ 'mediawiki.util', 'mediawiki.util' ], function(){
 // onload
 $( maybeStart );
 $( addMarvin );
 $( AVTAutoEditLoader );
} );

// </nowiki></pre>

Retrieved from "https://en.wikipedia.org/w/index.php?title=User:Nick_Moyes/recent2test.js&oldid=933538929"





This page was last edited on 1 January 2020, at 16:40 (UTC).

Text is available under the Creative Commons Attribution-ShareAlike License 4.0; additional terms may apply. By using this site, you agree to the Terms of Use and Privacy Policy. Wikipedia® is a registered trademark of the Wikimedia Foundation, Inc., a non-profit organization.



Privacy policy

About Wikipedia

Disclaimers

Contact Wikipedia

Code of Conduct

Developers

Statistics

Cookie statement

Mobile view



Wikimedia Foundation
Powered by MediaWiki