Utilisateur:Creasy/AdvancedContrib.dev.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) ;

Chrome / Internet Explorer / Opera : maintenez la touche Ctrl en cliquant sur le bouton Actualiser ou pressez Ctrl-F5.
//{{Projet:JavaScript/Script|AdvancedContribs}}

//<source lang=javascript><pre><nowiki>

	var ACobj = {}
	
	ACobj.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
	if(mw.config.get('wgNamespaceNumber')!=0 || mw.config.get('wgAction') == "history") 
		addOnloadHook(function ()
		{
			var list = document.getElementById('p-cactions')
		
			AC_initVarsMin()
		
			if(!list) return
			list = list.childNodes[3].childNodes[1]
		
			var elt = document.createElement('li')
			var a = document.createElement('a')
			
			a.onclick = toggleFollowAnchor
			a.href = "#"
			a.id = "caa_userFollow"
			a.appendChild(document.createTextNode("Suivi des users"));
			elt.appendChild(a)
			list.appendChild(elt)
			
			if(AC_changeFollowListLink)
			{
				var li = document.getElementById("pt-watchlist")
				if(li) li.firstChild.href = "/wiki/Utilisateur:Maloq/AdvancedContribs"
			}
		})
	
	//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
		ACobj.USERCONTRIBLIMIT = 0 //type pour addWarning()
		ACobj.WATCHLISTLIMIT = 1 //type pour addWarning()
		ACobj.HISTORYLIMIT = 2 //type pour addWarning()
		ACobj.CHANGEVERSION = 3 //type pour addWarning()
		ACobj.INITTITLE = 4
		
		/*
		ACobj.CellWithAnchor //une cellule et un anchor à l'intérieur, pour la duplication
		ACobj.DateRegExp  //la regexp pour les date
		ACobj.ArticlesWrotten //l'objet qui contient tous les articles deja marqué
		ACobj.timeStampLimit //la date a partir de laquelle on choppe les historique en timeStamp
		ACobj.dateLimit //la date a partir de laquelle on choppe les historique
		
		ACobj.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
		/*
		ACobj.delayContrib_LOC
		ACobj.includeFollowList_LOC
		ACobj.version_LOC //n° de version en cours, mise sur le page de AC
		*/
		ACobj.version = "0.9.24"  //n° de version du script
		
		addOnloadHook(function ()
		{
			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
			}
			
			AC_initVars()
			
			ACobj.version_LOC = getVersionNo(div.textContent)
			ACobj.delayContrib_LOC = AC_delayContrib
			ACobj.includeFollowList_LOC = AC_includeFollowList
			
			div.innerHTML= "<style>.trover{} " +
						".trover:hover{background:#e5e5e5} </style>" +
						"<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()'>Enregistrer 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
			ACobj.DateRegExp = new RegExp();
			ACobj.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
			ACobj.CellWithAnchor = document.createElement("td")
			ACobj.CellWithAnchor.appendChild(document.createElement("a"))
			ACobj.CellWithAnchor.style.paddingRight='3px'
			ACobj.CellWithAnchor.style.width='0%'
			
			getData()
		});
		
	}


	//initialise les variables nécéssaire à l'onglet sans avoir la liste: optimiser le temps
	function AC_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 AC_initVars()
	{	
		try {if(AC_BlackList){}}
		catch(e){ AC_BlackList = new Array() }
		
		try {if(AC_WhiteList){}}
		catch(e){ AC_WhiteList = 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 = 5000 }
		
		try {if(AC_historyLimit){}}
		catch(e){ AC_historyLimit = 500 }
		
		try {if(AC_userContribLimit){}}
		catch(e){ AC_userContribLimit = 500 } 
		
		try {if(AC_blackListColor){}}
		catch(e){ AC_blackListColor = '#FFB0B0' } 
		
		try {if(AC_whiteListColor){}}
		catch(e){ AC_whiteListColor = '#B0B0FF' }
		
		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 }

                try {if(AC_linkToContrib){}}
		catch(e){ AC_linkToContrib = 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="' +
		'//fr.wikipedia.org/w/index.php?title=' + encodeURIComponent(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" >$1</a>');
		string = string.replace(/\>[^\]\|<]*\|([^\]\|<]*)</g, ">$1<");

		//les commentaires
		string = string.replace(/\/\*([^\*\/]*)\*\//g, "<span style='color:#888888'>/*$1*/</span>");

		//les {{a|article}}
		string = string.replace(/\{\{a\|([^\}]*)\}\}/g, '<a href="'+mw.config.get('wgServer')+mw.config.get('wgScriptPath')+'/index.php?title=$1&redirect=no">$1</a>');

		//les {{u|utilisateur}}
		string = string.replace(/\{\{u\|([^\}]*)\}\}/g, '<a href="'+mw.config.get('wgServer')+mw.config.get('wgScriptPath')+'/index.php?title=Utilisateur:$1">$1</a>');

		return string 
	}
	
	//parse la chaine de caratère et la transforme en date
	function parseDate(string)
	{
		var now = new Date();
		var match = ACobj.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//////////////////////////////////
	
	
	//change l etat de l'user (0: rien, 1 suivi, 2 confiance)
	function toggleUserAction(user, action)
	{
		var BLPos = AC_BlackList.indexOf(user)
		var WLPos = AC_WhiteList.indexOf(user)
		var Summeray
	
		if(action == 1 && BLPos==-1)
		{
			AC_BlackList[AC_BlackList.length] = user
			if(WLPos!=-1) AC_WhiteList.splice(WLPos, 1)
			
			ajaxSetUsersPage('Rajoute ' + user + ' dans la liste de surveillance',user, AC_blackListColor)
		}
		else if(action == 2 && WLPos==-1)
		{
			AC_WhiteList[AC_WhiteList.length] = user
			if(BLPos!=-1) AC_BlackList.splice(BLPos, 1)
			
			ajaxSetUsersPage('Rajoute ' + user + ' dans la liste de confiance',user, AC_whiteListColor)
		}	
		else if(action == 0 && (WLPos!=-1 || BLPos!=-1))
		{
			if(BLPos!=-1) AC_BlackList.splice(BLPos, 1)
			if(WLPos!=-1) AC_WhiteList.splice(WLPos, 1)
			
			ajaxSetUsersPage('supprime ' + user + ' des deux listes',user, AC_normalListColor)
		}
		
		document.AC_infoBox.style.display="none"
	}
	
	
	//affiche la petite boite de dialogue
	function toggleUser(e)
	{
		var user = this.AC_user
		
		var AC_infoBox = document.AC_infoBox
		
		if(!AC_infoBox)
		{
			AC_infoBox = document.createElement("div")
			AC_infoBox.style.border="1px solid grey"
			AC_infoBox.style.background="#FFFFFF"
			
			AC_infoBox.style.zIndex = "2"
			AC_infoBox.style.position = "absolute"
			
			
			var labels = ['Aucune liste','Liste de surveillance','Liste de confiance']
			for(var i=0; i!=labels.length;i++)
			{
				var input = document.createElement("input")
				var label = document.createElement("label")
				label.htmlFor='AC_infoboxCheck' + i
				label.textContent = labels[i]
				label.style.cursor="pointer"
				label.marginBottom='2px'
				input.name = "AC_infobox"
				input.id='AC_infoboxCheck' + i
				input.type='radio'
				input.style.width = '12px'
				input.action=i
				
				AC_infoBox.appendChild(input)
				AC_infoBox.appendChild(label)
				AC_infoBox.appendChild(document.createElement('br'))
				
				input.onclick = function()
				{
					if(!this.checked) return
					toggleUserAction(document.AC_infoBox.user, this.action)
				}
				
				AC_infoBox["input"+i] = input
			}
		
			document.body.appendChild(AC_infoBox)
			document.AC_infoBox = AC_infoBox
		}
		else if(AC_infoBox.style.display=="")
		{
			AC_infoBox.style.display="none"
			if(user==AC_infoBox.user)	return
		}
		
		
		AC_infoBox["input"+0].checked = true
		
		var inBlackList = AC_BlackList.indexOf(user) != -1
		var inWhiteList = AC_WhiteList.indexOf(user) != -1
			
		if(inBlackList) AC_infoBox["input"+1].checked = true
		else if(inWhiteList) AC_infoBox["input"+2].checked = true
			
		
		
		var posx = 300;
		var posy = 300;
		
		if (e.pageX) 	
		{
			posx = e.pageX;
			posy = e.pageY;
		}
		else if (e.clientX ) 	
		{
			posx = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
			posy = e.clientY + document.body.scrollTop	+ document.documentElement.scrollTop;
		}
		
		AC_infoBox.style.top = (posy + 15) +  "px"
		AC_infoBox.style.left = posx + "px"
		
		AC_infoBox.user = user						
		AC_infoBox.style.display=""	
	}
	
	//change l'etat des anchors associé a user (FollowedColor: couleur à mettre)
	function setAnchorState(user, FollowedColor) 
	{
		var i
		var len = ACobj.UsersAnchors[user].length
		
		for(i=0;i!=len;i++)
			ACobj.UsersAnchors[user][i].style.background = FollowedColor
	
	}
	
	//lupin :p
	function getUserFromHref(href)
	{
		var regexp = new RegExp(/(\/wiki\/Utilisateur:|\/wiki\/Sp(e|é|%C3%A9)cial:Contributions\/|\/w\/index.php\?title=Utilisateur:|\/wiki\/Discussion_Utilisateur:)([^\/&]+)([&]?.*)$/)
		var match = regexp.exec(href)
		
		if(match) return decodeURIComponent(match[3]).replace(/_/g, " ")
		
		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
	
		AC_initVars()
	
		if(!ACobj.Anchors)
		{
			first = true
			ACobj.UsersAnchors = new Object()
			ACobj.Anchors = new Array()
			localAnchors = document.getElementById('bodyContent').getElementsByTagName('a')
		}
		else
		{
			localAnchors = ACobj.Anchors
		}
	
		len = localAnchors.length
	
		if(ACobj.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(!ACobj.UsersAnchors[user]) ACobj.UsersAnchors[user] = new Array()
						ACobj.UsersAnchors[user][ACobj.UsersAnchors[user].length] = localAnchors[i]
						ACobj.Anchors[ACobj.Anchors.length] = localAnchors[i]
	
						localAnchors[i].AC_user = user
						localAnchors[i].AC_hrefSave = localAnchors[i].href
						localAnchors[i].href = '#'
						
						localAnchors[i].onclick =toggleUser
						
						if(AC_BlackList.indexOf(user)!=-1 ) localAnchors[i].style.background = AC_blackListColor
						else if(AC_WhiteList.indexOf(user)!=-1 ) localAnchors[i].style.background = AC_whiteListColor
						else localAnchors[i].style.background = AC_normalListColor
					}
				}  
			}
			else
			{
				for(i=0;i!=len;i++)
				{
					user = localAnchors[i].AC_user
					localAnchors[i].href = '#'
					localAnchors[i].onclick =toggleUser
					
					if(AC_BlackList.indexOf(user)!=-1 ) localAnchors[i].style.background = AC_blackListColor
					else if(AC_WhiteList.indexOf(user)!=-1 ) localAnchors[i].style.background = AC_whiteListColor
					else localAnchors[i].style.background = AC_normalListColor
	
				}
			}
	
			document.getElementById('caa_userFollow').textContent='Liens users normaux'
	
			ACobj.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').textContent='Suivi des users'
	
			ACobj.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 ""
	}
	
	
	
	//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 (ACobj.USERCONTRIBLIMIT):
			{
				str = "La limite de requête (" + AC_userContribLimit + ") a été atteinte pour les contributions de " + htmlUserLink(Data1)
				break
			}
			case (ACobj.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 (ACobj.HISTORYLIMIT):
			{
				str = "La limite de requête (" + AC_historyLimit + ")  a été atteinte pour l'historique de " + htmlArticleLink(Data1)
				break
			}
			case (ACobj.CHANGEVERSION):
			{
				str = "<big>Une nouvelle version d'<b>AdvancedContribs</b> est sortie, rechargez votre cache.</big>"
				break
			}
			case (ACobj.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()
	{
		ACobj.delayContrib_LOC = document.getElementById('AC_delayContrib').value
		ACobj.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(/'/,"\\'") + "'"
		}
		
		res = res + "); //liste des users suivi\n" +
		"var AC_WhiteList = new Array("
		
		for(i=0;i!=AC_WhiteList.length;i++)
		{
			if(i!=0) 	res = res + ","
			res = res + "'" + AC_WhiteList[i].replace(/'/,"\\'") + "'"
		}
		
		
		return res + "); //liste des users de confiance\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_whiteListColor='" + AC_whiteListColor + "'; //la couleur de fond d'un utilisateur de la whitelist\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, user, color)
	{
		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:" + encodeURIComponent(mw.config.get('wgUserName'))  + "/AdvancedContribs.js&action=submit", false)
						
					reqSubmit.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
					reqSubmit.send(post)
					if(user && color) setAnchorState(user, color)
				}
			}
		}
		
		req.open("GET","/w/index.php?title=Utilisateur:" + encodeURIComponent(mw.config.get('wgUserName'))  + "/AdvancedContribs.js&action=edit")
		req.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
		req.send(null)
	}
	
	
	//met la page en attente de la fin des chargements ou la libère
	//true pour dire qu'elle fait les requêtes, false pour la libérer
	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(ACobj.INITTITLE)
		
		if(ACobj.version_LOC != ACobj.version) addWarning(ACobj.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 ACobj.delayContrib_LOC jours
		ACobj.dateLimit = new Date(date.getTime() - ACobj.delayContrib_LOC * 60 * 60 * 1000)
		ACobj.timeStampLimit = getTimeStamp(ACobj.dateLimit)
		
		ACobj.ArticlesWrotten = new Object()
		
		if(ACobj.FollowState == true) toggleFollowAnchor()
		ACobj.FollowState = false 
		ACobj.Anchors = false //pour reforcer l'état des anchors
		
		ACobj.requestStack = 0
		
		setPageLocked(true)
	}
	
	
	//lance les requetes qui vont chercher les contributions des utilisateurs
	function getData()
	{
		var i
	
		initPage()
	
		if(ACobj.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.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, ACobj.USERCONTRIBLIMIT, req.user)
						
						getHistoriesFromUserContrib(req.responseXML, req.user)
					}
					
					ACobj.requestStack-- 
					if(ACobj.requestStack==0) setPageLocked(false)
				}
			}
		}
		
		req.open("GET","/w/api.php?action=query&list=usercontribs&ucuser=" + user + "&ucprop=title&uclimit=" + AC_userContribLimit + "&format=xml&ucend=" + ACobj.timeStampLimit, true)
			
		req.setRequestHeader('Content-Type', 'text/xml; charset=utf-8')
		ACobj.requestStack++
		req.send(null)
	}
	
	//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, ACobj.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])
					}
					
					ACobj.requestStack-- 
					if(ACobj.requestStack==0) setPageLocked(false)
				}
			}
		}
		
		req.open("GeT", "/w/api.php?action=query&generator=watchlist&gwlallrev&prop=revisions&gwllimit=" + AC_watchListLimit + "&format=xml&gwlend=" + ACobj.timeStampLimit, true)
		req.setRequestHeader('Content-Type', 'text/xml; charset=utf-8')
		ACobj.requestStack++
		req.send(null)
	}
	
	//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)
		}
	}
	
	//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(ACobj.ArticlesWrotten[article]) continue
			if(article.length == 0) continue
			getArticleHistory(article)
		}
		
	}
	
	//lance la requete Ajax qui cherche l'historique
	function getArticleHistory(article)
	{
		ACobj.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, ACobj.HISTORYLIMIT, req.article)
						
						History = req.responseXML.getElementsByTagName('revisions') 
						if(History.length != 0)
						{
							History = History[0].childNodes
							writeHistory(History, req.article, true)
						}
					}
					
					ACobj.requestStack-- 
					if(ACobj.requestStack==0) setPageLocked(false)
				}
			}
		}
		
		req.open("GET","/w/api.php?action=query&titles=" + article + "&format=xml&prop=revisions&rvlimit=" + AC_historyLimit + "&rvend=" + ACobj.timeStampLimit, true)
		req.setRequestHeader('Content-Type', 'text/xml; charset=utf-8')
		ACobj.requestStack++
		req.send(null)
	}
	
	//é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
			ACobj.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)
			if(AC_WhiteList.indexOf(user) == -1 || article.indexOf(":") != -1)
				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.className='trover'
		if(article == 'Discussion Utilisateur:' + mw.config.get('wgUserName')) row.style.backgroundColor = '#fef3d8'
		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))
		
		insertCellText(row, " ").style.width='100%' 
		
	}
	
	
	
	
	//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
		var hide = true 
		
		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=9
		
		subtable.cellPadding = 0
		subtable.cellSpacing = 0 
		subtable.id = '_ACH_' + article
		subtable.className= 'tablecontrib'
		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])
				hide = hide && (AC_WhiteList.indexOf(user) != -1)
				
				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])
				hide = hide && (AC_WhiteList.indexOf(user) != -1)
	
				if(userList[user]) userList[user]++
				else userList[user] = 1
			}
		}
		
		if(!hide || article.indexOf(":") != -1) //si tous les users viennent de la whitelist, on le l'affiche pas
		{
			//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.className='trover'
			if(article == 'Discussion Utilisateur:' + mw.config.get('wgUserName')) mainrow.style.backgroundColor = '#fef3d8'
			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 = ""
		
		row.className='trover'
		
		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 = ''
		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(/'/g, "\\'") + '\')">#</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=ACobj.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=ACobj.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=ACobj.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=ACobj.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=ACobj.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=ACobj.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=ACobj.CellWithAnchor.cloneNode(true)
		
		cell.firstChild.title = article
		cell.firstChild.href = "/wiki/" + article.replace(/ /g,"_");
		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 + '" href="/wiki/' + encodeURIComponent(article) + '">' + article + '</a>'
	}
	
	//lien delete
	function htmlDeleteLink(article)
	{
		if (AC_displayDeleteLink)
			return '<a title="supprimer" href="/w/index.php?title=' + encodeURIComponent(article) + '&action=delete">' + 
			'<img width="14" height="14" style="margin-top:2px" src="//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)
		
		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)
	{
                // redirection des liens utilisateurs vers leurs contributions ou non
                var userLinkNamespace = "Utilisateur:";
                if (AC_linkToContrib) { userLinkNamespace = "Special:Contributions/"; }

		return '<a title="Utilisateur:' + User + '" href="/wiki/' + userLinkNamespace + encodeURIComponent(User) + '" ' + 
				iif(AC_BlackList.indexOf(User)!=-1, 'style="border-bottom:1px solid red"','') + '>' + User + '</a>'
	
	}

//</nowiki></pre></source>