User:Ale jrb/Scripts/iglooMain.js
//
/* ======================================================== *\
- igloo frontend manager - main
\* ======================================================== */
/*
fixes:
- fixed a bug that prevented igloo from intercepting and blocking some key presses in Google Chome.
- fixed a bug that caused text size issues in the vector skin - igloo will now more aggressively defend its CSS.
- fixed a bug where igloo would occasionally wait much longer than was necessary after loading data from iglooNet before proceeding.
- fixed a bug where page titles containing more than one apostrophe could not be clicked on in the recent changes feed.
- fixed an initial filter error where only one condition would be checked.
- fixed a bug where igloo did not display total sessions correctly.
changes:
- implemented the filter system.
- added settings for controlling filters.
- created the default filters for general use.
- make several improvements to the profanity highlighter.
behind the scenes:
- altered iglooNet to be able to stream filters.
- introduced the ID system.
- /
function iglooMain () {
this.internalCounter = 0;
this.iglooBase = new wa_document ();
this.launch = function ( details ) {
switch ( this.internalCounter ) {
default: case 0:
this.startload = new Date ();
this.canDebug = ( typeof console !== 'undefined' );
wa_window.prototype = new wa_document;
wa_element.prototype = new wa_document;
// step 1 of launching: build the loading interface.
var t = 'igloo - ' + iglooSettings.versionString;
var t2 = '';
for ( var i = 0; i < wgUserGroups.length; i ++ ) {
if ( wgUserGroups[i] == 'steward' ) { t2 += 'steward|'; }
else if ( wgUserGroups[i] == 'oversight' ) { t2 += 'oversighter|'; }
else if ( wgUserGroups[i] == 'checkuser' ) { t2 += 'checkuser|'; }
else if ( wgUserGroups[i] == 'bureaucrat' ) { t2 += 'bureaucrat|'; }
else if ( wgUserGroups[i] == 'sysop' ) { t2 += 'administrator|'; iglooSettings.mesysop = true; }
else if ( wgUserGroups[i] == 'rollbacker' ) { t2 += 'rollback|'; }
}
if ( t2 !== '' ) t += ' [wiki:' + t2.substr ( 0, t2.length - 1 ) + ']';
//t += ' [igloo:' + iglooSettings.iglooFlags + ']';
document.title = t;
iglooSettings.userGroup = t2.substr ( 0, t2.length - 1 );
this.iglooBase.wk_base.innerHTML= ''; // just destroy the mediawiki page content
this.iglooInterface = new wa_window ( this.iglooBase.wk_base );
this.iglooInterface.win_bg = '#ededff';
this.iglooInterface.win_maintfill = false;
this.iglooInterface.win_fill = true;
this.iglooInterface.applyAll ();
// step 2 of launching: add text.
this.iglooLoading = new wa_window ( this.iglooBase.wk_base );
this.iglooLoading.win_width = 210;
this.iglooLoading.win_height= 17;
this.iglooLoading.win_bd = '#bbbbff';
this.iglooLoading.win_bd_wd = 1;
this.iglooLoading.win_bg = '#fdfdff';
this.iglooLoading.win_content = '
this.iglooLoading.applyAll ();
this.iglooLoading.center ( 'both', true, new Array ( 0, -100 ) );
// step 3 of launching: verify session.
this.iglooSession = new iglooSecurity ();
if ( typeof this.iglooSession.shutdown != 'undefined' ) return false;
this.iglooSession.verifySession ( 'initial' );
// increment counter
this.internalCounter ++;
break;
case 1:
// step 4 of launching: the session is verified, tell the user.
this.iglooLoading.win_width = 330;
this.iglooLoading.win_content = '
this.iglooLoading.applyAll ();
this.iglooLoading.center ( 'both', true, new Array ( 0, -100 ) );
// increment counter
this.internalCounter ++;
// run
this.iglooNet = new iglooNet ();
this.iglooNet.retrieve ( true );
break;
case 2:
// step 5 of lauching: load the user settings
this.iglooLoading.win_width = 180;
this.iglooLoading.win_content = '
this.iglooLoading.applyAll();
this.iglooLoading.center ( 'both', true, new Array ( 0, -100 ) );
// increment counter
this.internalCounter ++;
// run
this.iglooManageSettings = new iglooManageSettings ();
this.iglooManageSettings.retrieve ();
break;
case 3:
// adjust title now that the settings have loaded and we know the iglooNet permissions
document.title = document.title + ' [igloo:' + iglooSettings.iglooFlags + ']';
// display first run if relevant
// increment counter
this.internalCounter ++;
if ( iglooSettings.firstRun == true ) {
var url = iglooSettings.remoteHost + 'main.php?action=settings&do=set&session='+igloo.iglooSession.session+'&me='+encodeURIComponent(wgUserName)+'&setting=firstRun&value=false';
iglooImport( url, true, 'iglooFirstRun' );
wa ( ':api' ).get ( 'ig_firstrun', iglooSettings.localBase + 'config', 1 ).wait ( function () {
var firstruntext = wa ( ':api' ).results ['ig_firstrun']['query']['pages']['page']['revisions']['rev']['#text'], regTest = /firstrun:(.+?);;/i, o;
firstruntext = regTest.exec ( firstruntext );
firstruntext = firstruntext[1].replace ( '%CURRENTUSER%', wgUserName );
igloo.iglooLoading.win_width = 900;
igloo.iglooLoading.win_height = 400;
igloo.iglooLoading.win_content = firstruntext;
igloo.iglooLoading.applyAll ();
igloo.iglooLoading.center ( 'both', true );
} ).run ();
} else { this.launch (); }
break;
case 4:
// finalising launch: the session is verified, tell the user.
this.iglooLoading.win_width = 210;
this.iglooLoading.win_height= 17;
this.iglooLoading.win_content = '
this.iglooLoading.applyAll ();
this.iglooLoading.center ( 'both', true, new Array ( 0, -100 ) );
// preload images
if ( iglooSettings.preloadInterface === true ) {
var images = new Array ( 'logo', 'back', 'back-grey', 'forward', 'forward-grey', 'hist', 'revert', 'settings', 'go' ), images2 = new Array ();
for ( var i = 0, l = images.length; i < l; i ++ ) {
images2 [i] = new Image ();
images2 [i].src = iglooSettings.remoteHost + 'images/igloo-' + images [i] + '.png';
}
}
// increment counter
this.internalCounter ++;
// run
setTimeout( "igloo.launch ();", 750 );
break;
case 5:
this.endload = new Date ();
// start the required program elements. log if possible.
this.iglooDiff = new iglooDiff ();
this.iglooDiff.start ();
if ( this.canDebug === true ) console.log ( 'igloo: started diff component' );
this.iglooStatus = new iglooStatus ();
this.iglooStatus.start ();
if ( this.canDebug === true ) console.log ( 'igloo: started status component' );
this.iglooControls = new iglooControls ();
this.iglooControls.start ();
if ( this.canDebug === true ) console.log ( 'igloo: started control component' );
this.iglooChanges = new iglooChanges ();
this.iglooChanges.start ();
if ( this.canDebug === true ) console.log ( 'igloo: started changes component' );
this.iglooPopup = new iglooPopup ();
this.iglooPopup.start ();
if ( this.canDebug === true ) console.log ( 'igloo: started popup component' );
this.iglooActions = new iglooActions ();
if ( this.canDebug === true ) console.log ( 'igloo: started actions component' );
this.iglooManageSettings.start ();
if ( this.canDebug === true ) console.log ( 'igloo: started settings component' );
// hide the loading element
this.iglooLoading.hide ();
if ( this.canDebug === true ) console.log ( 'igloo: completed load!' );
break;
}
}
this.shutdown = function ( reason, retry ) {
if (reason == null) { reason = ''; } else { reason = '
'+reason; }
if (retry == 'retry') { reason += '
retry | help'; }
if (retry == 'tryagain') { reason += '
new session'; }
if ( typeof this.iglooChanges != 'undefined' ) this.iglooChanges.destroy ();
if ( typeof this.iglooDiff != 'undefined' ) this.iglooDiff.destroy ();
if ( typeof this.iglooControls != 'undefined' ) this.iglooControls.destroy ();
if ( typeof this.iglooStatus != 'undefined' ) this.iglooStatus.destroy ();
if ( typeof this.iglooManageSettings != 'undefined' ) this.iglooManageSettings.hidedisplay ();
if ( typeof this.iglooSession != 'undefined' ) clearTimeout ( this.iglooSession.verificationTimer );
if ( typeof this.iglooNet != 'undefined' ) clearTimeout ( this.iglooNet.retrievalTimer );
this.iglooLoading.show ();
this.iglooLoading.win_height = 0;
this.iglooLoading.win_width = 350;
this.iglooLoading.win_content = '
this.iglooLoading.applyAll ();
this.iglooLoading.center ( 'both' );
return true;
}
}
function iglooNet () {
// the iglooNet module retrieves wiki data from the igloo server to help fight vandalism
this.initial = true;
this.lastUpdate = 0;
this.iglooScores = [];
this.iglooCount = 0;
this.pingFails = 0;
this.iglooCommit = 0;
this.retrieve = function ( cacheBypass ) {
if ( typeof igloo.iglooStatus != 'undefined' ) igloo.iglooStatus.addStatus ( 'Requesting data from iglooNet...' );
this.internalCounter = 0;
if ( cacheBypass == true ) { var cache = '&cachebypass=true'; } else { var cache = ''; }
iglooImport ( iglooSettings.remoteHost + 'main.php?action=retrieve&pingfails=' + this.pingFails + '' + cache + '&me=' + encodeURIComponent ( wgUserName ) + '&session=' + igloo.iglooSession.session, true, 'iglooRetrieve' );
this.retrieveFailed = setTimeout ( function () { igloo.shutdown ( 'userlist retrieval failed - lost connection to iglooNet', 'retry' ); return false; }, iglooSettings.serverTimeout * 3 * 1000 );
//this.retrieveMain ();
}
this.retrieveMain = function ( status ) {
if ( status === 'ok' ) {
clearTimeout ( this.retrieveFailed );
igloo.iglooNet.mergeUpdates ( iglooNetScores );
return true;
} else {
igloo.shutdown ( 'session invalid or expired', 'tryagain' );
return false;
}
/*thisUpdate = false;
if ( typeof iglooScoresDone != 'undefined' ) if ( iglooScoresDone != 'unknown' ) if ( iglooScoresDone == 'ok' ) {
iglooScoresDone = 'unknown';
this.pingFails = 0;
igloo.iglooNet.mergeUpdates ( iglooNetScores );
return true;
} else {
igloo.shutdown ( 'session invalid or expired', 'tryagain' );
return false;
}
if ( this.internalCounter >= ( iglooSettings.serverTimeout * 3 ) ) {
this.pingFails ++;
if ( typeof igloo.iglooStatus !== 'undefined' ) igloo.iglooStatus.addStatus ( 'Server connect failed (action: retrieve; pingfails ' + this.pingFails + ')' );
if ( this.pingFails >= iglooSettings.permitPingfails ) {
igloo.shutdown ( 'userlist retrieval failed - lost connection to iglooNet', 'retry' );
return false;
}
if ( igloo.canDebug === true ) console.log ( 'igloo: pingfail on retrieve (number '+this.pingFails+')' );
this.internalCounter = 0;
this.retrieveMain ();
return false;
} else {
this.internalCounter ++;
thisUpdate = this;
setTimeout ( "if ( thisUpdate ) { thisUpdate.retrieveMain (); }", 500 );
}*/
}
this.mergeUpdates = function ( newUpdates ) {
// the merge updates function takes the data that the iglooNet server has just sent and merges it into the central iglooScores array that is used
// to list the diffs to the user.
var j = 0;
for ( var i in newUpdates ) {
// newUpdates[i][0] = u [or] p
// newUpdates[i][1] = score [or] flag
// i = username [or] pagename
if ( ! this.iglooScores[i] ) {
// if we don't already have data on this item
this.iglooScores[i] = [];
this.iglooScores[i] = newUpdates[i];
} else {
// if we DO already have data on this item, update it
this.iglooScores[i].length = 0;
this.iglooScores[i] = [];
this.iglooScores[i] = newUpdates[i];
}
j ++;
this.iglooCount ++;
}
if ( this.initial == true ) {
igloo.launch ();
this.initial = false;
}
this.retrievalTimer = setTimeout ("igloo.iglooNet.retrieve();", 30 * 1000);
}
this.scoreObject = function ( object ) {
// generally, administrators/crats will be sent as a risk of 0 and rollbackers will be given 0.2.
// trusted users, who have made over 250 edits will be assigned a score of 0.4 - mysteriously meaning
// vandalism is likely to appear first, but there will always be an 'untrustworthy' edit to check.
// by default, other users and IPs will have 0.5 - the server assigns higher scores based on user
// actions
var score = [];
score.length= 0;
score[0] = false;
score[1] = '';
if ( (igloo.iglooNet.iglooScores[object]) && (igloo.iglooNet.iglooScores[object][0] == 'u') ) {
score[0] = igloo.iglooNet.iglooScores[object][1];
}
// if we have special data on this page, such as a whitelist of priority warning, append it here.
// pages that are whitelisted will be sent with a priority of 0, regardless of the user score
// pages that are flagged will gain a score of 0.7
// pages that are blacklisted will gain a score of 0.9
if ( ( igloo.iglooNet.iglooScores[object] ) && ( igloo.iglooNet.iglooScores[object][0] == 'p' ) ) {
switch ( igloo.iglooNet.iglooScores[object][1] ) {
case 'w':
score[0] = 0;
score[1] = 'w';
break;
case 'f':
score[0] = 0.6;
score[1] = 'f';
break;
case 'b':
score[0] = 0.9;
score[1] = 'b';
break;
}
}
return score;
}
this.colourScore = function ( score, defaultCol ) {
defaultCol = typeof ( defaultCol ) != 'undefined' ? defaultCol : '#ffffff';
if ( score === false ) return defaultCol;
if (iglooSettings.enableFeedColour == false) {
var col = defaultCol;
} else if ( score >= 0.8 ) {
var col = iglooSettings.flagColours[0];
} else if ( score >= 0.6 ) {
var col = iglooSettings.flagColours[1];
} else if ( score >= 0.4 ) {
var col = iglooSettings.flagColours[2];
} else if ( score >= 0.2 ) {
var col = iglooSettings.flagColours[3];
} else if ( score >= 0 ) {
var col = iglooSettings.flagColours[4];
} else {
var col = defaultCol;
}
return col;
}
this.genCode = function ( len ) {
var a = new Array ( '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' ), s = '', x = a.length;
for ( var i = 0; i < len; i ++ ) {
var r = Math.floor ( Math.random () * x );
s += a[r];
}
return s;
}
this.investigate = function ( user ) {
if ( ( typeof user !== 'string' ) || ( iglooSettings.iglooFlags.indexOf ( 't' ) === -1 ) || ( iglooSettings.commitToIgNet === false ) ) return false;
var score = this.scoreObject ( user );
if ( ( user.match ( /^[0-9]+\.[0-9]+\.[0-9]+\.?[0-9]*$/i ) === null ) && ( this.iglooCommit >= iglooSettings.commitWhen ) && ( ( score[0] === false ) || ( iglooSettings.recheck === true ) ) ) {
this.iglooCommit = 0; // reset counter
var url = iglooSettings.remoteHost + 'main.php?action=investigate&session=' + igloo.iglooSession.session + '&me=' + encodeURIComponent ( wgUserName ) +'&user=' + user + '';
iglooImport ( url, true, 'iglooInvestigate' );
} else { this.iglooCommit ++; }
}
}
function iglooFilter ( filter ) {
// generate filter variables
this.conditions = [];
this.events = [];
this.activeChange = false;
this.blockFilters = false; // whether to block further filter execution after this one
this.parseFilter = function ( code ) {
var t = t2 = t3 = t4 = [];
// split into statements
t = code.split ( "\n" );
if ( t.length === 0 ) return false; // if no statements
// for each statement, extract the commands
for ( var i = 0, l = t.length; i < l; i ++ ) {
t2 [i] = [];
t2 [i] = t [i].split ( ' ' );
// switch the type of statement (i.e. the first command)
switch ( t2 [i] [0] ) {
case 'if': case 'ifany':
if ( this.parseCondition ( t2 [i] ) === false ) return false;
break;
case 'set': case 'hide': case 'mark': case'blockfilters':
if ( this.parseEvent ( t2 [i] ) === false ) return false;
break;
case '': case '//': //comments
break;
default:
// if we cannot recognise the command, die.
return false;
break;
}
}
}
this.parseCondition = function ( array ) {
if ( array.length < 4 ) return false;
// insert this condition
var useId = this.conditions.length;
this.conditions [useId] = {};
// if vs ifany
this.conditions [useId] ['type'] = array [0];
if ( array [0] === 'if' ) {
switch ( array [1] ) { default: return false; break; case 'summary': case 'oldsize': case 'newsize': case 'changesize': case 'tags': case 'title': case 'user': case 'score': break; }
this.conditions [useId] ['target'] = array [1];
if ( this.conditions [useId] ['negate'] = ( ( array [2] === 'NOT' ) || ( array [2] === '!' ) ) ) { var s = 3; } else { var s = 2; }
switch ( array [s] ) { default: return false; break; case 'regexmatch': case 'contains': case '==': case '<': case '>': break; }
// op limits
if ( ( array [1] === 'tags' ) && ( ( array [s] !== 'regexmatch' ) && ( array [s] !== 'contains' ) && ( array [s] !== '==' ) ) ) return false;
if ( ( ( array [s] === '<' ) || ( array [s] === '>' ) ) && ( ( array [1] !== 'oldsize' ) && ( array [1] !== 'newsize' ) && ( array [1] !== 'changesize' ) && ( array [1] !== 'score' ) ) ) return false;
// fin
this.conditions [useId] ['op'] = array [s];
this.conditions [useId] ['value'] = '';
for ( var i = s+1, l = array.length; i < l; i ++ ) {
this.conditions [useId] ['value'] += array [i] + ' ';
}
this.conditions [useId] ['value'] = this.conditions [useId] ['value'].substr ( 0, this.conditions [useId] ['value'].length - 1 );
}
return true;
}
this.parseEvent = function ( array ) {
var t = {};
// the command
t ['type'] = array [0];
switch ( array [0] ) {
default: return false; break;
case 'set': // set [score/id] [absolute/relative] value
// checks
if ( ( array [1] !== 'score' ) && ( array [1] !== 'id' ) && ( array [1] !== 'comment' ) ) return false; // unrecognised
if ( ( array [1] !== 'comment' ) && ( array [2] !== 'absolute' ) && ( array [2] !== 'relative' ) ) return false; // unrecognised
if ( array [1] === 'score' ) {
if ( isNaN ( array [3] = parseFloat ( array [3] ) ) === true ) return false; // not a number
array [3] = Math.round ( array [3] * 10 ) / 10;
t ['action'] = array [2];
t ['value'] = array [3];
} else if ( array [1] === 'id' ) {
if ( isNaN ( array [3] = parseInt ( array [3], 10 ) ) === true ) return false; // not a number
if ( ( array [3] > 99 ) || ( array [3] < 0 ) ) return false; // out of range
t ['action'] = array [2];
t ['value'] = array [3];
} else {
t ['value'] = '';
for ( var i = 2, l = array.length; i < l; i ++ ) {
t ['value'] += array [i] + ' ';
}
t ['value'] = t ['value'].substr ( 0, t ['value'].length - 1 );
}
// build
t ['target'] = array [1]; // what part of the change data do we want to edit?
break;
}
// insert this event
var useId = this.events.length;
this.events [useId] = t;
return true;
}
this.applyFilter = function ( change ) {
this.activeChange = change;
if ( this.checkConditions () === true ) { this.executeActions (); return this.activeChange; } else { return change; }
}
this.checkConditions = function () {
for ( var i = 0, l = this.conditions.length; i < l; i ++ ) {
var m = this.conditions [i];
switch ( m ['type'] ) {
case 'if':
// convert targets to id codes
var target;
switch ( m['target'] ) {
case 'summary': target = 9; break;
case 'changesize': target = 8; break;
case 'oldsize': target = 6; break;
case 'newsize': target = 7; break;
case 'tags': target = 10; break;
case 'title': target = 0; break;
case 'user': target = 1; break;
case 'score': target = 4; break;
default: return false; break;
}
var meTrue = m['negate'] ? false : true; var meFalse = ! meTrue, r = false;
switch ( m['op'] ) {
case 'regexmatch':
var extractReg = /^\/(.+?)\/([igm]*)$/ig;
var regMatch = extractReg.exec ( this.dataReplace ( m['value'] ) );
var regTest = new RegExp ( regMatch [1], regMatch [2] );
extractReg.lastIndex = 0;
if ( this.activeChange [target].match ( regTest ) !== null ) { r = meTrue; } else { r = meFalse; }
break;
case 'contains':
if ( this.activeChange [target].indexOf ( this.dataReplace ( m['value'] ) ) > -1 ) { r = meTrue; } else { r = meFalse; }
break;
case '==':
if ( this.activeChange [target] == m['value'] ) { r = meTrue; } else { r = meFalse; }
break;
case '<':
if ( this.activeChange [target] < parseFloat ( m['value'] ) ) { r = meTrue; } else { r = meFalse; }
break;
case '>':
if ( this.activeChange [target] > parseFloat ( m['value'] ) ) { r = meTrue; } else { r = meFalse; }
break;
default: r = false; break;
}
break;
}
if ( r === false ) return false;
}
return true;
}
this.executeActions = function () {
for ( var i = 0, l = this.events.length; i < l; i ++ ) {
var m = this.events [i];
switch ( m ['type'] ) {
case 'set':
if ( m['target'] === 'comment' ) {
if ( typeof this.activeChange [11] !== 'string' ) this.activeChange [11] = '';
this.activeChange [11] += ' ' + this.dataReplace ( m['value'] );
break;
}
var existing = this.activeChange [4]; var scoreStr = existing.toString ( 10 );
if ( scoreStr.indexOf ( '.' ) === -1 ) scoreStr += '.0';
var score = scoreStr.substr ( 0, scoreStr.indexOf ( '.' ) + 2 );
var id = scoreStr.substr ( scoreStr.indexOf ( '.' ) + 2 );
if ( id == '' ) id = '00';
if ( id.length === 1 ) id += '0';
if ( m['target'] === 'score' ) {
var newScore = parseFloat ( score );
if ( m['action'] === 'relative' ) {
newScore += parseFloat ( m['value'] );
newScore = Math.round ( newScore * 10 ) / 10;
newId = id;
} else {
newScore = parseFloat ( m['value'] );
newScore = Math.round ( newScore * 10 ) / 10;
newId = id;
}
} else {
var newId = parseInt ( id, 10 );
if ( m['action'] === 'relative' ) {
newId += parseInt ( m['value'], 10 );
if ( newId > 99 ) newId = 99;
if ( newId < 0 ) newId = 0;
newId = newId.toString ( 10 );
newScore = Math.round ( parseFloat ( score ) * 10 ) / 10;
} else {
newId = parseInt ( m['value'], 10 );
newId = newId.toString ( 10 );
newScore = Math.round ( parseFloat ( score ) * 10 ) / 10;
}
}
if ( ( parseInt ( newId, 10 ) < 10 ) && ( newId.substr ( 0, 1 ) !== '0' ) ) newId = '0' + newId;
var final = parseFloat ( newScore + '' + newId );
this.activeChange [4] = final;
break;
case 'blockfilters':
this.blockFilters = true;
break;
}
}
}
this.dataReplace = function ( string ) {
var regTest = /%DATA([0-9A-Z]+)%/g, c = this.activeChange;
regTest.lastIndex = 0;
var o = string.replace ( regTest, function ( m, m2 ) {
if ( m2 === 'ME' ) {
return wgUserName;
} else {
if ( c[m2] === null ) return false;
return c[m2].toString();
}
} );
return o;
}
// on create
this.parseSuccess = this.parseFilter ( filter ); // return parse success
return true;
}
function iglooSecurity () {
this.userActivity = true;
this.pingFails = 0;
if ( (window.location.href.indexOf('&sessionkey=') == -1) || (window.location.href.indexOf('::::') == -1) ) { igloo.shutdown('invalid session provided', 'tryagain'); this.shutdown = true; return false; }
this.session = window.location.href.substr(window.location.href.indexOf('&sessionkey=') + 12);
this.session = this.session.substr(0, this.session.length - 4);
this.verifySession = function ( type ) {
this.internalCounter = 0;
if ( this.userActivity == true ) { var alive = '&keep-alive=true'; } else { var alive = '&keep-alive=false'; }
this.userActivity = false;
iglooImport( iglooSettings.remoteHost + 'main.php?action=verify&pingfails=' + this.pingFails + '&user=' + encodeURIComponent ( wgUserName ) + '&verify=' + this.session + alive, true, 'iglooVerify' );
this.checkVerification ( type );
}
this.checkVerification = function ( type ) {
if ( typeof iglooSessionVerified != 'undefined' ) if ( iglooSessionVerified != 'unknown' ) if ( iglooSessionVerified == 'ok' ) {
this.pingFails = 0;
iglooSessionVerified = 'unknown';
this.verificationTimer = setTimeout("igloo.iglooSession.verifySession();", 45 * 1000);
if ( type == 'initial' ) {
igloo.launch();
}
return true;
} else {
igloo.shutdown('session invalid or expired', 'tryagain');
return false;
}
if ( this.internalCounter >= iglooSettings.serverTimeout * 2 ) {
this.pingFails ++;
if ( type != 'initial' ) igloo.iglooStatus.addStatus ( 'Server connect failed (action: verify; pingfails ' + this.pingFails + ')' );
if ( this.pingFails >= iglooSettings.permitPingfails ) {
igloo.shutdown ( 'verification failed - lost connection to iglooNet', 'retry' );
}
return false;
} else {
this.internalCounter ++;
setTimeout("igloo.iglooSession.checkVerification('"+type+"');", 1000);
}
}
}
function iglooManageSettings () {
// the iglooManageSettings module retrieves settings from the igloo server, and replaces the defaults where applicable.
this.settingsEnabled = true;
this.retrieve = function () {
this.internalCounter = 0;
iglooImport ( iglooSettings.remoteHost + 'main.php?action=settings&me=' + encodeURIComponent(wgUserName) + '&do=get&session=' + igloo.iglooSession.session, true, 'iglooNetSettings' );
this.retrieveMain ();
}
this.retrieveMain = function () {
thisSetting = false;
if ( typeof iglooNetSettingsDone != 'undefined' ) if ( iglooNetSettingsDone != 'unknown' ) if ( iglooNetSettingsDone == 'ok' ) {
// success
this.overwritelocal ();
this.managefilters ();
// continue launch
igloo.launch ();
return true;
} else {
igloo.shutdown( 'session invalid or expired', 'tryagain' );
return false;
}
if ( this.internalCounter >= ( iglooSettings.serverTimeout * 2 ) ) {
igloo.shutdown( 'settings failed - lost connection to iglooNet', 'retry' );
return false;
} else {
this.internalCounter ++;
thisSetting = this;
setTimeout( "if ( thisSetting ) { thisSetting.retrieveMain (); }", 500 );
}
}
this.overwritelocal = function () {
for ( i in iglooNetSettings ) {
if ( iglooSettings [i] !== undefined ) {
iglooSettings [i] = iglooNetSettings [i];
}
}
return true;
}
this.managefilters = function () {
for ( var i = 0, l = iglooSettings.filterList.length; i < l; i ++ ) {
iglooSettings.filterList[i][4] = new iglooFilter ( iglooSettings.filterList[i][3] );
if ( iglooSettings.filterList[i][4].parseSuccess === false ) { alert ( 'Warning: parse error; igloo filter failed to parse, global filter ID ' + iglooSettings.filterList[i][0] ); }
}
return true;
}
this.set = function ( setting, value ) {
if ( this.settingsEnabled === true ) {
iglooImport ( iglooSettings.remoteHost + 'main.php?action=settings&me=' + encodeURIComponent ( wgUserName ) + '&do=set&setting=' + encodeURIComponent ( setting ) + '&value=' + encodeURIComponent ( value ) + '&session=' + igloo.iglooSession.session, true, 'iglooNetDoSet' );
this.settingsEnabled = false;
return true;
} else {
alert ( 'Could not alter setting - previous requests are still being processed. Please wait, then try again.' );
return false;
}
}
this.freeSettings = function () {
this.settingsEnabled = true;
}
this.start = function () {
this.mainContent = '
';if ( igloo.canDebug === true ) console.log ( 'igloo: prepped settings main' );
}
this.showdisplay = function () {
// generate interface
igloo.iglooPopup.show ( this.mainContent );
// add tabs
this.addtab ( 'info', 'user info' );
this.addtab ( 'general', 'general' );
this.addtab ( 'interface', 'interface' );
//this.addtab ( 'actions', 'actions' );
this.addtab ( 'filters', 'filters' );
if ( iglooSettings.mesysop ) this.addtab ( 'admin', 'admin' );
this.addtab ( 'close', 'close' );
// default tab
this.switchtab ( 'info' );
// dynamic key blocking
iglooSettings.dynamicBlockKeys = 'settings';
return true;
}
this.hidedisplay = function () {
igloo.iglooPopup.hide ();
iglooSettings.dynamicBlockKeys = 'default';
return true;
}
this.addtab = function ( tabid, tabtext ) {
if ( ( ! tabid ) || ( ! tabtext ) ) return false;
var tabscont = document.getElementById ( 'igloo-settings-tabs' );
tabscont.innerHTML += '
return tabscont;
}
this.genFilterText = function () {
var filterText = '';
for ( var i = 0, l = iglooSettings.filterList.length; i < l; i ++ ) {
var t = iglooSettings.filterList [i], optionsString = 'this filter has a problem';
var disp = t[3].replace ( /\\/g, '\\\\' );
disp = disp.replace ( /\n/g, '\\n' );
disp = disp.replace ( /\'/g, '\\\'' );
//this.disEnString = new Array ();
//this.disEnString[i] = ( t[1] === true ) ? 'iglooImport ( \+iglooSettings.remoteHost+'main.php?action=settings&me=' + encodeURIComponent ( wgUserName ) + '&do=set&setting=disablefilter&value='+t[0]+'\', true, \'iglooFilter\' ); iglooSettings.filterList['+i+'][1] = false;' : 'iglooImport ( \+iglooSettings.remoteHost+'main.php?action=settings&me=' + encodeURIComponent ( wgUserName ) + '&do=set&setting=enablefilter&value='+t[0]+'\', true, \'iglooFilter\' ); iglooSettings.filterList['+i+'][1] = true;';
var disEnString = ( t[1] === true ) ? 'Disable' : 'Enable';
//disEnString = disEnString.replace ( /'/g, '\\\'' );
if ( t[2] !== 'default' ) {
var saveString = '';
optionsString = 'edit';
optionsString += ' | delete';
} else {
optionsString = 'view filter (cannot edit)';
}
var col = ( t[1] === true ) ? '' : 'background-color: #ffbbbb;';
filterText += '
filterText += '- filter ' + t[0] + ' (' + optionsString + ')';
filterText += '
}
if ( i === 0 ) filterText = '
return filterText;
}
this.togglefilterenabled = function ( to ) {
var t = document.getElementById ( 'igloo-toggle-filter-disable' ), id = document.getElementById ( 'igloo-filter-current-id' ).innerHTML.split ( ':' );
id = parseInt ( id[0], 10 );
if ( to === 'enabled' ) {
iglooImport ( iglooSettings.remoteHost+'main.php?action=settings&me=' + encodeURIComponent ( wgUserName ) + '&do=set&setting=enablefilter&value=' + iglooSettings.filterList[id][0] + '&session=' + igloo.iglooSession.session, true, 'iglooFilter' );
iglooSettings.filterList[id][1] = true;
t.value = 'Disable this filter';
t.onclick = function () { igloo.iglooManageSettings.togglefilterenabled ( 'disabled' ); document.getElementById ( 'igloo-filter-list' ).innerHTML = igloo.iglooManageSettings.genFilterText (); }
} else {
iglooImport ( iglooSettings.remoteHost+'main.php?action=settings&me=' + encodeURIComponent ( wgUserName ) + '&do=set&setting=disablefilter&value=' + iglooSettings.filterList[id][0] + '&session=' + igloo.iglooSession.session, true, 'iglooFilter' );
iglooSettings.filterList[id][1] = false;
t.value = 'Enable this filter';
t.onclick = function () { igloo.iglooManageSettings.togglefilterenabled ( 'enabled' ); document.getElementById ( 'igloo-filter-list' ).innerHTML = igloo.iglooManageSettings.genFilterText (); }
}
return true;
}
this.attachfilterbuttons = function ( id ) {
if ( id !== 'new' ) {
var t = document.getElementById ( 'igloo-toggle-filter-disable' );
if ( iglooSettings.filterList[id][1] === true ) {
// enabled, so disable
t.onclick = function () { igloo.iglooManageSettings.togglefilterenabled ( 'disabled' ); document.getElementById ( 'igloo-filter-list' ).innerHTML = igloo.iglooManageSettings.genFilterText (); }
} else {
// disabled, so enable
t.onclick = function () { igloo.iglooManageSettings.togglefilterenabled ( 'enabled' ); document.getElementById ( 'igloo-filter-list' ).innerHTML = igloo.iglooManageSettings.genFilterText (); }
}
}
if ( document.getElementById ( 'igloo-filter-text' ) !== null ) {
t = document.getElementById ( 'igloo-filter-text' );
t.onkeyup = function () {
var t2 = new iglooFilter ( document.getElementById ( 'igloo-filter-text' ).value );
if ( t2.parseSuccess === false ) {
var t3 = document.getElementById ( 'igloo-save-filter' );
t3.disabled = true;
t3.value = 'Parse error: filter is invalid';
} else {
var t3 = document.getElementById ( 'igloo-save-filter' );
t3.disabled = false;
if ( document.getElementById ( 'igloo-filter-current-id' ).innerHTML.indexOf ( 'new' ) > -1 ) {
t3.value = 'Create new filter';
} else {
t3.value = 'Save filter changes';
}
}
}
}
if ( document.getElementById ( 'igloo-save-filter' ) !== null ) {
t = document.getElementById ( 'igloo-save-filter' );
t.onclick = function () {
this.disabled = true;
var id = document.getElementById ( 'igloo-filter-current-id' ).innerHTML.split ( ':' );
var data = document.getElementById ( 'igloo-filter-text' ).value;
// if new
if ( id[1] === 'new' ) {
var t = [], n = true;
t [0] = igloo.iglooNet.genCode ( 5 );
t [1] = true;
t [2] = wgUserName;
t [3] = data;
t [4] = new iglooFilter ( t [3] );
id [1] = t [0];
iglooSettings.filterList.push ( t );
} else {
var t = iglooSettings.filterList [ parseInt ( id[0], 10 ) ], n = false;
t [3] = data;
t [4] = new iglooFilter ( t [3] );
iglooSettings.filterList [ parseInt ( id[0], 10 ) ] = t;
}
iglooImport ( iglooSettings.remoteHost+'main.php?action=settings&me=' + encodeURIComponent ( wgUserName ) + '&do=set&setting=editfilter&id=' + id [1] + '&value=' + encodeURIComponent ( data ) + '&session=' + igloo.iglooSession.session, true, 'iglooFilter' );
if ( n === true ) { igloo.iglooManageSettings.switchtab ( 'filters' ); } else { document.getElementById ( 'igloo-filter-list' ).innerHTML = igloo.iglooManageSettings.genFilterText (); }
}
}
}
this.switchtab = function ( tabid ) {
if ( ! tabid ) { throw 'igloo: unexpected settings call, tab is missing'; return false; }
var tabcont = document.getElementById ( 'igloo-settings-content' ), v;
switch ( tabid ) {
case 'info':
tabcont.innerHTML = ''; // blank
tabcont.innerHTML += '
- username: ' + wgUserName + '
- recognised usergroup: ' + iglooSettings.userGroup + '
- igloo user flags: ' + iglooSettings.iglooFlags + '
- igloo trust status: N/A
- total sessions: ' + iglooSettings.totalSessions + '
- last connected from: ' + iglooSettings.lastConnectIp + '
- last connected: ' + iglooSettings.lastConnectTime + '
break;
case 'general':
tabcont.innerHTML = ''; // blank
var cont = '';
cont += '
'
v = iglooSettings.updateTime;
cont += '
';v = iglooSettings.updateQuantity;
cont += '
';v = iglooSettings.updateLimit;
cont += '
';v = iglooSettings.promptRevertSelf ? 'checked' : '';
cont += '
';v = iglooSettings.profFilter ? 'checked' : '';
cont += '
';cont += '
Update time | |
Update quantity | |
Update list limit | |
Prompt on self revert | |
Enable profanity highlighting |
tabcont.innerHTML = cont;
break;
case 'interface':
tabcont.innerHTML = ''; // blank
var cont = '';
cont += '
'
v = iglooSettings.preloadInterface ? 'checked' : '';
cont += '
';v = iglooSettings.diffFontSize;
cont += '
';v = iglooSettings.enableFeedColour ? 'checked' : '';
cont += '
';v = iglooSettings.histWinTimeout;
cont += '
';cont += '
Preload interface elements | |
Diff font size (px) | |
Enable feed colouring | |
History window timeout |
tabcont.innerHTML = cont;
break;
case 'admin':
tabcont.innerHTML = ''; // blank
var cont = '';
cont += '
'
v = iglooSettings.preloadInterface ? 'checked' : '';
cont += '
';//v = iglooSettings.enableFeedColour ? 'checked' : '';
//cont += '
';//v = iglooSettings.histWinTimeout;
//cont += '
';cont += '
Action after final warning | |
Enable feed colouring | |
History window timeout |
tabcont.innerHTML = cont;
break;
case 'filters':
// build filterText
var filterText = this.genFilterText ();
// build display
var cont = ''; // blank
cont += '
'
cont += '
';
cont += '
cont += ' | ';
cont += ' Select \'edit\' from a filter on the left to begin... ';
cont += ' |
tabcont.innerHTML = cont;
break;
case 'close':
this.hidedisplay ();
break;
default:
throw 'igloo: unexpected settings call, tab content undefined';
break;
}
}
}
function iglooChanges () {
// the iglooChanges object is the object that retrieves, sorts, manages and displays changes from Wikipedia
this.recentChanges = []; // main array, holding the changes
this.viewedChanges = []; // main array, holding diffs that should NOT be displayed (we've seen them already)
this.serverDetails = []; // main array, holding details from the server regarding users and pages
this.start = function () {
// start the changed program
this.startInterface ();
this.startTicker ();
}
this.startTicker = function () {
// perform the refresh ticks that grab info from the server
this.updateContent ();
this.refreshTicker = setInterval ( "igloo.iglooChanges.updateContent();", iglooSettings.updateTime * 1000 );
}
this.startInterface = function () {
// this creates the basic interface into which changes are placed when they have been received.
// essentially, it is a div that will contain clickable list elements.
this.changeDisplay = new wa_window ( igloo.iglooInterface );
this.changeDisplay.win_width = 190;
this.changeDisplay.win_height = parseInt ( igloo.iglooInterface.win_obj.style.height ) - 50;
this.changeDisplay.win_bg = '#ffffff';
this.changeDisplay.win_bd_rt = '1px solid #000000'; this.changeDisplay.win_bd_bt = '1px solid #000000';
this.changeDisplay.win_padding = 0;
this.changeDisplay.win_content = '
';this.changeDisplay.applyAll ();
this.logoDisplay = new wa_window ( igloo.iglooInterface );
this.logoDisplay.win_top = parseInt ( igloo.iglooInterface.win_obj.style.height ) - 50;
this.logoDisplay.win_width = 190;
this.logoDisplay.win_height= 50;
this.logoDisplay.win_bg = '#ffffff';
this.logoDisplay.win_bd_tp = '1px solid #000000';
this.logoDisplay.win_padding = 0;
this.logoDisplay.win_content = '';
this.logoDisplay.applyAll ();
}
this.addToViewed = function ( revid ) {
// mark an oldid as viewed so we do not display it more than once in the display window.
var sizeLimit = 30;
this.viewedChanges.push ( revid );
if ( this.viewedChanges.length > sizeLimit ) this.viewedChanges.shift ();
return true;
}
this.markViewed = function ( revid ) {
this.addToViewed ( revid );
// next, remove it from the recentChanges array, and redisplay that.
for ( var i = 0; i < this.recentChanges.length; i ++ ) {
if ( this.recentChanges[i][2] == revid ) {
this.recentChanges.splice(i, 1);
var change = i;
}
}
this.displayChanges ();
}
this.updateContent = function () {
var update = new iglooUpdateChanges ();
}
this.displayChanges = function () {
var visibleChangeOutput = '';
for ( var i = 0; i < this.recentChanges.length; i ++ ) {
if ( typeof this.recentChanges[i][4] == 'undefined' ) this.recentChanges[i][4] = 0.5;
var backgroundColour = igloo.iglooNet.colourScore ( this.recentChanges[i][4] );
if ( this.recentChanges[i][3] == true ) { var newPage = 'N '; } else { var newPage = ''; }
visibleChangeOutput += '
}
document.getElementById('iglooChangesList').innerHTML = visibleChangeOutput;
}
this.destroy = function () { // calling this will destroy the interface and connections of this object.
this.changeDisplay.hide ();
this.logoDisplay.hide ();
if ( typeof this.refreshTicker != 'undefined' ) clearInterval ( this.refreshTicker );
}
}
function iglooUpdateChanges () {
// the iglooUpdate object handles making a request to the server, and returning an array of data.
this.updateCounter = 0;
this.update = function () {
switch ( this.updateCounter ) {
default: case 0:
// first, get some recent changes
var aRequest = this;
this.ajax = new wa_ajaxcall ();
this.ajax.requestUrl = iglooSettings.rootApi + '?format=xml&action=query&list=recentchanges&rcprop=user|title|ids|sizes|comment|tags&rctype=edit|new&rclimit=' + iglooSettings.updateQuantity;
this.ajax.doRequest ( function () {
aRequest.updateCounter ++;
aRequest.update ();
});
break;
case 1:
// recent changes are held such that:
// [0] = title
// [1] = user
// [2] = oldid
// [3] = new page?
// [4] = user vandal score
// [5] = priority note - a priority note is assigned to pages that have priority for some reason. These will be displayed at the top of the list, regardless of the score of the user.
// [6] = old length
// [7] = new length
// [8] = changed length
// [9] = comment
// [10] = tag string
// [11] - igloo change comments (can be set using filters)
this.tempChanges = [];
var data = this.ajax.response.getElementsByTagName ( 'rc' );
for (var i = 0; i < data.length; i++) {
this.tempChanges[i] = [];
this.tempChanges[i][0] = data[i].getAttribute ( 'title' );
this.tempChanges[i][1] = data[i].getAttribute ( 'user' );
this.tempChanges[i][2] = data[i].getAttribute ( 'revid' );
if ( data[i].getAttribute ( 'type' ) == 'edit' ) {
this.tempChanges[i][3] = false;
} else {
this.tempChanges[i][3] = true;
}
this.tempChanges[i][4] = 0;
this.tempChanges[i][5] = 0;
this.tempChanges[i][6] = parseInt ( data[i].getAttribute ( 'oldlen' ) );
this.tempChanges[i][7] = parseInt ( data[i].getAttribute ( 'newlen' ) );
this.tempChanges[i][8] = this.tempChanges[i][7] - this.tempChanges[i][6];
this.tempChanges[i][9] = data[i].getAttribute ( 'comment' );
var t = data[i].childNodes[0].childNodes, s = '::';
for ( var j = 0, l = t.length; j < l; j ++ ) {
s += t[j].childNodes[0].wholeText + '::';
}
this.tempChanges[i][10] = s;
this.tempChanges[i][11] = '';
}
this.updateCounter ++;
this.update ();
break;
case 2:
// we have the details - build the temporary changes array
var score = [];
for ( var i = 0; i < this.tempChanges.length; i ++ ) {
// if we have special data on this user, such as a priority score, append it here.
// check for pages
score.length = 0;
score = igloo.iglooNet.scoreObject ( this.tempChanges[i][0] );
// check for users
if ( score[0] === false ) {
score.length = 0;
score = igloo.iglooNet.scoreObject ( this.tempChanges[i][1] );
}
// backup
if ( score[0] === false ) score[0] = iglooSettings.defaultUserScore;
this.tempChanges[i][4] = score[0];
this.tempChanges[i][5] = score[1];
// apply any relevant filters to the changes we've loaded
if ( iglooSettings.enableFilters === true ) {
for ( var j = 0, l = iglooSettings.filterList.length; j < l; j ++ ) {
var t = iglooSettings.filterList [j];
if ( ( t[1] === false ) || ( t[4].parseSuccess === false ) ) continue;
this.tempChanges[i] = t[4].applyFilter ( this.tempChanges[i] );
if ( t[4].blockFilters === true ) {
t[4].blockFilters = false;
break;
}
}
}
}
// we want to remove all duplicates from the temp array, by copying them into
// another temp array only if they are not already there.
var tempArray = [];
for ( var i = 0; i < this.tempChanges.length; i ++ ) {
var t = false;
for ( var j = 0; j < tempArray.length; j ++ ) {
if ( this.tempChanges[i][0] == tempArray[j][0] ) {
t = true; break;
}
}
if ( t === false ) tempArray.push ( this.tempChanges[i] );
}
// now, remove any elements that are on the viewed list that we do not wish to display to the user OR that were made by our user
var limit = tempArray.length
for (var i = 0; i < limit; i ++) {
if ( ( in_array ( tempArray[i][2], igloo.iglooChanges.viewedChanges ) == true ) || ( ( tempArray[i][1] == wgUserName ) && ( iglooSettings.hideOwn == true ) ) ) {
tempArray.splice ( i, 1 ); i --; limit --;
} else {
if ( ( tempArray[i][0] == igloo.iglooDiff.currentDiff[0] ) && ( igloo.iglooActions.reversionEnabled !== 'pause' ) ) {
// if this is the same title as the page we're viewing, update the display
igloo.iglooChanges.addToViewed ( tempArray[i][2] );
igloo.iglooDiff.display ( tempArray[i][0], tempArray[i][1], tempArray[i][2], tempArray[i][3], tempArray[i][4], tempArray[i][11] );
igloo.iglooDiff.haschanged = true;
tempArray.splice ( i, 1 ); i --; limit --;
}
}
}
// we now have the full array of scores
// go through the main recent changes array, check if there are any pages that match
// here and there, delete them from the main array, then merge this one into the main one
var i = 0;
while ( typeof igloo.iglooChanges.recentChanges[i] != 'undefined' ) {
for ( var j = 0; j < tempArray.length; j ++ ) {
if ( typeof igloo.iglooChanges.recentChanges[i] == 'undefined' ) break;
if ( igloo.iglooChanges.recentChanges[i][0] == tempArray[j][0] ) {
igloo.iglooChanges.recentChanges.splice ( i, 1 );
i --;
}
}
i ++;
}
// recent changes array now holds all the data it did before EXCEPT titles that conflict with the new changes
// merge the new changes into the old ones
igloo.iglooChanges.recentChanges = tempArray.concat ( igloo.iglooChanges.recentChanges );
// now, sort the array based on the float values :)
igloo.iglooChanges.recentChanges = sort_array_multi ( igloo.iglooChanges.recentChanges, 4, 'descending' );
// check that we aren't over the hard limit for number of changes. If we are, remove those least likely to be vandalism.
if ( igloo.iglooChanges.recentChanges.length > iglooSettings.updateLimit ) {
igloo.iglooChanges.recentChanges = igloo.iglooChanges.recentChanges.splice ( 0, iglooSettings.updateLimit ); }
// now, we have to display the changes to the user!
igloo.iglooChanges.displayChanges ();
break;
}
}
this.update();
}
function iglooDiff () {
// the iglooDiff module is the object that displays and styles Wikiepdia diffs in the main window
this.viewingDiff = false;
this.previousDiff = [];
this.currentDiff = [];
this.displayCounter = 0;
this.displayHistory = [];
this.historyPosition = 0;
this.canAddToHist = true;
this.start = function () { // this functions creates the diff window for future use, and displays the latest news in it :)
this.startInterface ();
this.displayWelcome ();
this.warnedParser = false;
}
this.startInterface = function () {
// this creates the basic interface into which changes are placed when they have been received.
// essentially, it is a div that will contain clickable list elements.
this.scoreDisplay = new wa_window ( igloo.iglooInterface );
this.scoreDisplay.win_left = 190;
this.scoreDisplay.win_top = 79;
this.scoreDisplay.win_width = parseInt ( igloo.iglooInterface.win_obj.style.width ) - 200;
this.scoreDisplay.win_height= 11;
this.scoreDisplay.win_bg = '#ffffff';
this.scoreDisplay.win_bd_bt = '1px solid #000000';
this.scoreDisplay.win_padding = 2;
this.scoreDisplay.win_fontsize = 10;
this.scoreDisplay.win_content = 'You are not yet viewing a diff';
this.scoreDisplay.applyAll ();
this.diffDisplay = new wa_window ( igloo.iglooInterface );
this.diffDisplay.win_left = 190;
this.diffDisplay.win_top = 95;
this.diffDisplay.win_width = parseInt ( igloo.iglooInterface.win_obj.style.width ) - 200;
this.diffDisplay.win_height= parseInt ( igloo.iglooInterface.win_obj.style.height ) - 255;
this.diffDisplay.win_bg = '#ededff';
this.diffDisplay.win_padding = 5;
this.diffDisplay.win_content = '
this.diffDisplay.applyAll ();
}
this.displayWelcome = function () {
// this function specifically displays the welcome message in the diff window
var welcomeRequest = new wa_mediawikiApi ();
welcomeRequest.onCompleteAction = function ( data ) {
var regTest = /welcome:(.+?);;/i, o;
regResult = regTest.exec( this.data['page']['revisions'][0]['content'] );
o = regResult[1].replace ( '%CURRENTVERSION%', iglooSettings.version );
document.getElementById( 'iglooDiffDisplay' ).innerHTML = o;
};
welcomeRequest.getPage ( iglooSettings.localBase + 'config', 1, 'content' );
}
this.display = function ( title, user, revisionId, newPage, diffScore, iglooNetComment ) { // this function displays the diff of an edit on the screen for the user
// the user has displayed activity by initiating a diff display.
this.viewingDiff = true;
this.haschanged = false;
igloo.iglooSession.userActivity = true;
// update the holding variables. Some of these may be absent based on the origin of the display call.
if ( typeof this.currentDiff[0] != 'undefined' ) { this.previousDiff[0] = this.currentDiff[0]; this.previousDiff[1] = this.currentDiff[1]; this.previousDiff[2] = this.currentDiff[2]; this.previousDiff[3] = this.currentDiff[3]; this.previousDiff[4] = this.currentDiff[4]; this.previousDiff[5] = this.currentDiff[5]; }
this.currentDiff[0] = title; this.currentDiff[1] = user; this.currentDiff[2] = revisionId; this.currentDiff[3] = newPage; this.currentDiff[4] = diffScore; this.currentDiff[5] = iglooNetComment;
// add to history
this.manageHist ();
// investigate
if ( this.currentDiff [1] ) igloo.iglooNet.investigate ( this.currentDiff [1] );
// decide upon the request to perform - is this a specific request, or a general one?
if ( ! revisionId ) {
revisionId = false;
var url = mw.config.get('wgServer') + mw.config.get('wgScript') + '?title=' + encodeURIComponent ( title ) + '&diff=cur&diffonly=true&redirect=no';
} else {
var url = mw.config.get('wgServer') + mw.config.get('wgScript') + '?oldid=' + revisionId + '&diff=prev&diffonly=true&redirect=no';
}
var aDisplay = this;
this.ajax = new wa_ajaxcall ();
this.ajax.requestUrl = url;
this.ajax.doRequest ( function () {
aDisplay.parseScreenScrape ();
});
}
this.manageHist = function () {
// add the PREVIOUS page to the display history.
if ( ( this.currentDiff[0] ) && ( this.currentDiff[1] ) && ( this.currentDiff[2] ) ) if ( this.canAddToHist == true ) {
// first, remove any history between the current position and 0.
if ( this.historyPosition > 0 ) {
var temp = [];
temp.length = 0;
temp = this.displayHistory.slice(this.historyPosition);
this.displayHistory.length = 0;
this.displayHistory = temp;
this.historyPosition = 0;
}
// then add the page
var histEntry = [];
histEntry.length = 0;
histEntry[0] = this.currentDiff[0]; histEntry[1] = this.currentDiff[1]; histEntry[2] = this.currentDiff[2];
this.displayHistory.unshift ( histEntry );
if ( this.displayHistory > iglooSettings.maxHistory ) this.displayHistory.length = iglooSettings.maxHistory;
}
this.canAddToHist = true;
// handle greying of invalid options
var backButton = document.getElementById('igloo-buttons-back-b');
var forwardButton = document.getElementById('igloo-buttons-forward-b');
var backUrl = '' + iglooSettings.remoteHost + 'images/igloo-back';
var forwardUrl = '' + iglooSettings.remoteHost + 'images/igloo-forward';
var grey = '-grey';
var filetype = '.png';
if (this.displayHistory.length <= 1) { backButton.src = backUrl + grey + filetype; forwardButton.src = forwardUrl + grey + filetype; }
else if ( (this.displayHistory.length > 1) && (this.historyPosition == 0) ) { backButton.src = backUrl + filetype; forwardButton.src = forwardUrl + grey + filetype; }
else if ( (this.displayHistory.length > 1) && (this.historyPosition == (this.displayHistory.length - 1)) ) { backButton.src = backUrl + grey + filetype; forwardButton.src = forwardUrl + filetype; }
else { backButton.src = backUrl + filetype; forwardButton.src = forwardUrl + filetype; }
}
this.goBack = function ( count ) {
if ( this.displayHistory.length <= 0 ) return false;
if ( ! count ) count = 1;
if ( ( this.historyPosition + count ) > this.displayHistory.length ) count = this.displayHistory.length;
this.historyPosition += count;
var doView = this.displayHistory [this.historyPosition];
this.canAddToHist = false;
this.display ( doView[0], doView[1], doView[2] );
return true;
}
this.goForward = function(count) {
if (this.historyPosition <= 0) return false;
if (!count) count = 1;
if ( (this.historyPosition - count) < 0 ) { this.historyPosition = 0; } else { this.historyPosition -= count; }
var doView = this.displayHistory[this.historyPosition];
this.canAddToHist = false;
this.display(doView[0], doView[1], doView[2]);
}
this.parseScreenScrape = function ( html ) {
if ( html == null ) {
if ( typeof this.ajax.responseXML !== 'undefined' ) { html = this.ajax.responseXML; var tryParse = false; } else
{ html = this.ajax.responseText; var tryParse = true; }
}
if ( ! html ) return false;
// CSS details: object widths
var markerwidth = 14;
var contentwidth = ( this.diffDisplay.win_width / 2 ) - markerwidth;
// step 0 - build an XML document from the HTML for IE - cos it's rubbish
var ie = false, err = false, t = 'nothing';
if ( ( ! html.getElementById ) && ( tryParse === false ) ) {
// we're hacking for IE
ie = true;
// get, then clean, the responseText
html = this.ajax.pageRequest.responseText;
html = html.substr ( html.indexOf ( '
html = html.replace ( / /g, ' ' );
var doc = ie_create_document ();
var test = doc.loadXML ( html );
if ( doc.parseError.errorCode != 0 ) {
alert ( 'Internet Explorer failed to parse the incoming page because igloo sanitised it incorrectly. XML parser returned:'+"\n"+doc.parseError.reason );
return false;
}
html = doc;
} else {
// perform error checking on the retrieved document
if ( html.getElementsByTagName ) {
var err = html.getElementsByTagName ( 'parsererror' ), attempt;
err = err.length;
} else { var err = 1, attempt; }
if ( err > 0 ) {
if ( typeof this.ajax.responseText !== 'undefined' ) {
attempt = this.ajax.responseText;
// sanitise XML
attempt = attempt.replace ( / /g, ' ' );
attempt = attempt.replace ( /&/g, '&' );
attempt = attempt.replace ( /®/g, '®' );
attempt = attempt.replace ( /©/g, '©' );
// final replacements
attempt = attempt.replace ( /&([^#])/g, '&$1' );
if ( window.DOMParser ) {
var parser = new DOMParser ();
html = parser.parseFromString ( attempt, 'text/xml' );
if ( html.getElementsByTagName ( 'parsererror' ).length > 0 ) { err = true; t = html.getElementsByTagName ( 'parsererror' )[0].firstChild.nodeValue; } else {
if ( this.warnedParser !== true ) igloo.iglooStatus.addStatus ( 'Warning: igloo was forced to sanitise the incoming page because it contained invalid XML. This is most commonly caused by a faulty, recent change to the Wikipedia page layout and may require reporting if you frequently receive this error.' );
this.warnedParser = true;
}
} else {
err = true;
}
} else {
err = true;
}
}
}
if ( err === true ) {
// clean
document.getElementById('iglooDiffDisplay').innerHTML = '';
// the container div
var innerDiv = document.createElement ( 'div' );
innerDiv.setAttribute ( 'id', 'iglooInnerDiv' );
innerDiv.style.margin = 'auto';
t = t.replace ( '<', '<' ); t = t.replace ( '>', '>' ); t = t.replace ( "\n", '
' );
innerDiv.innerHTML = 'igloo error: an unrecoverable XML parsing error occured on the page you attempted to view. This is most commonly caused by a faulty, recent change to the Wikipedia page layout. If you are receiving this error frequently, you should stop using igloo and report the problem to User:Ale_jrb.
Details:
' + t;
// display everything in the window
document.getElementById('iglooDiffDisplay').appendChild ( innerDiv );
document.getElementById('iglooDiffDisplay').innerHTML += ' ';
return false;
}
// step 1 - build an array of the data that is displayed by the diff screen
// this.diffData[0] = old
// this.diffData[1] = new
// #[0] = revision as of
// #[1] = username
// #[2] = comment/summary
this.diffData = [];
this.diffData[0] = []; this.diffData[1] = [];
for ( var i = 0; i < 3; i ++ ) {
if ( html.getElementById ) { // good browsers
if ( html.getElementById ( 'mw-diff-otitle' + ( i + 1 ) ) != null ) { this.diffData[0][i] = echo_nodes_recursive ( html.getElementById ( 'mw-diff-otitle' + ( i + 1 ) ) ); }
if ( html.getElementById ( 'mw-diff-ntitle' + ( i + 1 ) ) != null ) { this.diffData[1][i] = echo_nodes_recursive ( html.getElementById ( 'mw-diff-ntitle' + ( i + 1 ) ) ); }
} else { // the trash that is IE
this.diffData[0][i] = ie_getElementById ( html, 'mw-diff-otitle' + ( i + 1 ) ).text;
this.diffData[1][i] = ie_getElementById ( html, 'mw-diff-ntitle' + ( i + 1 ) ).text;
}
}
// step 2 - remove that from the visible diff
var allTables = html.getElementsByTagName ( 'table' );
for ( var i = 0; i < allTables.length; i ++ ) {
if ( allTables[i].className == 'diff' ) break;
}
if ( i >= allTables.length ) i = ( allTables.length - 1 );
if (i < 0 ) { var newPage = true; } else { var newPage = false; }
if ( newPage == false ) {
var table = document.createElement ( 'table' );
table.className = 'diff';
// in order to add content to the table in IE, we must first add it to a diff. We also handle styling IE output here.
if ( ie ) {
var tempIEDiv = document.createElement ( 'div' );
var tempIETable = ie_cloneNode ( allTables[i] );
tempIEDiv.appendChild ( tempIETable );
//tempIEDiv.innerHTML = this.flag(tempIEDiv.innerHTML);
tempIEDiv.innerHTML = tempIEDiv.innerHTML.replace(/class='?diff-context'?/ig, 'style="background-color: #ddddff;"');
tempIEDiv.innerHTML = tempIEDiv.innerHTML.replace(/class='?diff-addedline'?/ig, 'style="background-color: #ccddcc;"');
tempIEDiv.innerHTML = tempIEDiv.innerHTML.replace(/class='?diff-deletedline'?/ig, 'style="background-color: #ffffaa;"');
tempIEDiv.innerHTML = tempIEDiv.innerHTML.replace(/class='?diff['>]/ig, 'style="width: 100%; font-size: 12px; background-color: #ededff;"');
tempIEDiv.innerHTML = tempIEDiv.innerHTML.replace(/(del |ins )class=['"]?.*?diffchange.*?['"]?(>)?/ig, '$1style="text-decoration: none; font-weight: bold; color: #ff0000;"$2');
tempIEDiv.innerHTML = tempIEDiv.innerHTML.replace(/class='?diff-marker'?/ig, 'style="width: '+markerwidth+'px; font-size: 14px; font-weight: bold;"');
tempIEDiv.innerHTML = tempIEDiv.innerHTML.replace(/class='?diff-content'?/ig, 'style="width: '+contentwidth+'px;"');
table.appendChild ( tempIEDiv );
} else {
table.innerHTML = allTables[i].innerHTML.toString();
var size = iglooSettings.diffFontSize;
table.innerHTML = table.innerHTML.replace ( /class="diff-addedline"/ig, 'class="diff-addedline" style="font-size: '+size+'px;"' );
table.innerHTML = table.innerHTML.replace ( /class="diff-context"/ig, 'class="diff-context" style="font-size: '+size+'px;"' );
table.innerHTML = table.innerHTML.replace ( /class="diff-deletedline"/ig, 'class="diff-deletedline" style="font-size: '+size+'px;"' );
table.innerHTML = this.flagProfanity(table.innerHTML);
}
// remove the built in rubbish
if ( table.getElementsByTagName ( 'tr' )[0] != null ) table.getElementsByTagName ( 'tr' )[0].parentNode.removeChild ( table.getElementsByTagName ( 'tr' )[0] );
// add our own (basically rubbish) stuff
// first, users
var newTr = document.createElement ( 'tr' );
if ( this.diffData[0][1] ) {
var oldEditor = this.diffData[0][1].substr( 0, this.diffData[0][1].indexOf('(talk') );
} else { var oldEditor = '? missing - report ?'; }
if ( this.diffData[1][1] ) {
var newEditor = this.diffData[1][1].substr( 0, this.diffData[1][1].indexOf('(talk') );
} else { var newEditor = '? missing - report ?'; }
// if we don't have the user for this diff, we might as well set it, even if something goes wrong; it's better than nothing
if ( typeof this.currentDiff[1] == 'undefined' ) this.currentDiff[1] = newEditor;
if ( this.currentDiff[1] === true ) /* will be true if a revert fails; we should still try and score it */ this.currentDiff[1] = newEditor;
var newTd1 = document.createElement ( 'td' );
newTd1.innerHTML = +oldEditor+;
newTd1.setAttribute ( 'colspan', '2' );
newTd1.setAttribute ( 'align', 'center' );
newTd1.setAttribute ( 'width', '50%' );
var newTd2 = document.createElement ( 'td' );
newTd2.innerHTML = +newEditor+;
newTd2.setAttribute ( 'colspan', '2' );
newTd2.setAttribute ( 'align', 'center' );
newTd2.setAttribute ( 'width', '50%' );
newTr.appendChild(newTd1); newTr.appendChild(newTd2);
table.insertBefore(newTr, table.firstChild);
// second, summaries
var newTr = document.createElement('tr');
if ( ( typeof this.diffData[0][2] != 'undefined' ) && ( this.diffData[0][2] != false ) ) { var oldSummary = this.diffData[0][2]; } else { var oldSummary = ''; }
if ( ( typeof this.diffData[1][2] != 'undefined' ) && ( this.diffData[1][2] != false ) ) { var newSummary = this.diffData[1][2]; } else { var newSummary = ''; }
if ( oldSummary.indexOf ( '(del/undel)' ) > -1 ) oldSummary = oldSummary.substr ( 0, oldSummary.indexOf ( '(del/undel)' ) );
if ( newSummary.indexOf ( '(del/undel)' ) > -1 ) newSummary = newSummary.substr ( 0, newSummary.indexOf ( '(del/undel)' ) );
var newTd1 = document.createElement('td');
newTd1.innerHTML = +oldSummary+;
newTd1.setAttribute('colspan','2');
newTd1.setAttribute('align','center');
var newTd2 = document.createElement('td');
newTd2.innerHTML = +newSummary+;
newTd2.setAttribute('colspan','2');
newTd2.setAttribute('align','center');
newTr.appendChild(newTd1); newTr.appendChild(newTd2);
table.insertBefore(newTr, table.childNodes[1]);
} else {
// step 2 - get the page content
var table = document.createElement ( 'div' );
table.setAttribute ( 'style', 'font-size: 12px;' );
table.className = 'diff';
var text = this.ajax.pageRequest.responseText;
text = text.substring ( text.indexOf ( '' ), text.indexOf ( '