Aller au contenu

Utilisateur:Bibifricotin/monobook.js

Une page de Wikipédia, l'encyclopédie libre.
Note : après avoir enregistré la page, vous devrez forcer le rechargement complet du cache de votre navigateur pour voir les changements.

Mozilla / Firefox / Konqueror / Safari : maintenez la touche Majuscule (Shift) en cliquant sur le bouton Actualiser (Reload) ou pressez Maj-Ctrl-R (Cmd-R sur Apple Mac) ;

Firefox (sur GNU/Linux) / Chrome / Internet Explorer / Opera : maintenez la touche Ctrl en cliquant sur le bouton Actualiser ou pressez Ctrl-F5.
//Nouveau:
//bug de encodeURIcomponent
//bug du multiple diff (direction=prev
//bug de wikiparse (mauvais caracteres)
 
if(mw.config.get('wgUserGroups').indexOf("user") != -1) 
{
	var AC_UsersAnchors //objet contenant les anchors de chaque users, initialisé au premier clic sur l'onglet suivi des users
	var AC_Anchors //tableau contenant tous les anchors qui nous interresse
	var AC_FollowState = false //l'état des liens users (vers la page ou vers le javascript)
 
	loadJsForced("User:" + mw.config.get('wgUserName') + "/AdvancedContribs.js")
 
	//rajouter l'onglet suivi des users
	$(addFollowTab);
 
	//si on est dans la sous-page user/AdvancedContrib, alors on lance le bouzin	
	if (mw.config.get('wgTitle') == "Maloq/AdvancedContribs" && mw.config.get('wgAction') == "view")
	{	
		//on déclare les variables que si elles sont utiles
		var AC_USERCONTRIBLIMIT = 0 //type pour addWarning()
		var AC_WATCHLISTLIMIT = 1 //type pour addWarning()
		var AC_HISTORYLIMIT = 2 //type pour addWarning()
		var AC_CHANGEVERSION = 3 //type pour addWarning()
		var AC_INITTITLE = 4
 
		var AC_CellWithAnchor //une cellule et un anchor à l'intérieur, pour la duplication
		var AC_DateRegExp  //la regexp pour les date
		var AC_ArticlesWrotten //l'objet qui contient tous les articles deja marqué
		var AC_timeStampLimit //la date a partir de laquelle on choppe les historique en timeStamp
		var AC_dateLimit //la date a partir de laquelle on choppe les historique
 
		var AC_requestStack //pour bloquer les action quand les requets sont lancées
 
		//la variables locales sont la pour pouvoir charger la page sans sauvegarder les paramètres
		var AC_delayContrib_LOC
		var AC_includeFollowList_LOC
		var AC_version_LOC //n° de version en cours, mise sur le page de AC
		var AC_version = "0.9.9"  //n° de version du script
 
		$(startAdvancedContrib);
 
	}
}
 
//initialise les variables nécéssaire à l'onglet sans avoir la liste: optimiser le temps
function initVarsMin()
{
	try {if(AC_changeFollowListLink){}}
	catch(e){ AC_changeFollowListLink = false }
}
 
 
//initialise les variables pour la page de contrib, si elles n'existent pas, la fonction les crée
function initVars()
{	
	try	{if(AC_BlackList){}}
	catch(e){ AC_BlackList = new Array() }
 
	try {if(AC_debugFlag){}}
	catch(e){ AC_debugFlag = false }
 
	try {if(AC_delayContrib){}}
	catch(e){ AC_delayContrib = 24 }
 
	try {if(AC_includeFollowList){}}
	catch(e){ AC_includeFollowList = false }
 
	try {if(AC_watchListLimit){}}
	catch(e){ AC_watchListLimit = 500 }
 
	try {if(AC_historyLimit){}}
	catch(e){ AC_historyLimit = 50 }
 
	try {if(AC_userContribLimit){}}
	catch(e){ AC_userContribLimit = 50 } 
 
	try {if(AC_blackListColor){}}
	catch(e){ AC_blackListColor = '#FFB0B0' }
 
	try {if(AC_normalListColor){}}
	catch(e){ AC_normalListColor = '#B0FFB0' }
 
	try {if(AC_displayDeleteLink){}}
	catch(e){ AC_displayDeleteLink = false }
 
	try {if(AC_displayWarnings){}}
	catch(e){ AC_displayWarnings = true }
 
	try {if(AC_changeFollowListLink){}}
	catch(e){ AC_changeFollowListLink = false }
}
 
 
/////////////////////////////////////TOOLBOX  ///////////////////////////////////////////////////
 
//if en fonction
function iif(cond, ifTrue, ifFalse)
{
	if(cond) return ifTrue
 
	return ifFalse
}
 
//charge un js en forçant la purge du cache
function loadJsForced(page) 
{
	var date = new Date().getTime()
	document.write('<script type="text/javascript" src="' +
 	'http://fr.wikipedia.org/w/index.php?title=' + page +
 	'&action=raw&ctype=text/javascript&dontcountme=s&dummy=' + date + '"></script>');
}
 
//renvoi la string commentaire parsé pour avoir les liens
function wikiParse(string)
{
	string = string.replace(/&/, '&amp;');
	string = string.replace(/>/, '&gt;');
	string = string.replace(/</, '&lt;');
	string = string.replace(/"/, '&quot;');
 
	//les [[liens]]
	string = string.replace(/\[\[(([^\]\|]*)(.*?))\]\]/g, "<a href='"+mw.config.get('wgServer')+mw.config.get('wgScriptPath')+"/index.php?title=$2&redirect=no' target='_new'>$1</a>");
	string = string.replace(/\>[^\]\|<]*\|([^\]\|<]*)</g, ">$1<");
 
	//les commentaires
	string = string.replace(/\/\*(([^\*\/]*)(.*?))\*\//g, "<span style='color:#888888'>/*$1*/</span>");
 
	//les modèles
	string = string.replace(/\{\{(([^\}\|]*)(.*?))\}\}/g, "<a href='"+mw.config.get('wgServer')+mw.config.get('wgScriptPath')+"/index.php?title=Modèle:$2&redirect=no' target='_new'>$1</a>");
	string = string.replace(/\>([^\]\|<]*)\|([^\]\|<]*)</g, ">{{$1|$2}}<");
 
	return string 
}
 
//parse la chaine de caratère et la transforme en date
function parseDate(string)
{
	var now = new Date();
	var match = AC_DateRegExp.exec(string);
 
	if (!match) return now
 
	now.setFullYear(match[1],(match[2])-1, match[3])
	now.setHours(match[4], match[5], match[6],0)
 
	now.setTime(now.getTime() + (-now.getTimezoneOffset())*60*1000)
 
	return now
}
 
/////////////////////////////////////FONCTIONS LIEES A L'ONGLET//////////////////////////////////
 
//rajoute l'onglet suivi des users
function addFollowTab()
{
	var list = document.getElementById('p-cactions')
 
	initVarsMin()
 
	if(!list) return
	list = list.childNodes[3].childNodes[1]
 
	var elt = document.createElement('li')
	elt.innerHTML = "<a id='caa_userFollow' href='javascript:toggleFollowAnchor()'>Suivi des users</a>"
	list.appendChild(elt)
 
	if(AC_changeFollowListLink)
	{
		var li = document.getElementById("pt-watchlist")
		if(li) li.firstChild.href = "/wiki/Utilisateur:Maloq/AdvancedContribs"
	}
}
 
//change l'état d'un utilisateur (suivi ou non)
function toggleUser(User)
{
	var userPos = AC_BlackList.indexOf(User)
	var Summeray
 
	if(userPos == -1)
	{
		AC_BlackList[AC_BlackList.length] = User
		setAnchorState(User, true)
		ajaxSetUsersPage('Rajoute ' + User)
	}
	else
	{
		AC_BlackList.splice(userPos, 1)
		setAnchorState(User, false)
		ajaxSetUsersPage('Supprime ' + User)
	}	
}
 
//change l'etat des anchors associé a user (Followed: true pour mettre suivi, false pour mettre normal)
function setAnchorState(user, Followed) 
{
	var i
	var len = AC_UsersAnchors[user].length
 
	for(i=0;i!=len;i++)
	{
		if(Followed) AC_UsersAnchors[user][i].style.background = AC_blackListColor
		else AC_UsersAnchors[user][i].style.background = AC_normalListColor  
	}
}
 
//lupin :p
function getUserFromHref(href)
{
	var regexp = new RegExp(/(\/wiki\/Utilisateur:|\/wiki\/Special:Contributions\/)([^\/]+)$/)
	var match = regexp.exec(href)
 
	if(match) return decodeURIComponent(match[2]).replace("_", " ")
 
	return ""
}
 
//function qui cherches les anchor vers les pages users et qui change le href (soit vers la fonction js, soit vers la page user)
function toggleFollowAnchor() 
{
	var localAnchors
	var i, user, len
	var first = false
 
	initVars()
 
	if(!AC_Anchors)
	{
		first = true
		AC_UsersAnchors = new Object()
		AC_Anchors = new Array()
		localAnchors = document.getElementById('bodyContent').getElementsByTagName('a')
	}
	else
	{
		localAnchors = AC_Anchors
	}
 
	len = localAnchors.length
 
	if(AC_FollowState == false)
	{
		if(first) //on dédouble le for pour que ca soit plus rapide
		{
			for(i=0;i!=len;i++)
			{
				user = getUserFromHref(localAnchors[i].href)
 
				if(user!="")
				{
					if(!AC_UsersAnchors[user]) AC_UsersAnchors[user] = new Array()
					AC_UsersAnchors[user][AC_UsersAnchors[user].length] = localAnchors[i]
					AC_Anchors[AC_Anchors.length] = localAnchors[i]
 
					localAnchors[i].AC_user = user
					localAnchors[i].AC_hrefSave = localAnchors[i].href
					localAnchors[i].href = 'javascript:toggleUser("' + user + '")'
					if(AC_BlackList.indexOf(user)!=-1 ) localAnchors[i].style.background = AC_blackListColor
					else localAnchors[i].style.background = AC_normalListColor
				}
			}  
		}
		else
		{
			for(i=0;i!=len;i++)
			{
				user = localAnchors[i].AC_user
				localAnchors[i].href = 'javascript:toggleUser("' + user + '")'
				if(AC_BlackList.indexOf(user)!=-1 ) localAnchors[i].style.background = AC_blackListColor
				else localAnchors[i].style.background = AC_normalListColor
 
			}
		}
 
		document.getElementById('caa_userFollow').innerHTML='Liens users normaux'
 
		AC_FollowState = true
	}
	else
	{
		//la, le premier passage a deja rempli les tableau
		for(i=0;i!=len;i++)
		{	
			localAnchors[i].href = localAnchors[i].AC_hrefSave
			localAnchors[i].style.background=''
		}
		document.getElementById('caa_userFollow').innerHTML='Suivi des users'
 
		AC_FollowState = false
	}
}
 
////////////////////////////////////////FONCTIONS LIEES A LA LISTE, OU AUX DEUX
 
//cherche le numero de version dans le textContent de bodyContent
function getVersionNo(str)
{
	var regexp = new RegExp()
	var match
 
 
	regexp.compile(/§§§([^#]*)§§§/)
	match = regexp.exec(str)
 
	if(match) return match[1]
 
	return ""
}
 
 
//fonction qui lance le bouzin
function startAdvancedContrib()
{
	var div=document.getElementById('bodyContent')
 
	var getAnchorsFollowed = function()
	{
		var res = ""
 
		for(var i=0;i!=AC_BlackList.length;i++)
			res = res + htmlUserPageLink(AC_BlackList[i]) + "&nbsp;"
 
		return res
	}
 
	initVars()
 
	AC_version_LOC = getVersionNo(div.textContent)
	AC_delayContrib_LOC = AC_delayContrib
	AC_includeFollowList_LOC = AC_includeFollowList
 
	div.innerHTML= "<table><tr><td>Monter les contributions <select id='AC_delayContrib'>" + 
				"<option value='1' " + iif(AC_delayContrib==1, "SELECTED","") + ">de la dernière heure</option>" + 
				"<option value='3' " + iif(AC_delayContrib==3, "SELECTED","") + ">des 3 dernières heures</option>" + 
				"<option value='6' " + iif(AC_delayContrib==6, "SELECTED","") + ">des 6 dernières heures</option>" + 
				"<option value='12' " + iif(AC_delayContrib==12, "SELECTED","") + ">des 12 dernières heures</option>" + 
				"<option value='18' " + iif(AC_delayContrib==18, "SELECTED","") + ">des 18 dernières heures</option>" + 
				"<option value='24' " + iif(AC_delayContrib==24, "SELECTED","") + ">du dernier jour</option>" + 
				"<option value='48' " + iif(AC_delayContrib==48, "SELECTED","") + ">des deux derniers jours</option>" + 
				"<option value='72' " + iif(AC_delayContrib==72, "SELECTED","") + ">des trois derniers jours</option>" + 
				"<option value='168' " + iif(AC_delayContrib==168, "SELECTED","") + ">de la semaine dernière</option></select></td>" +
				"<input type=checkbox id='AC_includeFollowList' " + iif(AC_includeFollowList,"checked","") + ">" + 
				"<label for='AC_includeFollowList'>Inclure la liste de suivi</label>" + 
				"<td><button id='btn_reload' onclick='setLocalParameters()'>Recharger avec ces paramètres</button></td>" + 
				"<td><button id='btn_save' onclick='saveParameters()'>Enregistrez ces paramètres</button></td>" + 
				"</tr></table>" +
				"<small><div id='contribContent'>&nbsp;</div>" + 
				"<div id='WarningDiv' style='display:none;border:2px solid #FF9900;padding-left:3px'><b><big>Warnings</big></b><br></div>" + 
				"<div id='AlertDiv' style='display:none;border:2px solid #FF0000;padding-left:3px'><b><big>Alerts</big></b><br></div>" + 
				"<center><div>" + getAnchorsFollowed() + "</div>" +
				"<div>" + 
				"<a href='/wiki/Utilisateur:Maloq/AdvancedContribs/Todo' title='todo'>ToDo</a> - " +
				"<a href='/wiki/Utilisateur:Maloq/AdvancedContribs/Documentation' title='Documentation'>Documentation</a> - " +
				"<a href='/wiki/Utilisateur:" + mw.config.get('wgUserName') + "/AdvancedContribs.js' title='Vos paramètres'>Vos paramètres</a>"  +
				"</div></center></small>"
 
 
	//on crée la regexp pour le timestamp
	AC_DateRegExp = new RegExp();
	AC_DateRegExp.compile(/^(\d\d\d\d)-(\d\d)-(\d\d)T(\d\d):(\d\d):(\d\d)Z$/)
 
	//cette cellule est la cellule de base qui conttient un seul anchor
	AC_CellWithAnchor = document.createElement("td")
	AC_CellWithAnchor.appendChild(document.createElement("a"))
	AC_CellWithAnchor.style.paddingRight='3px'
	AC_CellWithAnchor.style.width='0%'
 
	getData()
}
 
//ligne de debug
function addAlert(Text)
{
	if(AC_debugFlag)
	{
		var div = document.getElementById('AlertDiv')
 
		if(!div)
			alert(Text)
		else
		{
			var newDiv = document.createElement('div')
			div.style.display=''
			newDiv.innerHTML = Text 
			div.appendChild(newDiv)
		}
	}
}
 
//affiche les warnings
function addWarning(Type, Data1)
{
	var div = document.getElementById('WarningDiv')
	var newDiv = document.createElement('div')
	var str
 
	if(AC_displayWarnings) div.style.display=''
 
	switch(Type)
	{
		case (AC_USERCONTRIBLIMIT):
		{
			str = "La limite de requête (" + AC_userContribLimit + ") a été atteinte pour les contributions de " + htmlUserLink(Data1)
			break
		}
		case (AC_WATCHLISTLIMIT):
		{
			str = "La limite de requête (" + AC_watchListLimit + ")  a été atteinte pour votre <a href='/wiki/Special:Watchlist'>liste de suivi</a>"
			break
		}
		case (AC_HISTORYLIMIT):
		{
			str = "La limite de requête (" + AC_historyLimit + ")  a été atteinte pour l'historique de " + htmlArticleLink(Data1)
			break
		}
		case (AC_CHANGEVERSION):
		{
			str = "<big>Une nouvelle version d'<b>AdvancedContribs</b> est sortie, rechargez votre cache.</big>"
			break
		}
		case (AC_INITTITLE):
		{
			str = "<big><b>Warnings</b></big>"
			div.innerHTML = ''
			div.style.display='none'
			break
		}
	}
 
	newDiv.innerHTML = str
 
	div.appendChild(newDiv)
}
 
//met la valeurs du formulaire dans les variables locales et recharge
function setLocalParameters()
{
	AC_delayContrib_LOC = document.getElementById('AC_delayContrib').value
	AC_includeFollowList_LOC = document.getElementById('AC_includeFollowList').checked
 
	getData()
}
 
 
//met les valeurs du formulaire dans les variables, sauvegarde et recharge la page
function saveParameters()
{
	AC_delayContrib = document.getElementById('AC_delayContrib').value
	AC_includeFollowList = document.getElementById('AC_includeFollowList').checked
 
	ajaxSetUsersPage("Modifie les paramètres")	
}
 
 
 
//renvoi une chaine de caractère en mettant des zero aux place vide, maximum 4 la taille
function toNString(num, length)
{
	num = num + ""
 
	while(num.length < length)
		num = "0" + num
 
	return num
}
 
//renvoi le timeStamp depuis l'object date
function getTimeStamp(date)
{
	return date.getFullYear() + "-" +
			toNString(date.getMonth() + 1, 2) + "-" +
			toNString(date.getDate(), 2) + "T" +
			toNString(date.getHours(), 2) + ":" +
			toNString(date.getMinutes(), 2) + ":" +
			toNString(date.getSeconds(), 2) + "Z"
}
 
 
//crée les variables en Js pour la sauvegarde
function getVariablesStrForSaving()
{
	var res = "var AC_BlackList = new Array("
	var i
 
	for(i=0;i!=AC_BlackList.length;i++)
	{
		if(i!=0) 	res = res + ","
		res = res + "'" + AC_BlackList[i].replace(/'/,"\\'") + "'"
	}
 
	return res + "); //liste des users suivi\n" +
	"var AC_debugFlag=" + AC_debugFlag + "; //infos de debogage (laisser à faux)\n" +
	"var AC_delayContrib=" + AC_delayContrib + "; //en heure, jusqu'a quand on va chercher les contribs\n" +
	"var AC_includeFollowList=" + AC_includeFollowList + "; //si on inclut les articles de la liste de suivi\n" +
 
	"var AC_watchListLimit=" + AC_watchListLimit + "; //limite de réponse de la requete de la liste de suivi\n" +
	"var AC_historyLimit=" + AC_historyLimit + "; //limite de réponse de la requete de l'historique d'un article\n" +
	"var AC_userContribLimit=" + AC_userContribLimit + "; //limite de réponse de la requete des contributions d'un user\n" +
	"var AC_changeFollowListLink=" + AC_changeFollowListLink + "; //si true, change le lien 'liste de suivi' vers la page advancedContrib\n" +
 
	"var AC_blackListColor='" + AC_blackListColor + "'; //la couleur de fond d'un user suivi en blacklist\n" +
	"var AC_normalListColor='" + AC_normalListColor + "'; //la couleur de fond d'un utilisateur non suivi\n" +
	"var AC_displayDeleteLink=" + AC_displayDeleteLink + "; //affiche un lien delete pour chaque article dans la liste (landry-mode)\n" +
 
	"var AC_displayWarnings=" + AC_displayWarnings + "; //affiche les warnings (souvent qd les limites sont atteintes)\n" 
}
 
//a aprtir de la source d'une page html, cherche la valeur de l'input
//todo: essayer le DOMParser
function getInputValueFromStr(str)
{
	var regexp = new RegExp()
	var match
	regexp.compile(/value=["']([^"']+)["']/)
 
	match = regexp.exec(str)
	if(match) return match[1]
 
	return ""
}
 
//change la page user/AdvancedContrib selon le tableau Users
function ajaxSetUsersPage(Summeray)
{
	var req=new XMLHttpRequest()
 
	req.onreadystatechange = function()
	{
		if(req.readyState == 4)
		{
			if(req.status==200)
			{			
				var regexp = new RegExp()
				var match
				var wpStarttime = ""
				var wpEdittime = "" 
				var wpEditToken = ""
				var wpWatchthis = ""
 
				regexp.compile(/(<input[^>]+name="wpStarttime"[^>]+>)/)
				match=regexp.exec(req.responseText)
				if(match) wpStarttime = getInputValueFromStr(match[1])
 
				regexp.compile(/(<input[^>]+name="wpEdittime"[^>]+>)/)
				match=regexp.exec(req.responseText)
				if(match) wpEdittime = getInputValueFromStr(match[1])
 
				regexp.compile(/(<input[^>]+name="wpEditToken"[^>]+>)/)
				match=regexp.exec(req.responseText)
				if(match) wpEditToken = getInputValueFromStr(match[1])
 
				regexp.compile(/(<input[^>]+name="wpWatchthis"[^>]+>)/)
				match=regexp.exec(req.responseText)
				if(match) wpWatchthis = getInputValueFromStr(match[1])
 
				var varStr = getVariablesStrForSaving()
				var reqSubmit=new XMLHttpRequest()
 
				var post = "wpTextbox1=" + encodeURIComponent(varStr) + "&wpSummary=" + encodeURIComponent(Summeray)
				post = post + "&wpStarttime=" + encodeURIComponent(wpStarttime)
				post = post + "&wpEdittime=" + encodeURIComponent(wpEdittime)
				post = post + "&wpEditToken=" + encodeURIComponent(wpEditToken)
				post = post + "&wpWatchthis=" + encodeURIComponent(wpWatchthis)
 
				reqSubmit.open("POST","/w/index.php?title=Utilisateur:" + mw.config.get('wgUserName')  + "/AdvancedContribs.js&action=submit", true)
 
				reqSubmit.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
				reqSubmit.send(post)
			}
		}
	}
 
	req.open("GET","/w/index.php?title=Utilisateur:" + mw.config.get('wgUserName')  + "/AdvancedContribs.js&action=edit", true)
	req.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
	req.send(null)
}
 
 
//renvoi true si l'user est une ip
function isIP(user)
{
	var match = user.split(".")
	var i
 
	if(match.length != 4) return false
 
	for(i=0;i!=4;i++)
	{
		match[i] = parseInt(match[i])
		if(isNaN(match[i])) return false
		if(match[i]<0 || match[i]>255) return false
	}
 
	return true
}
 
//met la page en attente de la fin des chargement ou la libere
//true pour dire qu'elle fait les requetes, false pour la liberer
function setPageLocked(state)
{
 
	document.getElementById('btn_save').disabled =state
	document.getElementById('btn_reload').disabled =state
 
}
 
 
//initialise la page pour qu'elle puisse recevoir les contribs
function initPage()
{
	var div = document.getElementById('contribContent')
	var table = document.createElement('table')
	var date = new Date()
 
	addWarning(AC_INITTITLE)
 
	if(AC_version_LOC != AC_version) addWarning(AC_CHANGEVERSION)
 
	table.id = 'tablecontrib'
	table.cellPadding = 0
	table.cellSpacing = 0
 
	div.innerHTML = ''
	div.appendChild(table)
 
	//jetlag
	date.setTime(date.getTime() + (date.getTimezoneOffset())*60*1000)
	//on recul de AC_delayContrib_LOC jours
	AC_dateLimit = new Date(date.getTime() - AC_delayContrib_LOC * 60 * 60 * 1000)
	AC_timeStampLimit = getTimeStamp(AC_dateLimit)
 
	AC_ArticlesWrotten = new Object()
 
	if(AC_FollowState == true) toggleFollowAnchor()
	AC_FollowState = false 
	AC_Anchors = false //pour reforcer l'état des anchors
 
	AC_requestStack = 0
 
	setPageLocked(true)
}
 
 
//lance les requetes qui vont chercher les contributions des utilisateurs
function getData()
{
	var i
 
	initPage()
 
	if(AC_includeFollowList_LOC)
		getDataFollowList()
	else //c'est la liste de suivi qui appellera celle la
		for(i=0;i<AC_BlackList.length;i++)
			getDataUserContrib(AC_BlackList[i])
}
 
//fait la requete des contributions de cet user
function getDataUserContrib(user)
{
	var i
	var req=new XMLHttpRequest()
 
	req.user = user
	req.ip = isIP(user)
	req.onreadystatechange = function()
	{
		if(req.readyState == 4)
		{
			if(req.status==200)
			{
				if(!req.responseXML) 
					addAlert("Echec lors de la requete des contributions de " + req.user)
				else 
				{
					cleanQueryContinue(req.responseXML, AC_USERCONTRIBLIMIT, req.user)
 
					if(req.ip) getHistoriesFromIpContrib(req.responseXML, req.user)
					else getHistoriesFromUserContrib(req.responseXML, req.user)
				}
 
				AC_requestStack-- 
				if(AC_requestStack==0) setPageLocked(false)
			}
		}
	}
 
	if(req.ip)
		req.open("GET","/w/query.php?what=usercontribs&titles=User:" + user + "&uclimit=" + AC_userContribLimit + "&format=xml", true)
	else
		req.open("GET","/w/api.php?action=query&list=usercontribs&ucuser=" + user + "&ucprop=title&uclimit=" + AC_userContribLimit + "&format=xml&ucend=" + AC_timeStampLimit, true)
 
	req.setRequestHeader('Content-Type', 'text/xml; charset=utf-8')
	req.send(null)
	AC_requestStack++
}
 
//fait la requete de la liste de suivi
function getDataFollowList()
{
	var req=new XMLHttpRequest()
 
	req.onreadystatechange = function()
	{
		if(req.readyState == 4)
		{
			if(req.status==200)
			{
				if(!req.responseXML) addAlert("Echec lors de la requete de votre liste de suvi")
				else 
				{
					cleanQueryContinue(req.responseXML, AC_WATCHLISTLIMIT, "")
 
					writeWatchList(req.responseXML)
 
					for(var i=0;i<AC_BlackList.length;i++) //pour pouvoir mettre l'async, on met ça
						getDataUserContrib(AC_BlackList[i])
				}
 
				AC_requestStack-- 
				if(AC_requestStack==0) setPageLocked(false)
			}
		}
	}
 
	req.open("GeT", "/w/api.php?action=query&generator=watchlist&gwlallrev&prop=revisions&gwllimit=" + AC_watchListLimit + "&format=xml&gwlend=" + AC_timeStampLimit, true)
	req.setRequestHeader('Content-Type', 'text/xml; charset=utf-8')
	req.send(null)
	AC_requestStack++ 
}
 
//nettoie les query-continue et affiche les warnings
function cleanQueryContinue(XmlDoc, alertType, data)
{
	var nodes = XmlDoc.getElementsByTagName('query-continue')
 
	if(nodes.length!=0)
	{
		var node = nodes[0]
		node.parentNode.removeChild(node)
		addWarning(alertType, data)
	}
}
 
 
//cherche les contributions d'ip
function getHistoriesFromIpContrib(XmlDoc, Ip)
{
	var XmlContribs = XmlDoc.getElementsByTagName('contributions')
	var i, len
	var article
	var date
 
	if(XmlContribs.length==0)
	{
		addAlert("impossible de trouver les contributions de " + User) 
		return
	}
 
	XmlContribs = XmlContribs[0].childNodes
 
	len = XmlContribs.length
 
	for(i=0; i<len; i++)
	{
		date = parseDate(XmlContribs[i].attributes.timestamp.value)
		article = XmlContribs[i].textContent
 
		if(AC_dateLimit.getTime()> date.getTime()) break;
 
		if(AC_ArticlesWrotten[article]) continue
		if(article.length == 0) continue
		getArticleHistory(article)
	}
}
 
//prend les contribution d'un utilisateur, et cherche l'historique de tous les articles ou il a contribué
function getHistoriesFromUserContrib(XmlDoc, User)
{
	var XmlContribs = XmlDoc.getElementsByTagName('usercontribs')
	var i, len, article
 
	if(XmlContribs.length==0)
	{
		addAlert("impossible de trouver les contributions de " + User)
		return
	}
 
	XmlContribs = XmlContribs[0].childNodes //pour eviter le query-continue
 
	len = XmlContribs.length
 
	for(i=0;i<len;i++)
	{
		article = XmlContribs[i].attributes.title.value
		if(AC_ArticlesWrotten[article]) continue
		if(article.length == 0) continue
		getArticleHistory(article)
	}
 
}
 
//lance la requete Ajax qui cherche l'historique
function getArticleHistory(article)
{
	AC_ArticlesWrotten[article] = true
 
	var req=new XMLHttpRequest()
	req.article = article
	req.onreadystatechange = function()
	{
		if(req.readyState == 4)
		{
			if(req.status==200)
			{
 
				if(!req.responseXML) addAlert("Echec lors de la requete de l'historique de " + req.article)
				else
				{
					var History
 
					cleanQueryContinue(req.responseXML, AC_HISTORYLIMIT, req.article)
 
					History = req.responseXML.getElementsByTagName('revisions') 
					if(History.length != 0)
					{
						History = History[0].childNodes
						writeHistory(History, req.article, true)
					}
				}
 
				AC_requestStack-- 
				if(AC_requestStack==0) setPageLocked(false)
			}
		}
	}
 
	req.open("GET","/w/api.php?action=query&titles=" + article + "&format=xml&prop=revisions&rvlimit=" + AC_historyLimit + "&rvend=" + AC_timeStampLimit, true)
	req.setRequestHeader('Content-Type', 'text/xml; charset=utf-8')
	req.send(null)
 
	AC_requestStack++
 
}
 
//écrit la liste de suivi
function writeWatchList(XmlDoc)
{
	var Histories 
	var article, i
 
	Histories = XmlDoc.getElementsByTagName('revisions')
 
	for(i=0;i<Histories.length;i++)
	{
		article = Histories[i].parentNode.attributes.title.value
		writeHistory(Histories[i].childNodes, article, false) //les revisions sont marquées dans le mauvais ordre :( d'ou youngestFirst
		AC_ArticlesWrotten[article] = true
	}
}
 
//écrit l'historique de l'article
//youngestFirst a true si l'historique est classé du plus jeune au plus vieux
function writeHistory(History, article, youngestFirst)
{
	var table = document.getElementById('tablecontrib')
	var date
	var comment
	var revid
	var user
	var i
 
	if(History.length==1)
	{
		user = History[0].attributes.user.value
		if(History[0].attributes.comment) comment = History[0].attributes.comment.value
		else comment = ""
		revid = History[0].attributes.revid.value
		date = parseDate(History[0].attributes.timestamp.value)
 
		insertLineContrib(table, date, article, comment, revid, user, youngestFirst)
 
	}
	else
	{
		if(youngestFirst) date = parseDate(History[0].attributes.timestamp.value)
		else date = parseDate(History[History.length-1].attributes.timestamp.value)
		insertMultipleLineContrib(table, date, article, History, youngestFirst)
	}	
}
 
//rajoute une ligne html dans le tableau a la bonne place, pour les articles ou on a une seule contrib
//NotFollowed si l'article n'est pas suivi
function insertLineContrib(table, date, article, comment, revid, User, NotFollowed)
{
	var row, cell
	var pos 
	var strDate = stringDate(date)
 
	if(!table[strDate])
	{
		table[strDate] = true
		insertDateRow(table, date)
	}
 
	pos = getLineJusteBefore(table, date)
 
	row=table.insertRow(pos)
	row.style.whiteSpace='nowrap'
	row.timeStamp = date.getTime()
 
	insertCellsInMainRow(row, false, article, date, revid, revid, NotFollowed, htmlUserLink(User), comment)
 
}
 
 
function insertCellsInMainRow(row, expand, article, date, revid, oldid, NotFollowed, userStr, comment)
{
	var cell
 
	if(expand) 	insertCellHTML(row, htmlExpandLink(article)) 
	else insertCellText(row, "") 
 
	insertCellText(row, stringHour(date)) 
	insertHistCell(row, article) 
 
	if(expand) insertMultipleDiffCell(row, article, revid, oldid)
	else insertDiffCell(row, article, revid)
	insertEditCell(row,article)
 
	insertCellHTML(row, htmlDeleteLink(article)) 
	insertArticleCell(row, article, !NotFollowed)
 
	cell=insertCellHTML(row, "[" + userStr + "]")
	if(comment.length == 0) cell.colSpan = 2
	else insertCellHTML(row, wikiParse(comment))
}
 
 
 
 
//cree le sous tableau
//youngestFirst a true si l'historique est classé du plus jeune au plus vieux
function insertMultipleLineContrib(table, date, article, History, youngestFirst)
{
	var pos
	var strDate = stringDate(date)
	var subtable = document.createElement("table")
	var subcell, subrow, mainrow
	var user
	var userList = new Object()
	var first = true
	var usersStr
	var oldid, revid
 
	if(!table[strDate])
	{
		table[strDate] = true
		insertDateRow(table, date)
	}
 
	pos = getLineJusteBefore(table, date)
 
	//la ligne qui contient le tableau
	subrow=table.insertRow(pos)
	subrow.style.whiteSpace='nowrap'
	subrow.timeStamp = date.getTime()
	insertCellHTML(subrow,"")
	subcell=insertCellHTML(subrow, "")
	subcell.colSpan=8
 
	subtable.cellPadding = 0
	subtable.cellSpacing = 0 
	subtable.id = '_ACH_' + article
	subtable.style.display='none'
 
	if(youngestFirst)
	{
		revid = History[0].attributes.revid.value
		oldid = History[History.length-1].attributes.revid.value
 
		for(i=0;i!=History.length;i++)
		{
			user = insertLineSubContrib(subtable, article, History[i])
 
			if(userList[user]) userList[user]++
			else userList[user] = 1
		}
	}
	else
	{
		revid = History[History.length-1].attributes.revid.value
		oldid = History[0].attributes.revid.value
 
		for(i=History.length-1;i>=0;i--)
		{
			user = insertLineSubContrib(subtable, article, History[i])
 
			if(userList[user]) userList[user]++
			else userList[user] = 1
		}
	}
 
	//et on écrit la ligne principale, maintenant qu'on a les users
	usersStr = ""
	for(user in userList)
	{
		if(!first) usersStr = usersStr + "; "
		else first = false
		usersStr = usersStr +  htmlUserPageLink(user) 
		if(userList[user] != 1) usersStr = usersStr + " (" +userList[user] + "x)"
	} 
 
	mainrow=table.insertRow(pos)
	mainrow.style.whiteSpace='nowrap'
	mainrow.timeStamp = date.getTime()
	insertCellsInMainRow(mainrow, true, article, date, revid, oldid, youngestFirst, usersStr, "")
 
	subcell.appendChild(subtable)
}
 
//line de contribution d'un article, retourne l'user
function insertLineSubContrib(table, article, revision)
{
	var row =table.insertRow(-1)
	var date = parseDate(revision.attributes.timestamp.value)
	var user = revision.attributes.user.value
	var revid = revision.attributes.revid.value
	var comment = ""
 
	if(revision.attributes.comment) comment = revision.attributes.comment.value
 
	insertCellHTML(row, "&nbsp;&nbsp;&nbsp;")
	insertRevisionCell(row, article, date, revid)
	insertDiffCell(row, article, revid)
	insertCellHTML(row, htmlUserLink(user))
	insertCellHTML(row, wikiParse(comment))
 
	return user
} 
 
 
//affiche/cache un historique
function expandHistory(article)
{
	var table = document.getElementById('_ACH_' + article)
 
	if(!table) return
 
	if(table.style.display=='none') table.style.display = 'inline'
	else table.style.display = 'none'
}
 
//lien qui affiche/cache la table de l'historique d'un article
function htmlExpandLink(article)
{
	return '<a title="expand" href="javascript:expandHistory(\'' + article.replace(/'/, "\\'") + '\')">#</a>'
 
}
 
 
//rajoute une ligne avec la date
function insertDateRow(table, date)
{
	var localDate = new Date()
 
	localDate.setTime(date.getTime()) 
	localDate.setHours(23, 59, 59, 999)
 
	var pos = getLineJusteBefore(table, localDate)
	var row =table.insertRow(pos)
	var cell = row.insertCell(-1)
 
	row.timeStamp = localDate.getTime()
 
	cell.colSpan=8
	cell.style.paddingTop= '6px'
	cell.style.borderBottom = '1px solid blue'
	cell.innerHTML = "<b>" + stringDate(date) + "</b>"
}
 
//cherche la position pour l'insertion, y'a plus qu'a faire une recherche dichotomique. Un bisou à celui qui le fait :-)
function getLineJusteBefore(table, date)
{
	var i;
	var timeStamp = date.getTime()
 
	for(i=0; i<table.rows.length;i++)
	{
		if(timeStamp > table.rows[i].timeStamp)
			return i
	}
 
	return i
}
 
 
//insere une cellule formatée avec de l'html dedans
function insertCellHTML(row, innerHTML)
{
	var cell=row.insertCell(-1)
	cell.style.paddingRight='3px'
	cell.innerHTML = innerHTML
	cell.style.width='0%'
 
	return cell
}
 
//insere une cellule formatée avec du texte dedans
function insertCellText(row, Text)
{
	var cell=row.insertCell(-1)
	cell.style.paddingRight='3px'
	cell.textContent = Text
	cell.style.width='0%'
 
	return cell
}
 
 
//renvoi le nom du mois
function getMonthName(m)
{
	switch(m)
	{
		case 0: {return "janvier"}
		case 1: {return "février"}
		case 2: {return "mars"}
		case 3: {return "avril"} 
		case 4: {return "mai"}
		case 5: {return "juin"}
		case 6: {return "juillet"} 
		case 7: {return "août"}
		case 8: {return "septembre"}
		case 9: {return "octobre"} 
		case 10: {return "novembre"}
		case 11: {return "décembre"}
	}
 
	return ""
}
 
//renoi une chaine de caractère avec l'heure
function stringHour(d)
{
	return toNString(d.getHours(),2) + "h" + toNString(d.getMinutes(), 2) 
}
 
//renoi une chaine de caractère avec la date
function stringDate(d)
{
	return d.getDate() + " " + getMonthName(d.getMonth()) + " " + d.getFullYear() 
}
 
 
 
//insere une cellule formatée avec un anchor hist dedans
function insertHistCell(row, article) 
{
	var cell=AC_CellWithAnchor.cloneNode(true)
 
	cell.firstChild.title = 'historique'
	cell.firstChild.href = '/w/index.php?title=' + encodeURIComponent(article) + '&action=history'
	cell.firstChild.textContent = '(hist)'
 
	row.appendChild(cell)
}
 
//insere une cellule formatée avec un anchor vers une version précise
function insertRevisionCell(row, article, date, revid) 
{
	var cell=AC_CellWithAnchor.cloneNode(true)
 
	cell.firstChild.title = 'Version'
	cell.firstChild.href = "/w/index.php?title=" + encodeURIComponent(article) + "&oldid=" + revid
	cell.firstChild.textContent = stringHour(date)
 
	row.appendChild(cell)
}
 
//insere une cellule formatée avec un anchor vers un diff multipple
function insertMultipleDiffCell(row, article, revid, oldid) 
{
	var cell=AC_CellWithAnchor.cloneNode(true)
 
	cell.firstChild.title = 'diff'
	cell.firstChild.href = "/w/index.php?title=" + encodeURIComponent(article) + "&diff=" + revid + "&oldid=" + oldid + "&direction=prev"
	cell.firstChild.textContent = "(diff)"
 
	row.appendChild(cell)
}
 
//insere une cellule formatée avec un anchor vers un diff
function insertDiffCell(row, article, oldid) 
{
	var cell=AC_CellWithAnchor.cloneNode(true)
 
	cell.firstChild.title = 'diff'
	cell.firstChild.href = "/w/index.php?title=" + encodeURIComponent(article) + "&diff=prev&oldid=" + oldid
	cell.firstChild.textContent = "(diff)"
 
	row.appendChild(cell)
}
 
//insere une cellull formatée avec un lien édit
function insertEditCell(row, article) 
{
	var cell=AC_CellWithAnchor.cloneNode(true)
 
	cell.firstChild.title = "éditer"
	cell.firstChild.href = "/w/index.php?title=" + encodeURIComponent(article) + "&action=edit"
	cell.firstChild.textContent = "(edit)"
 
	row.appendChild(cell)
}
 
 
//insere une cellull formatée avec un lien édit
function insertRevertCell(row, article, token) 
{
	var cell=AC_CellWithAnchor.cloneNode(true)
 
	cell.firstChild.title = "Reverter"
	cell.firstChild.href = "/w/index.php?title=" + encodeURIComponent(article) + "&action=rollback&from=" + encodeURIComponent(mw.config.get('wgUserName')) + "&token=" + token
	cell.firstChild.textContent = "(revert)"
 
	row.appendChild(cell)
}
 
 
//insere une cellule formatée avec un anchor vers un article
function insertArticleCell(row, article, redBorder) 
{
	var cell=AC_CellWithAnchor.cloneNode(true)
 
	cell.firstChild.title = article
	cell.firstChild.href = "/wiki/" + article
	if(article.length>90) article = article.substring(0,87) + '...'
	cell.firstChild.textContent = article
 
	if(redBorder) cell.firstChild.style.borderBottom = '1px solid red'
 
	row.appendChild(cell)
}
 
//lien vers un article
function htmlArticleLink(article)
{
	return "<a title='" + article.replace(/'/, "\\'") + "' href='/wiki/" + encodeURIComponent(article).replace(/'/, "\\'") + "'>" + article + "</a>"
}
 
//lien delete
function htmlDeleteLink(article)
{
	if (AC_displayDeleteLink)
		return "<a title='supprimer' href='/w/index.php?title=" + encodeURIComponent(article).replace(/'/, "\\'") + "&action=delete'>" + 
		"<img width='14' height='14' style='margin-top:2px' src='http://upload.wikimedia.org/wikipedia/commons/thumb/c/ca/Crystal_error.png/14px-Crystal_error.png' longdesc='/wiki/Image:Crystal_error.png'/></a>"
 
	return ""
}
 
//lien user
function htmlUserLink(User)
{
	var UserURI = encodeURIComponent(User).replace(/'/, "\\'")
 
	return  htmlUserPageLink(User) + "<small>&nbsp;(" +
			"<a href='/wiki/Discussion_Utilisateur:" + UserURI + "'>d</a>&nbsp;" +
			"<a href='/wiki/Special:Contributions/" + UserURI + "'>c</a>&nbsp;" +
			"<a href='/wiki/Special:Blockip/" + UserURI + "'>b</a>)</small>" 			
}
 
//lien page user, souligne en rouge si suivi
function htmlUserPageLink(User)
{
	return "<a title='Utilisateur:" + User.replace("'", "\\'") + "' href='/wiki/Utilisateur:" + encodeURIComponent(User.replace("'", "\\'")) + "' " + 
			iif(AC_BlackList.indexOf(User)!=-1, "style='border-bottom:1px solid red'","") + ">" + User + "</a>"
 
}