Array.prototype.inArray = function(value){for (var i=0; i < this.length; i++){if(this[i] == value){return true;break;}}return false;};

Webadmin.RichTextEditorForm = Class.create();
Webadmin.RichTextEditorForm.prototype = {
	initialize : function(element, options){
  		this.options = Object.extend({
  			width: '400px',
	  		height: '200px',
	  		styles : []
  		}, options || {});	
		this.element = $(element);
		this.editors = Array();
		var textareas = this.element.getElementsByTagName('textarea');
		$A(textareas).each(function(textarea){
			if((this.options.only&&Element.hasClassName($(textarea), this.options.only))||!this.options.only){
				this.editors[this.editors.length] = new Editor($(textarea), this.options);				
			}
		}.bind(this));
		this.addListeners();
	},
	addListeners : function(){
		Event.observe(this.element, 'submit', this.save.bindAsEventListener(this));
	},
	save : function(){
		$A(this.editors).each(function(editor){
			editor._onsave();
		});
	}
}

var Editors = {
	count: 0
};

var Editor = Class.create();
Editor.prototype = {
	initialize : function(element, options){
		var style;
		this.str = 'Editor';
		
		this.options = Object.extend({
			controls : {},
			styles : [
				{tag : 'P', label : 'Normal'},
				{tag : 'H1', label : 'Heading', className : 'heading'},
				{tag : 'H2', label : 'Sub-heading'}					
			]
		}, options || {});
		this.options.blockLevelElements = this.options.styles.map(function(node){
			return node.block;
		});
		this.options.buttons = Object.extend({
			bold : true,
			italic : true,
			underline : false,
			strikethrough : true,
			subscript : true,
			superscript : true,
			link : true,
			unlink : true,
			anchor : false,
			ol : true,
			ul : true,
			undo : false,
			redo : false,
			symbols : true
		}, options.buttons || {});				
	
		this.element = element;	
		this.form = this.element.form;
		this.wrapper = new Element('div', {className: 'editor'});
		this.wrapper.setStyle({
			/*position: 'relative',*/
			width: this.element.offsetWidth+'px'
		});
		this.header = new Element('div', {className: 'header'});
		this.wrapper.appendChild(this.header);
		this.controls = new Element('ul', {className: 'controls'});
		this.header.appendChild(this.controls);
		this.editor = new Element('iframe', {name: 'editor_'+Editors.count});	
		if(Client.browser=='Explorer'){
			style = {
				width: this.element.offsetWidth+'px',
				height: this.element.offsetHeight+'px'
			};
		}else{
			style = {
				width: this.element.offsetWidth-2+'px',
				height: this.element.offsetHeight+'px',	
				border: '1px solid #aaa'
			};
		}
		this.editor.setStyle(style);
		//this.element.hide();
		this.wrapper.appendChild(this.editor);
		var footer = new Element('div', {className: 'footer'});
		this.wrapper.appendChild(footer);
		this.breadcrumbs = new Element('div', {className: 'breadcrumbs'});
		this.breadcrumbs.innerHTML='&nbsp;';
		footer.appendChild(this.breadcrumbs);
		
		this.element.parentNode.insertBefore(this.wrapper, this.element.nextSibling);					
		this.setHTML();
		this._setup();
		this._controls();
		this._waitForBody();
		this.element.hide();	
	},
	/* Editor.prototype.simpleCommands
	 *
	 * An array of simple on-off commands.
	 */
	simpleCommands : ['bold', 'italic', 'underline', 'strikethrough', 'subscript', 'superscript', 'unlink'],
	buttons : [
		{tags : ['b', 'strong'], command : 'bold'},
		{tags : ['i', 'em'], command : 'italic'},
		{tags : ['u'], command : 'underline'},
		{tags : ['strike'], command : 'strikethrough'},
		{tags : ['sub'], command : 'subscript'},
		{tags : ['sup'], command : 'superscript'},
		{tags : ['ol'], command : 'ol'},
		{tags : ['ul'], command : 'ul'}
	],	
	symbols : $A([
		{'number' : 38, 'name' : 'amp'},
		{'number' : 34, 'name' : 'quot'},
		{'number' : 39, 'name' : '#39'},
		{'number' : 60, 'name' : 'lt'},
		{'number' : 62, 'name' : 'gt'},
		{'number' : 160, 'name' : 'nbsp'},
		{'number' : 161, 'name' : 'iexcl'},
		{'number' : 164, 'name' : 'curren'},
		{'number' : 162, 'name' : 'cent'},
		{'number' : 163, 'name' : 'pound'},
		{'number' : 165, 'name' : 'yen'},
		{'number' : 166, 'name' : 'brvbar'},
		{'number' : 167, 'name' : 'sect'},
		{'number' : 168, 'name' : 'uml'},
		{'number' : 169, 'name' : 'copy'},
		{'number' : 170, 'name' : 'ordf'},
		{'number' : 171, 'name' : 'laquo'},
		{'number' : 172, 'name' : 'not'},
		{'number' : 173, 'name' : 'shy'},
		{'number' : 174, 'name' : 'reg'},
		{'number' : 8482, 'name' : 'trade'},
		{'number' : 175, 'name' : 'macr'},
		{'number' : 176, 'name' : 'deg'},
		{'number' : 177, 'name' : 'plusmn'},
		{'number' : 178, 'name' : 'sup2'},
		{'number' : 179, 'name' : 'sup3'},
		{'number' : 180, 'name' : 'acute'},
		{'number' : 181, 'name' : 'micro'},
		{'number' : 182, 'name' : 'para'},
		{'number' : 183, 'name' : 'middot'},
		{'number' : 184, 'name' : 'cedil'},
		{'number' : 185, 'name' : 'sup1'},
		{'number' : 186, 'name' : 'ordm'},
		{'number' : 187, 'name' : 'raquo'},
		{'number' : 188, 'name' : 'frac14'},
		{'number' : 189, 'name' : 'frac12'},
		{'number' : 190, 'name' : 'frac34'},
		{'number' : 191, 'name' : 'iquest'},
		{'number' : 215, 'name' : 'times'},
		{'number' : 247, 'name' : 'divide'},
		{'number' : 192, 'name' : 'Agrave'},
		{'number' : 193, 'name' : 'Aacute'},
		{'number' : 194, 'name' : 'Acirc'},
		{'number' : 195, 'name' : 'Atilde'},
		{'number' : 196, 'name' : 'Auml'},
		{'number' : 197, 'name' : 'Aring'},
		{'number' : 198, 'name' : 'AElig'},
		{'number' : 199, 'name' : 'Ccedil'},
		{'number' : 200, 'name' : 'Egrave'},
		{'number' : 201, 'name' : 'Eacute'},
		{'number' : 202, 'name' : 'Ecirc'},
		{'number' : 203, 'name' : 'Euml'},
		{'number' : 204, 'name' : 'Igrave'},
		{'number' : 205, 'name' : 'Iacute'},
		{'number' : 206, 'name' : 'Icirc'},
		{'number' : 207, 'name' : 'Iuml'},
		{'number' : 208, 'name' : 'ETH'},
		{'number' : 209, 'name' : 'Ntilde'},
		{'number' : 210, 'name' : 'Ograve'},
		{'number' : 211, 'name' : 'Oacute'},
		{'number' : 212, 'name' : 'Ocirc'},
		{'number' : 213, 'name' : 'Otilde'},
		{'number' : 214, 'name' : 'Ouml'},
		{'number' : 216, 'name' : 'Oslash'},
		{'number' : 217, 'name' : 'Ugrave'},
		{'number' : 218, 'name' : 'Uacute'},
		{'number' : 219, 'name' : 'Ucirc'},
		{'number' : 220, 'name' : 'Uuml'},
		{'number' : 221, 'name' : 'Yacute'},
		{'number' : 222, 'name' : 'THORN'},
		{'number' : 223, 'name' : 'szlig'},
		{'number' : 224, 'name' : 'agrave'},
		{'number' : 225, 'name' : 'aacute'},
		{'number' : 226, 'name' : 'acirc'},
		{'number' : 227, 'name' : 'atilde'},
		{'number' : 228, 'name' : 'auml'},
		{'number' : 229, 'name' : 'aring'},
		{'number' : 230, 'name' : 'aelig'},
		{'number' : 231, 'name' : 'ccedil'},
		{'number' : 232, 'name' : 'egrave'},
		{'number' : 233, 'name' : 'eacute'},
		{'number' : 234, 'name' : 'ecirc'},
		{'number' : 235, 'name' : 'euml'},
		{'number' : 236, 'name' : 'igrave'},
		{'number' : 237, 'name' : 'iacute'},
		{'number' : 238, 'name' : 'icirc'},
		{'number' : 239, 'name' : 'iuml'},
		{'number' : 240, 'name' : 'eth'},
		{'number' : 241, 'name' : 'ntilde'},
		{'number' : 242, 'name' : 'ograve'},
		{'number' : 243, 'name' : 'oacute'},
		{'number' : 244, 'name' : 'ocirc'},
		{'number' : 245, 'name' : 'otilde'},
		{'number' : 246, 'name' : 'ouml'},
		{'number' : 248, 'name' : 'oslash'},
		{'number' : 249, 'name' : 'ugrave'},
		{'number' : 250, 'name' : 'uacute'},
		{'number' : 251, 'name' : 'ucirc'},
		{'number' : 252, 'name' : 'uuml'},
		{'number' : 253, 'name' : 'yacute'},
		{'number' : 254, 'name' : 'thorn'},
		{'number' : 255, 'name' : 'yuml'},
		{'number' : 338, 'name' : 'OElig'},
		{'number' : 339, 'name' : 'oelig'},
		{'number' : 352, 'name' : 'Scaron'},
		{'number' : 353, 'name' : 'scaron'},
		{'number' : 376, 'name' : 'Yuml'},
		{'number' : 710, 'name' : 'circ'},
		{'number' : 732, 'name' : 'tilde'},
		{'number' : 8194, 'name' : 'ensp'},
		{'number' : 8195, 'name' : 'emsp'},
		{'number' : 8201, 'name' : 'thinsp'},
		{'number' : 8204, 'name' : 'zwnj'},
		{'number' : 8205, 'name' : 'zwj'},
		{'number' : 8206, 'name' : 'lrm'},
		{'number' : 8207, 'name' : 'rlm'},
		{'number' : 8211, 'name' : 'ndash'},
		{'number' : 8212, 'name' : 'mdash'},
		{'number' : 8216, 'name' : 'lsquo'},
		{'number' : 8217, 'name' : 'rsquo'},
		{'number' : 8218, 'name' : 'sbquo'},
		{'number' : 8220, 'name' : 'ldquo'},
		{'number' : 8221, 'name' : 'rdquo'},
		{'number' : 8222, 'name' : 'bdquo'},
		{'number' : 8224, 'name' : 'dagger'},
		{'number' : 8225, 'name' : 'Dagger'},
		{'number' : 8230, 'name' : 'hellip'},
		{'number' : 8240, 'name' : 'permil'},
		{'number' : 8249, 'name' : 'lsaquo'},
		{'number' : 8250, 'name' : 'rsaquo'},
		{'number' : 8364, 'name' : 'euro'}
	]),
	_setup : function(html){
		html = this.unescapeHTML(html||this.element.value);
		html = '<html><body>'+html+'</body></html>';
		var doc = this.getDocument();
		doc.open();
		doc.write(html);
		doc.close();
		doc.designMode="On";
		if(Client.browser!='Explorer'){
			doc.execCommand('styleWithCSS', false, false);
		}
		this.doc = this.getDocument();
	},
	_waitForBody : function(){
		if(this.doc.body){
			this._addListeners();			
			if(Client.browser=='Explorer'){
				this.doc.body.style.border = '1px solid #aaa';
			}			
		}else{
			callback = this._waitForBody.bindAsEventListener(this);
			window.setTimeout(callback, 10);
		}	
	},
	_addListeners : function(){
		Event.observe(this.doc, 'mouseup', this.mousedownEvent.bindAsEventListener(this));	
		Event.observe(this.doc, 'keyup', this.keyupEvent.bindAsEventListener(this));	
		Event.observe(this.doc.body, 'beforepaste', this.beforePasteEvent.bindAsEventListener(this));
		Event.observe(this.doc.body, 'paste', this.pasteEvent.bindAsEventListener(this));
		Event.observe(this.breadcrumbs, 'click', this.selectBreadcrumb.bindAsEventListener(this));
		//Event.observe(this.form, 'submit', this._onsave.bindAsEventListener(this));
	},
	_onsave : function(e){
		//Event.stop(e);
		this.element.value = this.escapeHTML(this.getHTML());
	},
	pasteEvent : function(){	
		this.cleanUp();
	},
	afterPasteEvent : function(){
	
	},
	beforePasteEvent : function(){
		if(!this.beforePasteHasFired){
			this.beforePasteHasFired = true;
			//var data = window.clipboardData.getData("text");
		}else{
			delete this.beforePasteHasFired;
		}
	},
	keyupEvent : function(e){
		if(e.keyCode==13 && !e.shiftKey){
			var nodes = this.doc.body.childNodes;
			$A(nodes).each(function(node){
				if(node.tagName.toLowerCase=='br'){
					this.doc.body.removeChild(node);
				}
			});
		}	
		if(e.keyCode!=8 && e.keyCode!=46){
			var node = this.getCurrentNode();
			if(node.tagName.toLowerCase()=='body'){
				this.command("formatblock","P");
			}
		}
		this.showBreadcrumbs();
		this.showHTML();
	},
	mousedownEvent : function(e){
		this.saveCaret();
		this.showBreadcrumbs();
		//this.nodeChangeEvent(this.getCurrentNode());	
	},	
	saveCaret : function(){
		if(Client.browser=='Explorer'){
			this.caretPos=document.selection.createRange();
		}
	},	
	getCurrentNode : function(){
		if(Client.browser=='Explorer'){
			var caretPos=this.caretPos;
    			if(caretPos!=null){
    				if(caretPos.parentElement!=undefined){
    					var node = caretPos.parentElement();
    					return node;
    				}
    			}
    		}else{
			if(this.editor.contentWindow.getSelection()){
				var node = this.editor.contentWindow.getSelection().focusNode;
				if(node.nodeName=='#text'){
					return node.parentNode;
				}else{
					return node;
				}
			}
		}
	},	
	setHTML : function(){		
	},
	getFrame : function(){
		if(Client.browser=='Explorer'){
			var j = 0;
			$A(document.frames).each(function(frame, i){
				if(frame.name==this.editor.name){
					j = i;
					return;
				}
			}.bind(this));
			return document.frames[j];	
		}else{
			return this.editor;
		}
	},
	getDocument : function(){
		// Returns the iframe we're using as our editor
		var frame = this.getFrame();
		if(Client.browser=='Explorer'){
			return frame.document;	
		}else{
			return frame.contentDocument;
		}
	},
	getHTML : function(){
		var value = this.clean(this.doc.body.innerHTML);
		value = this.massageTags(value);
		return value;
	},
	getRange : function(s){
		if(s.getRangeAt){
			return s.getRangeAt(0);
		}else if(this.doc.createRange){
			var range = this.doc.createRange();
			range.setStart(s.anchorNode,s.anchorOffset);
			range.setEnd(s.focusNode,s.focusOffset);
			return range;
		}else{
			return s;
		}
	},
	getSelection : function(){
		var s;
		if(window.getSelection){
			s = this.getFrame().contentWindow.getSelection();
		}else if(document.selection){ // should come last; Opera!
			s = this.doc.selection.createRange();
		}
		return this.getRange(s);		
	},	
	createSelection : function(){
		var range;
		if(this.doc.body.createTextRange){
			range = this.doc.body.createTextRange();
		}else{
			return false;
		}
		range.setEndPoint("StartToStart",this.selection); 
		range.setEndPoint("EndToEnd",this.selection); 
		range.select();
	},
	selectNode : function(node){
		var range;
		if(document.body.createTextRange){
			range = this.doc.body.createTextRange();
		}else if(document.createRange){	
			range = this.doc.createRange();
		}else{
			return false;
		}
		if(range.moveToElementText){
			range.moveToElementText(node);
		}else if(range.selectNode){
			range.selectNode(node);
		}
		if(range.select){
			range.select();
		}else if(window.getSelection){
			this.getFrame().contentWindow.getSelection().addRange(range);
		}
	},
	selectBreadcrumb : function(e){
		// Select a node from the selected breadcrumb
		var element = Event.element(e);
		if(element.tagName.toLowerCase()=='a'){
			var i = element.getAttribute('index');
			var node = this.nodes[i];
			this.selectNode(node);
			this.showBreadcrumbs(node, i);
		}
	},
	showBreadcrumbs : function(node, j){
		// Creates a breadcrumb trail of nodes in the HTML document
		this.breadcrumbs.innerHTML='';
		var nodes = $A();
		if(!node){
			node = this.getCurrentNode();
		}
		while(node.parentNode.nodeType!=9){
			nodes.push(node);
			node = node.parentNode;
		}		
		nodes = nodes.reverse();
		nodes.each(function(node, i){
			if(i!==0){
				var span = new Element('span').appendText('>');
				this.breadcrumbs.appendChild(span);
			}
			var tag = node.tagName.toLowerCase();
			if(tag=="b"){
				tag="strong";
			}
			if(tag=="i"){
				tag="em";
			}
			var link = new Element('a', {href:'#', index: i}).appendText(tag);
			this.breadcrumbs.appendChild(link);
			if(j&&j==i){
				link.addClassName('selected');
			}
		}.bind(this));	
		
		if(this.options.styles.length>0){
			var style = this.options.styles.find(function(style){
				return nodes.find(function(node){
					if(style.className){
						return node.tagName.toUpperCase()==style.tag && Element.hasClassName(node, style.className);
					}else{
						return node.tagName.toUpperCase()==style.tag;
					}		
				});
			});	
			this.styleMenu.selectedIndex=this.options.styles.indexOf(style);
		}
		var buttons = nodes.findAll(function(node){
			return this.buttons.find(function(button){
				return button.tags.include(node.tagName.toLowerCase());
			});
		}.bind(this));
		$A(this.controls.getElementsByTagName('a')).each(function(button){
			button.removeClassName('selected');
		});		
		buttons.each(function(button){
			this.controls.getElementsByClassName(this.buttons.find(function(b){
				return b.tags.include(button.tagName.toLowerCase());
			}).command).first().addClassName('selected');
		}.bind(this));
		this.nodes = nodes;
	},
	showHTML : function(){		
		var value = this.clean(this.doc.body.innerHTML);
		value = this.massageTags(value);
		this.element.value = value;
	},
	escapeHTML : function(html){		
		var _chars = this.symbols;
		html = html.replace(/<\S[^><]*>/g, function(match){
			return match.replace(/</g, "&#60;").replace(/>/g, "&#62;").replace(/"/g, "&#34;");
		});
		
		_chars.each(function(_char){
			var regex = new RegExp('&'+_char.name+';', "g");
			html = html.replace(regex, String.fromCharCode(_char.number));
		});
		
		_chars.each(function(_char){			
			if(_char.name){
				if(_char.name){
					if(_char.name=='amp'){
						var regex = new RegExp("&(?!#)", "g");
					}else{
						var regex = new RegExp(String.fromCharCode(_char.number), "g");
					}
					html = html.replace(regex, '&'+_char.name+';');
				}
			}
		});
		
		html = html.replace(/&#60;/g, "<").replace(/&#62;/g, ">").replace(/&#34;/g, "\"");
		return html;
	},
	unescapeHTML : function(html){
		var _chars = this.symbols;
		_chars.each(function(_char){
			var regex = new RegExp('&'+_char.name+';', "g");
			html = html.replace(regex, String.fromCharCode(_char.number));
		});
		return html.replace(
			/&(.*?);/g,
			function(dummy, s) {	        	
				s.match(/^#(\d+)$/) ? String.fromCharCode(s.replace(/#/,'')) :
				s.match(/^#x([0-9a-f]+)$/i) ? String.fromCharCode(s.replace(/#/,'0')) :s;
			}
		);	
		return html;
	},
	clean : function(html){	
		// Remove whitespace from begining and end of content
		html = html.replace(/^\s+/, "");
		html = html.replace(/\s+$/, "");
		
		// Remove tabs and multiple new lines
		html = html.replace(/\t+/g, "");
		html = html.replace(/(\n+)/g, "\n");
			
		// Downcase all HTML tags
		html = html.replace(/<[^> ]*/g, function(match){
			return match.toLowerCase();
		});
		
		// Downcase all attributes
		html = html.replace(/<[^>]*>/g, function(match){
			match = match.replace(/ [^=]+=/g, function(match2){
				return match2.toLowerCase();
			});
			return match;
		});		
		
		// Add quotes around all unquoted attributes
		html = html.replace(/<[^>]*>/g, function(match){
			match = match.replace(/( [^=]+=)([^"][^ >]*)/g, "$1\"$2\"");
			return match;
		});
		
		html = html.replace(/ id="[^"]*"/g, ""); // Remove the id attribute from any tag
		html = html.replace(/ style="[^"]*"/g, ""); // Remove the style attribute from any tag
		html = html.replace(/<br>/g, "<br />"); // Convert improper BR tags
		html = html.replace(/<br \/>\s*<\/(h1|h2|h3|h4|h5|h6|li|p)/g, "</$1"); // Remove BR tags from the end of block elements
		html = html.replace(/(<[^\/]>|<[^\/][^>]*[^\/]>)\s*<\/[^>]*>/g, ""); // Remove empty tags
		
		// Remove word stuff
		html = html.replace(/ class="mso([^ |>]*)"/gi, "");
		html = html.replace(/<\?xml[^>]*>/g, "");
		html = html.replace(/<[^ >]+:[^>]*>/g, "");
		html = html.replace(/<\/[^ >]+:[^>]*>/g, "");
		html = html.replace(/-- page break --\s*<p>&nbsp;<\/p>/gi, ""); // Remove pagebreaks
		html = html.replace(/-- page break --/gi, ""); // Remove pagebreaks
		html = html.replace(/<(!--)([^>]*)(--)>/g, "");  // Remove Word comments
		
		html = html.replace(/<\/?span[^>]*>/gi, "");
		html = html.replace(/<\/?font[^>]*>/gi, "");			
		html = html.replace(/<(\w[^>]*) lang=([^ |>]*)([^>]*)/gi, "<$1$3");

		return html;
	},
	massageTags : function(html){	
		// Convert <b> to <strong>
		html = html.replace(/<b(\s+|>)/g, "<strong$1");
		html = html.replace(/<\/b(\s+|>)/g, "</strong$1");
		
		// Convert <i> to <em>
		html = html.replace(/<i(\s+|>)/g, "<em$1");
		html = html.replace(/<\/i(\s+|>)/g, "</em$1");
		return html;
	},
	unMassageTags : function(html){
		// Convert <strong> to <b>
		html = html.replace(/<strong(\s+|>)/g, "<b$1");
		html = html.replace(/<\/strong(\s+|>)/g, "</b$1");
		
		// Convert <em> to <i>
		html = html.replace(/<em(\s+|>)/g, "<i$1");
		html = html.replace(/<\/em(\s+|>)/g, "</i$1");	
		return html;		
	},
	command  : function(command, options){		
		this.doc.execCommand(command, false, options); 
	},
	commandEvent : function(e){
		Event.stop(e);		
		var element;
		if(Event.element(e).tagName.toLowerCase()=='a'){
			element = Event.element(e);
		}else{
			element = Event.findElement(e, 'A');		
		}
		if(this.simpleCommands.indexOf(element.id)!=-1){
			this.command(element.id);
		}		
		switch(element.id){
			case 'symbols' :
					this.symbolsDiv.toggle();
				break;
			case 'anchor' :
				var anchor = prompt("Please enter an anchor name:", "");
				if(anchor!=null && anchor!=""){
					
				}
				break;
			case 'link':
				if(this.options.link){
					this.selection = this.getSelection();
					this.options.link.call(this);
				}else{
					var url = prompt("Please enter a URL:", "");
					if(url!=null && url!=""){
						this.command("createLink", url);
					}else{
						return false;
					}
				}
				break;
			case 'ol':
				this.command('insertorderedlist');
				break;
			case 'ul':
				this.command('insertunorderedlist');
				break;
			case 'undo':
				this.command('undo');
				break;
			case 'redo':
				this.command('redo');
				break;
		}		
		if(Client.browser=='Explorer'&&Client.version==6){
			// @TODO - this still isn't quite right... needs to get the just inserted node... which won't always be retrieved using Element.down()
			try{
				this.showBreadcrumbs(Element.down(this.getCurrentNode()));
			}catch(e){
			
			}
		}else{
			this.showBreadcrumbs();
		}
			
	},
	setFormatBlock : function(value){
		
	},
	styleChangeEvent : function(e){
		Event.stop(e);
		var element = Event.element(e);
		var style = this.options.styles[element.selectedIndex];		
		this.command("formatblock", "<"+style.tag+">");
		if(style.className){
			Element.addClassName(this.getCurrentNode(), style.className);
		}
	},
	_controls : function(){
		$H(this.options.buttons).each(function(control){		
			if(control[1]!==false){
				var li = new Element('li');
				var link = new Element('a', {href: '#', className: control[0], id:control[0], title: control[0].capitalize()});
				if(Client.browser=='Explorer'&&Client.version==6){
					// All this code here is to ensure the 24-bit transparency looks OK in IE... sucks really
					var span = new Element('span');
					span.setStyle({
						width:'16px',
						height:'16px',
						cursor: 'pointer',
						display: 'block'
					});			
					span.style.filter='progid:DXImageTransform.Microsoft.AlphaImageLoader(src=\'/cms/images/editor/'+control[0]+'.png\' sizingMethod=\'crop\')';
					link.appendChild(span);					
					var img = new Element('img', {src:'/cms/images/editor/magic.png', height:'16', width:'16'});
					img.setStyle({position: 'absolute', top: '0', left: '0'});
					link.appendChild(img);					
					link.setStyle({position: 'relative'});					
				}else{
					// Firefox can just use an img tag - hurrah!
					var img = new Element('img', {src:'/cms/images/editor/'+control[0]+'.png', height:'16', width:'16'});
					link.appendChild(img);
				}				
				li.appendChild(link);
				this.controls.appendChild(li);
				Event.observe(link, 'click', this.commandEvent.bindAsEventListener(this));
			}
		}.bind(this));
		if(this.options.styles.length>0){
			var li = new Element('li');
			this.styleMenu = new Element('select');
			this.styleMenu.setStyle({
				width: "auto"
			});
			$A(this.options.styles).each(function(style){
				var option = new Element('option', {value: style.tag, className: style.tag}).appendText(style.label);
				this.styleMenu.appendChild(option);
			}.bind(this));
			li.appendChild(this.styleMenu);
			this.controls.appendChild(li);
			Event.observe(this.styleMenu, 'change', this.styleChangeEvent.bindAsEventListener(this));
		}
		if(this.options.buttons.symbols){
			var left = $('symbols').offsetLeft-1;
			var top = this.header.offsetHeight+1;
			var div = new Element('div', {className: 'symbols'});
			div.setStyle({
				position: 'absolute',
				top: top+'px',
				left: left+'px'
			});
			var table = new Element('table');
			div.appendChild(table);
			var tbody = new Element('tbody');
			table.appendChild(tbody);			
			var rows = this.symbols.inGroupsOf(20);
			rows.each(function(row){
				var tr = new Element('tr');
				row.each(function(cell){
					var td;
					if(cell){
						td = new Element('td');
						var link = new Element('a', {href:'#'}).appendText(String.fromCharCode(cell.number));
						td.appendChild(link);
					} else {
						td = new Element('td');
					}				
					tr.appendChild(td);			
				}.bind(this));
				tbody.appendChild(tr);
			}.bind(this));			
			this.wrapper.appendChild(div);	
			Event.observe(div, 'mouseup', this.insertSymbol.bindAsEventListener(this));	
			div.hide();
			this.symbolsDiv = div;	
		}
	},
	insertSymbol : function(e){
		Event.stop(e);
		var element = Event.element(e);
		if(element.tagName.toLowerCase()=='td'){
			element = element.down();
		}		
		var string = this.escapeHTML(element.innerHTML);		
		try{
			// Works OK in Firefox.
			this.command('inserthtml', string);
		}catch(e){		
			// Catch any exceptions and try doing it the IE way.
			var range = this.caretPos||this.doc.body.createTextRange();
			range.collapse();
			range.select();
			range.pasteHTML(string);
		}	
		this.symbolsDiv.hide();	
	},
	cleanUp : function(){
	
	}
};


