/**
 * $Id: quontent.js 16512 2010-08-20 15:08:39Z plamondonl $

HyperTextArea http://hypertextarea.sourceforge.net
Type javascript:HyperTextArea.about() into your browser location on any page hosting a HyperTextArea for license details.

Quiboweb:
	Ajout du paramètre renderTo qui est le nom d'un div où on va mettre le texte, pour éviter les document.write

	Ajout aussi du paramètre setMenuFct qui est le nom d'une fonction a utiliser pour construire la barre de boutons, selon le contexte.
	La fonction doit prendre en paramètre un éditeur HyperTextArea.

	Ajout d'une variable membre this.cleanHtmlOnPaste qu'on peut mettre à true pour que les tags HTML soient enlevés lors d'un copier/coller
	(fonctionne seulement avec IE)

	Ajout d'une variable membre this.cleanHtmlOnSubmit qu'on peut mettre à true pour enlever les tags, attributs et styles non voulus.  Les tags
	permis sont donnés par this.allowedTags, les attributs par this.allowedAttributes et les styles par this.allowedStyles. Exemple:

		editor.allowedTags = new Array("body", "h3", "p", "li", "ol", "ul", "br", "span", "a", "strong", "em");
		editor.allowedAttributes = new Array("target", "href");
		editor.allowedStyles = new RegExp(/^\s*(font-weight: bold|font-style: italic)\s*$/i);
*/
/**
 * HyperTextArea()
 *
 * @param string	name 			: nom du champ qui sera envoyé au serveur
 * @param string	html 			: contenu du WYSIWYG
 * @param int 		width 			: largeur du WYSIWYG
 * @param int 		height 			: hauteur du WYSIWYG
 * @param string	resourcePath 	: path où se trouve le fichier js du WYSIWYG (obsolète ?)
 * @param string	styleSheetUrl 	: fichier .css pour l'affichage du contenu
 * @param string	delayRender 	: affichage direct après la création
 * @param string	renderTo	 	: identifiant du conteneur qui va recevoir le WYSIWYG
 * @param string	setMenuFct	 	: nom de la fonction qui va paramètrer l'affichage du menu du WYSIWYG (Attention : ne pas mettre de cote)
 * @param string	formId		 	: identifiant du formulaire dans lequel est contenu le WYSIWYG (nécessaire si upload d'images ou de documents)
 */
function HyperTextArea(name, html, width, height, resourcePath, styleSheetUrl, delayRender, renderTo, setMenuFct, formId){
	this.isRichText = false;
	this.rng = null;

	this.name = "frame_" + renderTo;
	this.postName = name;
	this.html = html||"";
	this.width = width;
	this.height = height;
	this.resourcePath = resourcePath||"";
	this.styleSheetUrl = styleSheetUrl||null;
	if(this.resourcePath.length && this.resourcePath.substring(this.resourcePath.length-1) != "/"){
		this.resourcePath = this.resourcePath + "/";
	}
	this.delayRender = delayRender||false;
	this.container = document.getElementById(renderTo);
	this.controlNames = new Array();
	this.controlsByName = new Array();
	this.toolbarNames = new Array();
	this.designModeRetryCount = 0;
	this.isSrcView = false;
	this.setMenuFct = setMenuFct;
	this.cleanHtmlOnSubmit = false;
	this.allowedTags = new Array();
	this.allowedAttributes = new Array();
	this.allowedStyles = new RegExp(/.*/);
	this.cleanHtmlOnPaste = false;
	this.formId = formId;

	this.init = function(){
		HyperTextArea.areas[this.name] = this;
		//check to see if designMode mode is available
		if (document.getElementById) {
			if (document.all) {
				//check for Internet Explorer 5+
				this.isRichText = true;
			} else {
				//check for browsers that support designmode
				//make sure that this is not safari (and perhaps other khtml based browsers) which returns "inherit" for document.designMode
				if (document.designMode && document.designMode.toLowerCase() != "inherit"){
					this.isRichText = true;
				}
			}
		}

		if (setMenuFct != null)
			setMenuFct(this);
		else {
			this.addControl(new Toolbar("toolbar0", this.width));

			this.addControl(new Menu("formatblock","formatblock", HyperTextArea.STYLETITLE,
				new Array("<p>", HyperTextArea.STYLES["p"], "<h2>", HyperTextArea.STYLES["h2"], "<h3>", HyperTextArea.STYLES["h3"])));

			this.addControl(new Menu("fontname","fontname", HyperTextArea.FONTTITLE,
				new Array("Arial, Helvetica, sans-serif","Arial","Courier New, Courier, mono","Courier New","Times New Roman, Times, serif","Times New Roman","Verdana, Arial, Helvetica, sans-serif","Verdana")));

			this.addControl(new Menu("fontsize","fontsize", HyperTextArea.FONTSIZETITLE,
				new Array(1,1,2,2,3,3,4,4,5,5,6,6,7,7)));

			this.addControl(new Toolbar("toolbar1", this.width));

			this.addControl(new TextFormatButton("bold",HyperTextArea.BOLD,SKINURL+"js/quontent/icons/post_button_bold.gif","bold"));
			this.addControl(new TextFormatButton("italic",HyperTextArea.ITALIC,SKINURL+"js/quontent/icons/post_button_italic.gif","italic"));
			//this.addControl(new Spacer());

			this.addControl(new TextFormatButton("policePlus",HyperTextArea.POLICEPLUS,SKINURL+"js/quontent/icons/post_button_policePlus.gif","policePlus"));
			this.addControl(new TextFormatButton("policeMoins",HyperTextArea.POLICEMOINS,SKINURL+"js/quontent/icons/post_button_policeMoins.gif","poluceMoins"));
			//this.addControl(new Spacer());

			this.addControl(new TextFormatButton("orderedlist",HyperTextArea.ORDEREDLIST,SKINURL+"js/quontent/icons/post_button_numbered_list.gif","insertorderedlist"));
			this.addControl(new TextFormatButton("unorderedlist",HyperTextArea.UNORDEREDLIST,SKINURL+"js/quontent/icons/post_button_list.gif","insertunorderedlist"));
			//this.addControl(new Spacer());

			this.addControl(new TextFormatButton("left",HyperTextArea.LEFT,SKINURL+"js/quontent/icons/post_button_left_just.gif","justifyleft"));
			this.addControl(new TextFormatButton("center",HyperTextArea.CENTER,SKINURL+"js/quontent/icons/post_button_centre.gif","justifycenter"));
			this.addControl(new TextFormatButton("right",HyperTextArea.RIGHT,SKINURL+"js/quontent/icons/post_button_right_just.gif","justifyright"));
			//this.addControl(new Spacer());

			this.addControl(new TextFormatButton("forecolor",HyperTextArea.FORECOLOR,SKINURL+"js/quontent/icons/post_button_textcolor.gif","forecolor"));
			this.addControl(new TextFormatButton("hilitecolor",HyperTextArea.HILITECOLOR,SKINURL+"js/quontent/icons/post_button_bgcolor.gif","hilitecolor"));
			//this.addControl(new Spacer());

			this.addControl(new Button("link", SKINURL+"js/quontent/icons/post_button_hyperlink.gif",HyperTextArea.LINK,"createLinkDialog"));
			this.addControl(new Button("insertTable",SKINURL+"js/quontent/icons/post_button_table.gif",HyperTextArea.INSERTTABLE,"insertTableDialog"));
			//this.addControl(new Spacer());

			this.addControl(new Button("code",SKINURL+"js/quontent/icons/post_button_code.gif",HyperTextArea.VIEWCODE,"toggleHTMLSrc"));
//			this.addControl(new TextFormatButton("code",HyperTextArea.VIEWCODE,SKINURL+"js/quontent/icons/post_button_code.gif","viewcode"));
			this.addControl(new Button("insertImage",SKINURL+"js/quontent/icons/post_button_image.gif",HyperTextArea.INSERTIMAGE,"displayExternalImage"));
			this.addControl(new Button("insertDocument",SKINURL+"js/quontent/icons/post_button_document.gif",HyperTextArea.INSERTDOCUMENT,"displayExternalDocument"));
			this.addControl(new TextFormatButton("outdent",HyperTextArea.OUTDENT,SKINURL+"js/quontent/icons/post_button_outdent.gif","outdent"));
			this.addControl(new TextFormatButton("indent",HyperTextArea.INDENT,SKINURL+"js/quontent/icons/post_button_indent.gif","indent"));
		}
	}

	this.addControl = function(control){
		control.resourcePath = this.resourcePath;
		control.area = this;
		i = this.controlNames.length
		this.controlNames[eval(i)] = control.name;
		this.controlsByName[control.name] = control;
	}

	this.getControl = function(name){
		return this.controlsByName[name];
	}

	this.replaceControl = function(oldName,newControl){
		if(this.getControl(oldName)){
			for(i=0;i<this.controlNames.length;i++){
				if(this.controlNames[i] == oldName){
					break;
				}
			}
		}else{
			i = this.controlNames.length;
		}
		newControl.area = this;
		newControl.resourcePath = this.resourcePath;
		this.controlNames[i] = newControl.name;
		this.controlsByName[newControl.name] = newControl;
	}

	this.insertControl = function(i,control){
		control.resourcePath = this.resourcePath;
		control.area = this;
		this.controlNames.splice(i,0, control.name);
		this.controlsByName[control.name] = control;
	}

	this.removeControl = function(name){
		for(i=0;i<this.controlNames.length;i++){
			if(this.controlNames[i] == name){
				this.controlNames.splice(i,1);
				return true;
			}
		}
		return false;
	}

	this.render = function(html){
		HyperTextArea.activeArea = this;
		text="this.render\n\n";
		for(i=0;i<this.controlNames.length;i++){
			text = text + "\t" + this.controlNames[i] + "\n";
		}
		if (this.isRichText) {
			this._renderRTE(html);
		} else {
			this._renderDefault(html);
		}
	}

	this._renderDefault = function(html){
		this.container.innerHTML += '<textarea id="' + this.name + '" style="width: ' + this.width + 'px; height: ' + this.height + 'px;">' + html + '</textarea>';
	}

	this.getControlNames = function(lable){
		text= lable + "\n\n";
		for(i=0;i<this.controlNames.length;i++){
			text = text + "\t" + this.controlNames[i] + "\n";
		}
		return text;

	}

	this._renderControls = function(){
		text = "";
		for(x=0;x<this.controlNames.length;x++){
			control = this.controlsByName[this.controlNames[x]];
			if(control){
				text = text + control.getRenderedText();
			}
		}
		text = text + '<td style="width: 100%; background-image: url('+SKINURL+'js/quontent/icons/spacer_final.gif);"></td></tr>';
		text = text + '</table>';
		this.container.innerHTML += text;
	}

	this._renderRTE = function(){
		//document.writeln('<style type="text/css">');
		//document.writeln('.btnImage {cursor: pointer; cursor: hand;}');
		//document.writeln('</style>');

		this._renderControls();
		text =  '<div style="display:none;" id="file_img_' + this.name + '_div">Image : <input type="file" name="file_img[' + this.name + ']" id="file_img_' + this.name + '" onchange="AIM.submit(document.' + this.formId + ', {\'onStart\' : function() {startCallback(\'' + this.name + '\',\'' + this.formId + '\',\'image\')}, \'onComplete\' : completeCallback})" /></div>';
		text += '<div style="display:none;" id="file_doc_' + this.name + '_div">Document : <input type="file" name="file_doc[' + this.name + ']" id="file_doc_' + this.name + '" onchange="AIM.submit(document.' + this.formId + ', {\'onStart\' : function() {startCallback(\'' + this.name + '\',\'' + this.formId + '\',\'document\')}, \'onComplete\' : completeCallback})" /></div>';
		text += '<iframe name="' + this.name + '"  id="' + this.name + '" width="' + this.width + 'px" height="' + this.height + 'px" ></iframe>';
		text += '<iframe width="145" height="130" id="cp' + this.name + '" name="cp' + this.name + '" marginwidth="0" marginheight="0" scrolling="no" style="visibility:hidden; position: absolute;"></iframe>';
		text += '<input type="hidden" id="hdn' + this.name + '" name="' + this.postName + '" value="">';
		//text += '<br /><input type="checkbox" id="chkSrc' + this.name + '" onclick="HyperTextArea.getArea(\''+this.name+'\').toggleHTMLSrc();" />&nbsp;View Source';

		this.container.innerHTML += text
		this.initializeContent(this.html);
		setTimeout('onHyperTextAreaLoad(\'' + this.name + '\')', 500);
	}

	this.initializeContent = function(html){
		HyperTextArea.activeArea = this;
		var frameHtml =
			//"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n" +
			//"<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"fr\" xml:lang=\"fr\">\n";
			"<html>\n";
		frameHtml += "<head>\n";
		if (this.styleSheetUrl){
			frameHtml += "<link type=\"text/css\" href=\"" + this.styleSheetUrl + "\" rel=\"stylesheet\">\n";
		}
		frameHtml += "</head>\n";
		frameHtml += "<body>\n";
		frameHtml += html;
		frameHtml += "</body>\n";
		frameHtml += "</html>";

		if (document.all) {
			var oRTE = frames[this.name].document;
			oRTE.open();
			oRTE.write(frameHtml);
			oRTE.close();
			// Attacher un keyboard handler pour intercepter le CTRL-V
			frames[this.name].document.attachEvent('onkeydown', kbHandlerIE);
			// Attacher un event handler pour intercepter le Coller du menu Édition
			frames[this.name].document.documentElement.attachEvent('onpaste', onPasteIE);
		} else {
			var oRTE = document.getElementById(this.name).contentWindow.document;
			oRTE.open();
			oRTE.write(frameHtml);
			oRTE.close();
			//attach a keyboard handler for Mozilla to make keyboard shortcuts for formatting text work
			oRTE.addEventListener("keypress", kbHandlerMozilla, true);
		}
	}

	this.setContent = function(html){
		HyperTextArea.activeArea = this;
		var oRTE;
		if (document.all) {
			oRTE = frames[this.name].document;
		} else {
			oRTE = document.getElementById(this.name).contentWindow.document;
		}
		body = oRTE.getElementsByTagName("body");
		body.innerHTML = html;
	}

	/**
	 * Cette fonction peut être appelée pour changer le contenu de l'éditeur à partir
	 * d'un autre script.
	 */
	this.setHtmlContent = function(html){
		
		// Toujours passer en mode HTML au lieu du mode source
		this.setViewMode(false);
		
		HyperTextArea.activeArea = this;
		var oRTE;
		if (document.all) {
			oRTE = frames[this.name].document;
		} else {
			oRTE = document.getElementById(this.name).contentWindow.document;
		}
		// Ressemble beaucoup à setContent mais il faut utiliser oRTE.body
		oRTE.body.innerHTML = html;
		
		this.update();
	}

	this.update = function(){
		this.setViewMode(false);

		if (document.all) {
			oRTE = frames[this.name];
		} else {
			oRTE = document.getElementById(this.name).contentWindow;
		}
		doc = oRTE.document;

		//set message value
		var oHdnMessage = document.getElementById('hdn' + this.name);

		if (this.isRichText) {
			if (oHdnMessage.value == null) oHdnMessage.value = "";

			// Nettoyer les tags non voulus si l'option est activée
			if (this.cleanHtmlOnSubmit) {
				oHdnMessage.value = this.cleanHTML();
			}
			else {
				oHdnMessage.value = doc.body.innerHTML;
			}

			// Retirer les caractères invalides potentiellement collés à partir de Word
			oHdnMessage.value = removeNonHtmlChars(oHdnMessage.value);

			//if there is no content set value to nothing
			//IE7 ajoute un <P>&nbsp;</> quand le contenu est vide, certains autres éditeurs ajoutent un <br>
			if (oHdnMessage.value.match(/^\s*<P>&nbsp;<\/P>\s*$/i) || oHdnMessage.value.match(/^\s*<br>\s*$/i))
				oHdnMessage.value = "";
			this.html = oHdnMessage.value;
		}
	}

	this.setToolbarsVisible = function(isVisible){
			visibleStyle = isVisible?"visible":"hidden";
			for(x=0;x<this.controlNames.length;x++){
				if(this.controlNames[x] != "code" && this.controlNames[x] != "toolbar1" )
					document.getElementById(this.controlNames[x] + "_" + this.name).style.visibility = visibleStyle;
			}
	}

	this.setViewMode = function(isSrcView){
		HyperTextArea.activeArea = this;
		//contributed by Bob Hutzel (thanks Bob!)
		var oRTE;
		if (document.all) {
			oRTE = frames[this.name].document;
		} else {
			oRTE = document.getElementById(this.name).contentWindow.document;
		}

		//only change the view if it is different than the current state
		if (isSrcView && !this.isSrcView){
			this.isSrcView = true;
			this.setToolbarsVisible(false);
			if (document.all) {
				oRTE.body.innerText = oRTE.body.innerHTML;
			} else {
				var htmlSrc = oRTE.createTextNode(oRTE.body.innerHTML);
				oRTE.body.innerHTML = "";
				oRTE.body.appendChild(htmlSrc);
			}
		}else if(!isSrcView && this.isSrcView){
			this.isSrcView = false;
			this.setToolbarsVisible(true);
			if (document.all) {
				oRTE.body.innerHTML = oRTE.body.innerText;
			} else {
				var htmlSrc = oRTE.body.ownerDocument.createRange();
				htmlSrc.selectNodeContents(oRTE.body);
				oRTE.body.innerHTML = htmlSrc.toString();
			}
		}

	}
	this.maView = false;
	this.toggleHTMLSrc = function(){
			this.maView = !this.maView;
			this.setViewMode(this.maView);
	}

	//TODO would really like to be able to plug functionality in here.  This would include the ability to launch a wizard, and then insert arbitrary text at the insertion point
	this.formatText = function (command,option){
		HyperTextArea.activeArea = this;
		var oRTE;
		if (document.all) {
			oRTE = frames[this.name];
		} else {
			oRTE = document.getElementById(this.name).contentWindow;
		}

		if ((command == "forecolor") || (command == "hilitecolor")) {
			this.command = command;
			controlElement = document.getElementById(this.name +"_" + command);
			cp = document.getElementById('cp' + this.name);
			this.cpWindow.area = this;
			cp.style.left = getOffsetLeft(controlElement) + "px";
			cp.style.top = (getOffsetTop(controlElement) + controlElement.offsetHeight) + "px";
			if (cp.style.visibility == "hidden") {
				cp.style.visibility="visible";
			} else {
				cp.style.visibility="hidden";
			}

			//get current selected range
			var sel = oRTE.document.selection;
			if (sel != null) {
				this.rng = sel.createRange();
			}
		} else {
			oRTE.focus();
		  	oRTE.document.execCommand(command, false, option);
			oRTE.focus();
		}

	}

	this.setColor = function(color){
		HyperTextArea.activeArea = this;

		var oRTE;
		if (document.all) {
			oRTE = frames[this.name];
		} else {
			oRTE = document.getElementById(this.name).contentWindow;
		}

		//var parentCommand = parent.command;
		if (document.all) {
			//retrieve selected range
			var sel = oRTE.document.selection;
			if (this.command == "hilitecolor") this.command = "backcolor";
			if (sel != null) {
				var newRng = sel.createRange();
				newRng = this.rng;
				newRng.select();
			}
		} else {
			oRTE.focus();
		}
		oRTE.document.execCommand(this.command, false, color);
		oRTE.focus();
		document.getElementById('cp' + this.name).style.visibility = "hidden";
	}

	this.addImage = function(imagePath){
		HyperTextArea.activeArea = this;
		if(!imagePath){
			imagePath = prompt('Enter Image URL:', 'http://');
		}
		var oRTE;
		if (document.all) {
			oRTE = frames[this.name];
		} else {
			oRTE = document.getElementById(this.name).contentWindow;
		}

		if ((imagePath != null) && (imagePath != "")) {
			oRTE.focus()
			oRTE.document.execCommand('InsertImage', false, imagePath);
		}
		oRTE.focus()
	}

	//TODO should look into ways to make this cross browser and platform
	this.checkspell = function(){
		try {
			var tmpis = new ActiveXObject("ieSpell.ieSpellExtension");
			tmpis.CheckAllLinkedDocuments(document);
		}
		catch(exception) {
			if(exception.number==-2146827859) {
				if (confirm("ieSpell not detected.  Click Ok to go to download page."))
					window.open("http://www.iespell.com/download.php","DownLoad");
			} else {
				alert("Error Loading ieSpell: Exception " + exception.number);
			}
		}

	}

	this.rngIE = null;
	// méthodes utilisées pour les upload à l'intérieur du WYSIWYG
	// image
	this.displayExternalImage = function() {
		formFile = document.getElementById("file_img_" + this.name + "_div");
		if(formFile.style.display != "block") {
			var image = null;
			if (document.all) { // IE
				oRTE = frames[this.name];
				var selection = oRTE.document.selection;
				if(selection.type == "Control") {
					var range = selection.createRangeCollection();
					if(range.item(0).tagName == "IMG")
						image = range.item(0);
				}
			}
			else { // Firefox
				oRTE = document.getElementById(this.name).contentWindow;
				var selection = oRTE.getSelection();
				var range = selection.getRangeAt(0);
				var container = range.startContainer||selection.focusNode;
				var afterNode = container.childNodes[range.startOffset];
				if(afterNode && afterNode.tagName == "IMG")
					image = afterNode;
			}
			if(image) {
				var w = window.open("section.php?action=imageProperties", "ImageProperties", "width=600, height=400, resizable=1, scrollbars=1");
				w.imageToModify = image;
				w.openerDocument = document;
			}
			else {
				formFile.style.display = "block";
				HyperTextArea.activeArea = this;
				// On sauvegarde le focus pour IE
				if (document.all) {
					frames[this.name].focus();
					this.rngIE = frames[this.name].document.selection.createRange();
				}
			}
		}
		else
			formFile.style.display = "none";
	}

	this.addExternalImage = function(imagePath, areaId){
		var oRTE;
		if (document.all) {
			oRTE = frames[areaId];
		} else {
			oRTE = document.getElementById(areaId).contentWindow;
		}

		if ((imagePath != null) && (imagePath != "")) {
			oRTE.focus()
			// On restaure le focus pour IE
			if(this.rngIE != null) {
				this.rngIE.select();
				this.rngIE = null;
			}
			oRTE.document.execCommand('InsertImage', false, imagePath);
		}
		oRTE.focus()
	}

	// document
	this.displayExternalDocument = function() {
		formFile = document.getElementById("file_doc_" + this.name + "_div");
		if(formFile.style.display != "block") {
			formFile.style.display = "block";
			HyperTextArea.activeArea = this;
			// On sauvegarde le focus pour IE
			if (document.all) {
				frames[this.name].focus();
				this.rngIE = frames[this.name].document.selection.createRange();
			}
		}
		else
			formFile.style.display = "none";

	}

	this.addExternalDoc = function(docPath, areaId){
		var oRTE;
		if (document.all) {
			oRTE = frames[areaId];
		} else {
			oRTE = document.getElementById(areaId).contentWindow;
		}
		oRTE.focus();
		// On restaure le focus pour IE
		if(this.rngIE != null) {
			this.rngIE.select();
			this.rngIE = null;
		}

		// Prompt
		textLink = prompt(HyperTextArea.DOCUMENTTEXTLINK, docPath.substring(docPath.lastIndexOf("/")+1));

		if ((textLink != null) && (textLink != "")) {
			var alink = oRTE.document.createElement("a");
			alink.setAttribute("href", docPath);
			alink.setAttribute("target", "_blank");
			alink.appendChild(oRTE.document.createTextNode(textLink));
			this.replaceSelectionWith(alink);
		}
		oRTE.focus();
	}

	this.createLink = function(linkUrl, inNewWindow){

		if (document.all) {
			oRTE = frames[this.name];
		} else {
			oRTE = document.getElementById(this.name).contentWindow;
		}
		doc = oRTE.document;

		linkElement = doc.createElement('a');
		linkElement.setAttribute('href', linkUrl);

		if (inNewWindow) {
			linkElement.setAttribute('target', '_blank');
		}

		// Bâtir le nom du lien sans le http:// si aucun texte n'est sélectionné
		linkText = linkUrl.replace(/^\w+:\/\//, '');
		linkElement.innerHTML = linkText;

		this.insertAroundSelection(linkElement);
	}

	this.createLinkDialog = function(){
		w = window.open("","linkDialog","width=300,height=150,resizable=1,scrollbars=1");
		w.area = this;
		d = w.document;
		d.open();
		d.write(getLinkDialogAsString(this.name));
		d.close();

	}

	this.select = function(menu,cmd){

		HyperTextArea.activeArea = this;
		var oRTE;
		if (document.all) {
			oRTE = frames[this.name];
		} else {
			oRTE = document.getElementById(this.name).contentWindow;
		}

		var idx = menu.selectedIndex;

		// First one is always a label
		if (idx != 0) {
			var selected = menu.options[idx].value;
			oRTE.document.execCommand(cmd, false, selected);
			menu.selectedIndex = 0;
		}
		oRTE.focus();

	}

	this.insertTableDialog = function(){
		if (document.all) {
			oRTE = frames[this.name].focus();
		} else {
			oRTE = document.getElementById(this.name).contentWindow.focus();
		}
		w = window.open("","tableDialog","width=280,height=250,resizable=1,scrollbars=1");
		w.area = this;
		d = w.document;
		d.open();
		d.write(getTableDialogAsString());
		d.close();

	}
	this.insertTable = function(rows,cols,spacing,padding,border,bordersize,slideshow){
		rows = rows||3;
		cols = cols||3;
		spacing = spacing||2;
		padding = padding||2;
		if(border == true){
			border = bordersize;
		}
		border = border||0;
		
		if (document.all) {
			oRTE = frames[this.name];
		} else {
			oRTE = document.getElementById(this.name).contentWindow;
		}
		doc = oRTE.document;

		table = doc.createElement("table");
		if(slideshow) {
			table.setAttribute("title", "slide show");
			table.setAttribute("style", "border:1px solid red;");
		}
		table.setAttribute("border", border);
		table.setAttribute("cellpadding", padding);
		table.setAttribute("cellspacing", spacing);
		table.setAttribute("class", "hyperTable");

		for (var i=0; i < rows; i++) {
			var tr = doc.createElement("tr");
			for (var j=0; j < cols; j++) {
				var td = doc.createElement("td");
				var content = doc.createTextNode('\u00a0');
				td.appendChild(content);
				tr.appendChild(td);
			}
			table.appendChild(tr);
		}
		this.replaceSelectionWith(table);
	}

	this.replaceSelectionWith = function(el){
		if (document.all) {
			oRTE = frames[this.name];
		} else {
			oRTE = document.getElementById(this.name).contentWindow;
		}
		doc = oRTE.document;
		if (document.all) {
			selection = doc.selection;
			var html = el.outerHTML;
			var range = selection.createRange();
			try {
				range.pasteHTML(html);
			} catch (e) {
				// catch error when range is evil for IE
			}
        }else{
        	selection = oRTE.getSelection();
			var range = selection.getRangeAt(0);
			selection.removeAllRanges();
			range.deleteContents();
			var container = range.startContainer||selection.focusNode;
			var pos = range.startOffset;
			afterNode = container.childNodes[pos];
			try{
				if (container.nodeName.toLowerCase() == "body" && pos < container.childNodes.length && container.childNodes[pos + 1]){
					afterNode = container.childNodes[pos+1]
					container.insertBefore(el, afterNode);
				}else{
					container.insertBefore(el, container.afterNode);
				}
			}catch (e){
				//if this is a text node, then break it up into a text node, new element, text node
				if(container.nodeName.toLowerCase() == "#text"){
					text0 = container.data.substring(0,range.startOffset);
					text1 = container.data.substring(range.startOffset,container.data.length);
					container.data = text0;
					parent = container.parentNode;
					parent.insertBefore(el,container.nextSibling);
					newTextNode = document.createTextNode(text1);
					parent.insertBefore(newTextNode,el.nextSibling);
				}else {
					alert(el.nodeName.toLowerCase() + " cannot be placed here for the following reason:\n\n" + e);
				}
			}
        }
	}

	// Insère un élément autour de la sélection.  Si la sélection n'est pas vide,
	// le contenu de l'élément est remplacé par la sélection.
	this.insertAroundSelection = function(el){
		if (document.all) {
			oRTE = frames[this.name];
		} else {
			oRTE = document.getElementById(this.name).contentWindow;
		}
		doc = oRTE.document;

		// Mettre le focus sur l'éditeur car on va paster qqchose dedans
		oRTE.focus();

		if (document.all) {
			selection = doc.selection;
			var range = selection.createRange();
			try {
				if (range.text.length > 0) {
					el.innerHTML = range.text;
				}
				range.pasteHTML(el.outerHTML);
			} catch (e) {
				// catch error when range is evil for IE
				alert(HyperTextArea.CREATELINKMSG);
			}
		}
		else {
	    	selection = oRTE.getSelection();
			range = selection.getRangeAt(0);

			// Si la sélection n'est pas vide, on ne remplace pas le texte sélectionné,
			// on ne fait qu'ajouter un parent autour du texte sélectionné
			if (range.startOffset != range.endOffset) {
				range.surroundContents(el);
			}
			else {
				range.deleteContents();
				range.insertNode(el);
			}
		}
	}

	this.cleanHTML = function() {

		if (document.all) {
			oRTE = frames[this.name];
		} else {
			oRTE = document.getElementById(this.name).contentWindow;
		}
		doc = oRTE.document;

		cleanRecursively(doc, doc.body, this.allowedTags, this.allowedAttributes, this.allowedStyles);

		return doc.body.innerHTML;
	}

	// bout pour les éléments dynamiques
	this.displayDynamicElement = function() {
		if (document.all) {
			oRTE = frames[this.name].focus();
		} else {
			oRTE = document.getElementById(this.name).contentWindow.focus();
		}
		lang = /[0-9]/.exec(this.name);
		d = window.open('section.php?action=dynamicElement&lang=' + lang, 'DynElem', 'width=950, height=700, location=no, resizable=yes, scrollbars=yes');
		d.area = this;
	}

	this.addDynamicElement = function(origin, type, objId, label) {
		if(type != "" && objId != "" && label) {
			var oRTE = null;
			if (document.all) {
				oRTE = frames[this.name];
			} else {
				oRTE = document.getElementById(this.name).contentWindow;
			}
			if (oRTE != null) {
				oRTE.focus();
				var ico=""
				if (type=="little_teaser"){
					 ico = "teaserp";
				}else if(type=="big_teaser"){
					 ico = "teaserg";
				}else if(type=="lead"){
					 ico = "lead";
				}else if(type=="little_teaser lead"){
					 ico = "teaserplead";
				}else if(type=="big_teaser lead"){
					 ico = "teaserglead";
				}
				var img = oRTE.document.createElement("img");
				img.setAttribute("src", "../../skin/images/"+ico+".jpg");
				img.setAttribute("class", "elt_dyn");
				img.setAttribute("alt", origin + " | " + type + " | " + objId);
				img.setAttribute("title", label.firstChild.nodeValue + " - " + type);
				this.replaceSelectionWith(img);
				oRTE.focus();
			}
		}
	}

	// Slideshow
	this.addSlideShow = function () {
		this.insertTable(5, 1, 0, 0, false, true);
	}

	this.init();
	if(! this.delayRender){
		this.render(this.html);
	}
}

function TextFormatButton(name,label,icon,command,option){
	this.name = name;
	this.label = label;
	this.icon = icon;
	this.command = command;
	this.option = option||"";
	//the next two values are set by the HyperTextArea object
	this.area = null;
	this.resourcePath = null;

	this.maSize = 3;
	this.getRenderedText = function(){
		background = 'style="background-image:url('+SKINURL+'js/quontent/icons/spacer_final.gif)"';
		if(this.name=="policePlus" || this.name=="policeMoins"){
			if(this.name=="policePlus" && this.maSize<10){
				this.maSize = this.maSize+1;
			}
			else if(this.name=="policeMoins" && this.maSize>0){
				this.maSize = this.maSize-1;
			}
			text = '<td '+background+'><div id="'+this.name+'_'+this.area.name+'">'
			text = text + '<img class="btnImage" src="'+this.resourcePath+this.icon+'"  height="21" alt="'+this.label+'" title="'+this.label+'" onClick="HyperTextArea.getArea(\''+this.area.name+'\').select(this.maSize,\'fontsize\')">';
			text = text + '</div></td>';
		}
		else{
			text = '<td '+background+'><div id="'+this.name+'_'+this.area.name+'">'
			text = text + '<img class="btnImage" src="'+this.resourcePath+this.icon+'"  height="21" alt="'+this.label+'" title="'+this.label+'" onClick="HyperTextArea.getArea(\''+ this.area.name +'\').getControl(\''+this.name+'\').execute()">';
			text = text + '</div></td>';
		}
		return text;
	}

	this.execute = function(){
		this.area.formatText(this.command,this.option);
	}
}

function Button(name,icon,title,methodName){
	this.name=name;
	this.getRenderedText = function(){
		background = 'style="background-image:url('+SKINURL+'js/quontent/icons/spacer_final.gif)"';

		text = '<td '+background+'><div id="'+this.name+'_'+this.area.name+'">'
		text = text + '<img class="btnImage" src="'+this.resourcePath+icon+'" width="27" height="21" alt="'+title+'" title="'+title+'" onClick="HyperTextArea.getArea(\''+ this.area.name +'\').'+methodName+'()">';
		text = text + '</div></td>';
		return text;
	}
}

function Spacer(name){
	this.name = name
	this.getRenderedText = function(){
		return '<td><img src="'+SKINURL+'js/quontent/icons/spacer.gif"/></td>'
	}
}


function Toolbar(name, isFirstToolbar, width){
	this.name = name
	this.isFirstToolbar = isFirstToolbar||false;
	this.getRenderedText = function(){
		this.area.toolbarNames[this.area.toolbarNames.length] = this.name;

		text = '<table  style="width:' + width + 'px;" id="' + this.name + '_' + this.area.name + '" cellpadding="1" cellspacing="0"><tr>'
		if(this.isFirstToolbar){
			text = '</tr></table>\n' + text;
		}
		return text;
	}
}

/**
 * Création d'un menu déroulant pour mettre dans la barre de boutons.
 *
 * name: nom du contrôle
 * cmd: commande à exécuter
 * title: nom qui apparaît comme premier élément (dépend de la langue)
 * itemPairs: liste des éléments à mettre dans le menu (valeur1, label1, valeur2, label2, etc.)
 */
function Menu(name,cmd,title,itemPairs){
	this.name = name;
	this.cmd = cmd;
	this.area = null;
	this.items = new Array();

	this.addArrayItems = function(items){
		for (i=0;i<items.length;i=i+2){
			this.addItem(items[i],items[i+1]);
		}
	}
	this.addItem = function(value,lable){
		this.items[this.items.length] = new MenuItem(value,lable);
	}
	this.getRenderedText = function(){
		background = 'style="background-image:url('+SKINURL+'js/quontent/icons/spacer_final.gif)"';

		text = "<td "+background+"><select name='"+this.name+"' id='"+this.name+"_"+this.area.name+"' onchange='HyperTextArea.getArea(\""+ this.area.name +"\").select(this,\""+this.cmd+"\");'>\n";
		for (i=0;i<this.items.length;i++){
			thisItem = this.items[i]
			text = text + "<option value='"+thisItem.value+"'>"+thisItem.lable+"</option>\n";
		}
		text = text + "</select></td>";
		return text;
	}

	// Mettre le titre du menu déroulant et les éléments du menu
	this.addItem("", title);
	this.addArrayItems(itemPairs);
}

function MenuItem(value,lable){
	this.value = value;
	this.lable = lable;
}

HyperTextArea.areas = new Array();
HyperTextArea.getArea = function(name){
	return HyperTextArea.areas[name];
}
HyperTextArea.activeArea = null;
HyperTextArea.about = function(){
	var area;
	for(i in HyperTextArea.areas){
		area = HyperTextArea.getArea(i);
		break;
	}
	window.open(area.resourcePath + "about.html");
}
HyperTextArea.updateAllAreas = function(){
	//iterate over all areas and call update
	for(i in HyperTextArea.areas){
		area = HyperTextArea.areas[i];
		if (area.update != null)
			area.update();
	}
}
HyperTextArea.forms = new Array();

function getOffsetTop(elm) {
	var mOffsetTop = elm.offsetTop;
	var mOffsetParent = elm.offsetParent;

	while(mOffsetParent){
		mOffsetTop += mOffsetParent.offsetTop;
		mOffsetParent = mOffsetParent.offsetParent;
	}

	return mOffsetTop;
}

function getOffsetLeft(elm) {
	var mOffsetLeft = elm.offsetLeft;
	var mOffsetParent = elm.offsetParent;

	while(mOffsetParent) {
		mOffsetLeft += mOffsetParent.offsetLeft;
		mOffsetParent = mOffsetParent.offsetParent;
	}

	return mOffsetLeft;
}

function kbHandlerMozilla(evt, rte) {
	//contributed by Anti Veeranna (thanks Anti!)
	if (evt.ctrlKey) {
		var key = String.fromCharCode(evt.charCode).toLowerCase();
		var cmd = '';
		switch (key) {
			case 'b':
				evt.target.ownerDocument.execCommand("bold",false,true);
				// stop the event bubble
				evt.preventDefault();
				evt.stopPropagation();
				break;

			case 'i':
				evt.target.ownerDocument.execCommand("italic",false,true);
				// stop the event bubble
				evt.preventDefault();
				evt.stopPropagation();
				break;

			case 'u':
				evt.target.ownerDocument.execCommand("underline",false,true);
				// stop the event bubble
				evt.preventDefault();
				evt.stopPropagation();
				break;

			/* Le code pour nettoyer les tags lors d'un copier/coller pourrait
				ressembler à ça, mais c'est pas sûr que ça fonctionne.  De plus,
				il faut écrire un textarea caché quelque part dans la page, comme ça:
					<textarea id="HyperTextAreaPaste" style="width:0px;height:0px;" />

			case 'v':

				// Ne pas intercepter le coller si c'est ce que le paramètre dit
				if (!HyperTextArea.activeArea.cleanHtmlOnPaste)
					return true;

				// Conserver le range sélectionné pour le remplacer plus tard
				var selection = evt.target.ownerDocument.defaultView.getSelection();
				var range = selection.getRangeAt(0);

				// Coller le texte html dans un textarea pour enlever les balises
				pasteBox = document.getElementById('HyperTextAreaPaste');
				pasteBox.value = "";
				pasteBox.focus();
				document.execCommand("paste", false, null);

				// Copier le texte nettoyé dans l'éditeur Html
				evt.target.focus();
				newNode = evt.target.ownerDocument.createTextNode(pasteBox.value.replace(/\n/g, "<br>"));
				HyperTextArea.activeArea.replaceSelectionWith(newNode);
				pasteBox.value = "";

				// S'assurer que le coller ordinaire ne se fasse pas
				evt.preventDefault();
				evt.stopPropagation();
				break;
			*/
		};

 	}
}

function kbHandlerIE(evt) {

	if (evt.ctrlKey) {
		var key = String.fromCharCode(evt.keyCode).toLowerCase();

		switch (key) {
			case 'v':
				return onPasteIE(evt);
		}
 	}
}

function onPasteIE(evt) {

	// Ne pas intercepter le coller si c'est ce que le paramètre dit
	if (!HyperTextArea.activeArea.cleanHtmlOnPaste)
		return true;

	// Ne pas intercepter le coller si on est en mode source
	if (HyperTextArea.activeArea.isSrcView)
		return true;

	// Conserver le range sélectionné pour le remplacer plus tard
	var selection = evt.srcElement.ownerDocument.selection;
	var range = selection.createRange();

	// Obtenir le texte sans balises et remplacer les retours de chariot par des br
	var cleanedHtml = window.clipboardData.getData('text');
	range.pasteHTML(cleanedHtml.replace(/\n/g, "<br />"));

	// S'assurer que le coller ordinaire ne se fasse pas
	evt.cancelBubble = true;
	return false;
}

function stripHTML(oldString) {
	var newString = oldString.replace(/(<[^img]([^>]+)>)/ig,"");

	//replace carriage returns and line feeds
	newString = escape(newString)
	newString = newString.replace("%0D%0A"," ");
	newString = newString.replace("%0A"," ");
	newString = newString.replace("%0D"," ");
	newString = unescape(newString)

	//trim string
	newString = trim(newString);

	return newString;
}

function trim(inputString) {
   // Removes leading and trailing spaces from the passed string. Also removes
   // consecutive spaces and replaces it with one space. If something besides
   // a string is passed in (null, custom object, etc.) then return the input.
   if (typeof inputString != "string") { return inputString; }
   var retValue = inputString;
   var ch = retValue.substring(0, 1);
   while (ch == " ") { // Check for spaces at the beginning of the string
      retValue = retValue.substring(1, retValue.length);
      ch = retValue.substring(0, 1);
   }
   ch = retValue.substring(retValue.length-1, retValue.length);
   while (ch == " ") { // Check for spaces at the end of the string
      retValue = retValue.substring(0, retValue.length-1);
      ch = retValue.substring(retValue.length-1, retValue.length);
   }
   while (retValue.indexOf("  ") != -1) { // Note that there are two spaces in the string - look for multiple spaces within the string
      retValue = retValue.substring(0, retValue.indexOf("  ")) + retValue.substring(retValue.indexOf("  ")+1, retValue.length); // Again, there are two spaces in each of the strings
   }
   return retValue; // Return the trimmed string back to the user
}

function getPaletteAsString(){
	hexArray = new Array("00","55","AA","FF");
	out = "";
	out2 = "";
	line = ""
	row = 1;
	count = 1;
	for(i=hexArray.length-1;i>=0;i--){
		val0 = hexArray[i];
		for(j=hexArray.length-1;j>=0;j--){
			val1 = hexArray[j];
			for(k=hexArray.length-1;k>=0;k--){
				val2 = hexArray[k];
				hexVal = val0+val1+val2;
				line = line + "\n <td id='#"+hexVal+"' bgcolor='#"+hexVal+"' width='15' height='15' onmouseover='this.style.border=\"1px dotted white\"' onmouseout='this.style.border=\"1px solid gray\"' onclick='area.setColor(this.id)'><img width='1' height='1'></td>";
				if(count==1 || (row % 2) == 0){
					if(((count - 1) % 8) == 0){
						out = out + "\n<tr>";
						row++
					}
					out = out + line;
					if((count % 8) == 0){
						out = out + "\n</tr>";
					}
				}else{
					if(((count - 1) % 8) == 0){
						out2 = out2 + "\n<tr>";
						row++
					}
					out2 = out2 + line;
					if((count % 8) == 0){
						out2 = out2 + "\n</tr>";
					}
				}
				line = "";
				count++;
			}
		}
	}
	out = '<table cellpadding="0" cellspacing="1" border="1" align="center">' + out + out2 + "</table>";
	return out;
}

function getLinkDialogAsString(areaName){
	out = '<html><head><title>' + HyperTextArea.LINKWINDOWTITLE + '</title></head>';
	out = out + '<body>';
	out = out + '<form name="linkDialog">';
	out = out + '<table cellpadding="2" cellspacing="2" border="0">';
	out = out + '<tr>';
	out = out + '<td>' + HyperTextArea.LINKURL +': </td><td><input type="text" name="linkUrl" size="40" value="http://"/></td>';
	out = out + '</tr>';
	out = out + '<tr>';
	out = out + '<td><input type="checkbox" name="newWindow" value=""/></td><td>' + HyperTextArea.LINKDEST + '</td>';
	out = out + '</tr>';
	out = out + '<tr>';
	out = out + '<td colspan="2"><div align="center"><input type="button" name="cancel" value="' + HyperTextArea.CANCELBTN + '" onclick="self.close()"/><input type="button" name="button" value="' + HyperTextArea.CREATELINKBTN + '" onclick="window.opener.HyperTextArea.areas[\'' + areaName + '\'].createLink(this.form.linkUrl.value,this.form.newWindow.checked);self.close()"/></div></td>';
	out = out + '</tr>';
	out = out + '</table>';
	out = out + '</form>';
	out = out + '</body>';
	out = out + '</html>';
	return out;
}
function getTableDialogAsString(){
	out = '<html><head><title>' + HyperTextArea.TABLEWINDOWTITLE + '</title></head>';
	out = out + '<body>';
	out = out + '<form name="tableDialog">';
	out = out + '<table cellpadding="2" cellspacing="2" border="0">';
	out = out + '<tr>';
	out = out + '<td>' + HyperTextArea.ROWS + ': </td><td><input type="text" name="rows" size="2" value="3"/></td>';
	out = out + '</tr>';
	out = out + '<tr>';
	out = out + '<td>' + HyperTextArea.COLUMNS +': </td><td><input type="text" name="cols" size="2" value="3"/></td>';
	out = out + '</tr>';
	out = out + '<tr>';
	out = out + '<td>' + HyperTextArea.SPACING + ': </td><td><input type="text" name="spacing" size="2" value="2"/></td>';
	out = out + '</tr>';
	out = out + '<tr>';
	out = out + '<td>' + HyperTextArea.PADDING + ': </td><td><input type="text" name="padding" size="2" value="2"/></td>';
	out = out + '</tr>';
	out = out + '<tr>';
	out = out + '<td>' + HyperTextArea.BORDER + ': </td><td><input type="checkbox" name="border" value="1"/></td>';
	out = out + '</tr>';
	out = out + '<tr>';
	out = out + '<td>' + HyperTextArea.BORDERSIZE + ': </td><td><input type="text" name="bordersize" size="2" value="1"/></td>';
	out = out + '</tr>';
	out = out + '<tr>';
	if(document.all)
		out = out + '<td colspan="2"><div align="center"><input type="button" name="cancel" value="' + HyperTextArea.CANCELBTN + '" onclick="self.close()"/><input type="button" name="button" value="' + HyperTextArea.INSERTTABLEBTN + '" onclick="window.opener.HyperTextArea.activeArea.insertTable(this.form.rows.value,this.form.cols.value,this.form.spacing.value,this.form.padding.value,this.form.border.checked,false);self.close()"/></div></td>';
	else
		out = out + '<td colspan="2"><div align="center"><input type="button" name="cancel" value="' + HyperTextArea.CANCELBTN + '" onclick="self.close()"/><input type="button" name="button" value="' + HyperTextArea.INSERTTABLEBTN + '" onclick="area.insertTable(this.form.rows.value,this.form.cols.value,this.form.spacing.value,this.form.padding.value,this.form.border.checked,this.form.bordersize.value,false);self.close()"/></div></td>';
	out = out + '</tr>';
	out = out + '</table>';
	out = out + '</form>';
	out = out + '</body>';
	out = out + '</html>';
	return out;
}
function enableDesignMode(areaName){
	try{
		if (document.all) {
			frames[areaName].document.body.contentEditable = true;
		}else{
			contentDocument = document.getElementById(areaName).contentDocument;
			contentDocument.designMode = "on";
		}
		self.status = "";
		area.setContent(area.html)
	}catch(e){
		//attempt to recover from any exceptions
		exp = "enableDesignMode('"+areaName+"')";
		area = HyperTextArea.getArea(areaName);
		area.designModeRetryCount++
		self.status = "Error in setting designMode property on attempt number "+ area.designModeRetryCount +".  Retrying.";
		if(area.designModeRetryCount <= 10){
			t = setTimeout(exp,100);
		}else{
			self.status = areaName + " failed to initialize properly";
			throw e;
		}
	}
}

function onHyperTextAreaLoad(areaName) {
	self.status = "attempting to set designMode property";
	area = HyperTextArea.getArea(areaName);
	area.cpWindow = frames['cp' + areaName].window;

	//enables the area to determine what form it belongs to
	area.form = document.getElementById("hdn"+areaName).form;

	//attaches to the forms submit handler only once
	formAlreadyStored = false;
	for(i=0;i<HyperTextArea.forms.length;i++){
		if(area.form == HyperTextArea.forms[i]){
			formAlreadyStored = true;
			break;
		}
	}
	if(!formAlreadyStored){
		onSubmitFunc = area.form.onsubmit;
		area.form.onsubmit = function(){
			HyperTextArea.updateAllAreas();
			if(onSubmitFunc){
				onSubmitFunc();
			}
		}
		HyperTextArea.forms[HyperTextArea.forms.length] = area.form;
	}
	area.setContent(area.html)
	if (document.all) {
		cp = frames["cp" + areaName];
		cp.document.write(getPaletteAsString());
	} else {
		cp = document.getElementById("cp"+areaName);
		d = cp.contentDocument;
		d.open();
		d.write(getPaletteAsString());
		d.close()
	}
	enableDesignMode(areaName);
	area.setContent(area.html)
}

/**
 * Examine les noeuds sous le noeud "elemet" et enlève les tags qui ne sont pas dans
 * allowedTags, enlève leurs attributs qui ne sont pas dans allowedAttributes et
 * enlève leurs styles qui ne sont pas dans allowedStyles.  Cette fonction ne devrait pas
 * être appelée directement, passer plutôt par cleanHTML.
 *
 * doc: document de l'éditeur Html
 * element: element dont on veut nettoyer les enfants.
 * allowedTags: array des tags à garder. Ex: new Array("body", "h3");
 * allowedAttributes: array des attributs à garder. Ex: new Array("target", "href");
 * allowedStyles: regexp des styles à garder. Ex: new RegExp(/^\s*(font-weight: bold|font-style: italic)\s*$/i);
 */
function cleanRecursively(doc, element, allowedTags, allowedAttributes, allowedStyles) {

    // Visiter tous les enfants du noeud element pour voir s'ils sont valides
	var child = element.firstChild;

    while (child != null) {
		// Se rappeler tout de suite du prochain noeud car plus loin on va effacer le noeud courant
    	var nextSibling = child.nextSibling;

    	// Nettoyer les petits-enfants de l'enfant avant de traiter l'enfant
    	cleanRecursively(doc, child, allowedTags, allowedAttributes, allowedStyles);

		// Ne pas traiter les noeuds de texte
		if (child.tagName != null) {

			if (!inArray(allowedTags, child.tagName.toLowerCase())) {
				// Tag de l'enfant non accepté: il faut retirer le noeud.  Pour ce faire,
				// remonter les petits-enfants d'un niveau, et effacer l'enfant devenu vide
				while (child.firstChild != null) {
					element.insertBefore(child.firstChild, child);
				}
				element.removeChild(child);
			}
	       else {
	       		// Tag de l'enfant accepté, mais éliminer les attributs non permis.
	        	// Pour supprimer tous les attributs non permis, remplacer l'élément par un nouveau
	        	// et recopier ses enfants.  Ç'aurait été plus simple d'utiliser attributes[],
	        	// mais c'est non portable
	        	var newNode = doc.createElement(child.tagName);

	        	while (child.firstChild != null) {
	        		newNode.appendChild(child.firstChild);
	        	}

				// Remplacer l'enfant par le nouveau noeud sans attributs
				element.replaceChild(newNode, child);

	        	// Vérifier s'il faut aussi copier certains attributs
				for (var a=0; a<allowedAttributes.length; a++) {
					attribute = child.getAttribute(allowedAttributes[a]);
					if (attribute) {
						newNode.setAttribute(allowedAttributes[a], attribute);
					}
				}

	        	// Vérifier s'il faut aussi copier certains styles
	        	// (les styles sont traités différemment des autres attributs car
	        	// Firefox peut combiner plusieurs instructions dans un même style)
	        	var style = child.getAttribute('style');

	            // Si c'est un tag accepté et qu'il y a un style, séparer les éléments entre ;
				if (style) {
					var styles = new Array();
					var newStyles = new Array();

					// Le style en Mozilla est un string, et un objet en IE
					if (typeof(style) == 'string') {
						styles = style.split(';');
					}
					else if (typeof(style) == 'object') {
						styles = style.cssText.split(';');
					}

					// Ne conserver que les styles permis
					for(var s=0; s<styles.length; s++) {
						if (styles[s].match(allowedStyles)) {
							newStyles.push(styles[s]);
						}
					}

					// Syntaxe valable pour IE et Mozilla pour remettre le style épuré
					newNode.style.cssText = newStyles.join(';');
				}
			}
		}

		child = nextSibling;
	}

}

function inArray(array, element) {
	for (var i=0; i<array.length; i++) {
		if (array[i] == element)
			return true;
	}
	return false;
}

/**
 * deleteFile()
 *
 * @param string	formName		: identifiant du formulaire
 * @param string	action			: action de suppression
 * @param string	fileName		: nom du fichier à supprimer
 */
function deleteFile(formName, action, filename){
	HyperTextArea.updateAllAreas();
	document.forms[formName].elements["action"].value = action;
	document.forms[formName].elements["fileName"].value = filename;
	document.forms[formName].submit();
}

/**
 * startCallback()
 * Vérifie si il vient de contenu privé ou public dans le nom et va le faire uploader dans le répertoire correspondant
 * @param string	name		: identifiant de l'iframe à modifier
 * @param string	formName	: nom du formulaire à envoyer
 * @param string	uploadType	: type upload dynamique (image|document)
 */
function startCallback(name, formName, uploadType) {
	formObject = document.getElementById(formName);

	// On passe le nom du iframe où l'ipload doit se faire
	var containerDiv = document.createElement("div");
	virtalInput = '<input type="hidden" name="__activeArea" value="' + name + '" />';
	virtalInput += '<input type="hidden" name="__type" value="' + uploadType + '" />';
	if (uploadType == 'document'){
		if (name.match('public'))
			virtalInput += '<input type="hidden" name="__typeContenu" value="public" />';
		else
			virtalInput += '<input type="hidden" name="__typeContenu" value="private" />';
	}
	containerDiv.innerHTML = virtalInput;
	formObject.appendChild(containerDiv);

    // make something useful before submit (onStart)
	var oldValue = formObject.action.value;
	formObject.action.value = "upload";
	formObject.submit();
	formObject.action.value = oldValue;
    formObject.target = "";
    //return true;
}

/**
 * completeCallback()
 * @param string	response 	: reponse du serveur
 */
function completeCallback(response) {
// 	alert(response);
	var error = null;
	var image = null;
	var doc = null;
	var container = null;
	reg = new RegExp("<ERROR>(.*)<\/ERROR>", "i");
	res = reg.exec(response);
	if(res)
		error = res[1];

	reg = new RegExp("<LIMG>(.*)<\/LIMG>", "i");
	res = reg.exec(response);
	if(res)
		image = res[1];

	reg = new RegExp("<DOC>(.*)<\/DOC>", "i");
	res = reg.exec(response);
	if(res)
		doc = res[1];

	reg = new RegExp("<CONTAINER>(.*)<\/CONTAINER>", "i");
	res = reg.exec(response);
	if(res)
		container = res[1];

	// Note : une erreur ne peut que se produire lors de l'ajout d'une image (ex: image non web)
	if(error){
    	document.getElementById("file_img_"+container).value = "";
    	document.getElementById("file_img_"+container+"_div").style.display = "none";
    	alert(error);
    }
    else if(image){
    	HyperTextArea.activeArea.addExternalImage(image, container);
    	document.getElementById("file_img_"+container).value = "";
    	document.getElementById("file_img_"+container+"_div").style.display = "none";
    }
    else if(doc){
    	HyperTextArea.activeArea.addExternalDoc(doc, container);
    	document.getElementById("file_doc_"+container).value = "";
    	document.getElementById("file_doc_"+container+"_div").style.display = "none";
    }
}

/**
 * Scanne une chaîne qui contient des caractères Unicode et supprime
 * ceux qui ne sont pas mappés par des caractères ASCII par les browsers
 * (donc qui sont des caractères invalides en HTML).
 * Utile quand le texte provient de Word.
 *
 * @param string	source		: chaîne à analyser
 * @return string	: chaîne nettoyée
 */
function removeNonHtmlChars(source) {

	for (i=0; i<source.length; i++) {
		code = source.charCodeAt(i);

		// Si le code fait partie des caractères ASCII valides, on le garde
		if ((code >= 32 && code <= 126) ||
			(code >= 160 && code <= 255) ||
			code == 338 ||
			code == 339 ||
			code == 352 ||
			code == 353 ||
			code == 376 ||
			code == 381 ||
			code == 382 ||
			code == 402 ||
			code == 710 ||
			code == 732 ||
			code == 8211 ||
			code == 8212 ||
			code == 8216 ||
			code == 8217 ||
			code == 8218 ||
			code == 8220 ||
			code == 8221 ||
			code == 8222 ||
			code == 8224 ||
			code == 8225 ||
			code == 8226 ||
			code == 8230 ||
			code == 8240 ||
			code == 8249 ||
			code == 8250 ||
			code == 8364 ||
			code == 8482)
			continue;

		// Rendu ici, le caractère n'est pas un caractère ASCII
		source = source.substring(0, i) + source.substring(i+1);
	}
	return source;
}


