/*
	AdvancedWebLibrary.ContentEditor based on mix of richEdit (initial), widgEdit, tinyMCE, FCKeditor ideas, code, tricks, images, 
	stolen EventManager idea by Keith Gaughan

	build 20070326:
	1. Plugin fixes (TImage)
	2. Code cleanups
	3. Fixed multiple em's in FF 2.0
	4. Worrying about filesize - 50kb
	5. Added THTMLEdit plugin
	Tested IE 6.0 / FF 2.0, 1.5, 1.0 / Opera 9 [sic]
*/

function intVal(prop) {
	return (prop||'0').replace(/[^\d\-\.]/g,'')*1;
}

var $E={

	data:[],
	tmp:{},
	addMethod:'',
	removeMethod:'',
	typePrefix:'',
	InitDone:false,

	Init:function(){
		if(this.InitDone){return;};
		if(window.addEventListener){

			this.addMethod='addEventListener';
			this.removeMethod='removeEventListener';

		}else if(window.attachEvent){

			this.addMethod='attachEvent';
			this.removeMethod='detachEvent';
			this.typePrefix='on';
		}

		$E.Add(window,'unload',this.CleanUp);
		this.InitDone=true;
	},

	_mutateEvent:function(e){
		var x=y=0;
		if(e.pageY){
			x=e.pageX;y=e.pageY;
		}else{

			x=e.clientX+document.body.scrollLeft+document.documentElement.scrollLeft;
			y=e.clientY+document.body.scrollTop+document.documentElement.scrollTop;
		}
		return {el:(e.target||e.srcElement),x:x,y:y,event:e,stop:function(){stopEvent(this.event)}};
	},

	_mutateHandler:function(fn){
		return function(e){
			fn($E._mutateEvent(e));
		}
	},

	Add:function(obj,type,fn,useCapture){

		if(typeof obj=='string'){
			obj=document.getElementById(obj);
		}

		if(obj===null||fn===null){
			return;
		}

		fn=this._mutateHandler(fn);

		if(this.addMethod){
			obj[this.addMethod](this.typePrefix+type,fn,false);
			this.data.push({obj:obj,type:type,fn:fn,useCapture:useCapture});
		}
	},

	AddTmp:function(scope,obj,type,fn){

			fn=this._mutateHandler(fn);
			obj[this.addMethod](this.typePrefix+type,fn,false);
			if(!this.tmp[scope]){
				this.tmp[scope]=[];
			}
			this.tmp[scope].push({obj:obj,type:type,fn:fn,useCapture:false});
	},

	CleanTmp:function(scope){
		var data,ev;
		if((data=this.tmp[scope])){
			for(var i=0;i<data.length;i++){
				ev=data[i];
				ev.obj[this.removeMethod](this.typePrefix+ev.type,ev.fn,ev.useCapture);
				ev.obj=null;
				ev.fn=null;
				ev=null;
			}
			this.tmp[scope]=[];
		}
	},

	Rem:function(obj,type,fn){
		obj[this.removeMethod](this.typePrefix+type,fn,null);
	},

	CleanUp:function(){

		if (!$E||!$E.data) return;

		var ev=null;
		var removeMethod=$E.removeMethod;
		var typePrefix=$E.typePrefix;

		for(var i=($E.data.length-1);i>=0;i--){
			ev=$E.data[i];
			ev.obj[removeMethod](typePrefix+ev.type,ev.fn,ev.useCapture);
			delete ev.obj;
		}
	}
};

$E.Init();

var DragDrop={

	x:0,
	y:0,
	moveElement:null,
	Sxy:{},

	objData:[],

	init:function(){

		$E.Add(document,'mousemove',DragDrop._trace);

		$E.Add(document,'mousedown',function(e){

			var el=e.el;
			do{
				if((el.className||'').indexOf('draggable')!=-1){
					document.onselectstart=function(){return false};
					DragDrop.Start(el);
//					e.stop();
					break;
				}
			}while(el=el.parentNode);

		});

		$E.Add(document,'mouseup',function(){
			if(DragDrop.moveElement){
				DragDrop.Stop();
			}
		});
	},

	_trace:function(e){
		DragDrop.x=e.x;
		DragDrop.y=e.y;
		if(DragDrop.moveElement!=null){
			DragDrop.Move(e);
		}
	},

	Move:function(e){
		e.stop();
		var xy=DragDrop.Sxy;
		var ss={top:(DragDrop.y-xy.y)+'px',left:(DragDrop.x-xy.x)+'px'};

		DragDrop.moveElement.ss(ss);
		if(DragDrop.moveElement.onDragMove){
			DragDrop.moveElement.onDragMove();
		}
	},

	Start:function(el){
		var s=el.style;
		DragDrop.Sxy={x:DragDrop.x-intVal(s.left),y:DragDrop.y-intVal(s.top)};

		DragDrop.moveElement=el;
		if(DragDrop.moveElement.onDragStart){
			DragDrop.moveElement.onDragStart();
		}
	},

	Stop:function(){
		if(DragDrop.moveElement==null){
			return false;
		}
		if(DragDrop.moveElement.onDragEnd){
			DragDrop.moveElement.onDragEnd();
		}

		DragDrop.moveElement=null;
		document.onselectstart=null;
		DragDrop.Sxy={};
	},

	Bind:function(el){
		el.cls('draggable',true);
	}
};

$E.Add(window,'load',DragDrop.init);


var ua=navigator.userAgent.toLowerCase();
var isOpera=ua.indexOf('opera/9')!=-1,isIE=(ua.indexOf('msie')!=-1)&&(!isOpera),isGecko=ua.indexOf('gecko')!=-1;
var encoding='utf-8';
var allRTEs=[];
var isRichText=document.getElementById&&(isOpera||isIE||isGecko);

function loadCSS(path,name){
	if(window[name+'_loaded']==true){
		return;
	}
	var s=document.documentElement.firstChild.appendChild(ce('link'));
	s.type='text/css';
	s.setAttribute('rel','stylesheet');
	s.setAttribute('href',path+name+'?'+Math.random());
	window[name+'_loaded']=true;
}

function _AWLrte(rte,html,path,width,height,restricted,pluginConfig){

	/* self config */
	var t=this;
	t.css=path+'editor.css?'+Math.random();
	t.cssHints=path+'hints.css?'+Math.random();

	t.getMaxWidth=true;
	t.restricted=restricted=':'+restricted.join(':')+':';

	/* content config */
	t.prevHTML='';
	t.bookmark=null;
	t.init=true;

	t.icon={x:23,y:23};
	t.cache=[];
	t.cacheDrops=[];

	t.undo=[];
	t.redo=[];

	function isAllowed(name){
		return restricted.indexOf(':'+name+':')==-1;
	}

	t.plugins={};
	t.plugins['table'] = new TTable(isAllowed('table'),t);
	t.plugins['link'] = new Link(isAllowed('link'),t);
	t.plugins['image'] = new TImage(isAllowed('image'),t);
	t.plugins['HTMLObject'] = new THTMLObject(isAllowed('object'),t);
	t.plugins['color'] = new TColor(isAllowed('color'),t);
	t.plugins['specialchar'] = new TSpecialChar(isAllowed('specialchar'),t);
	t.plugins['htmledit'] = new THTMLEdit(isAllowed('htmledit'),t);

	t.isFontTagValid=(isAllowed('color')||isAllowed('fontname')||isAllowed('fontsize'));

	for(var name in pluginConfig){
		if(!t.plugins[name]){
			alert('Plugin '+name+' not found');
			continue;
		}
		if(pluginConfig[name]['data']){
			t.plugins[name].loadData(pluginConfig[name]['data']);
		}
		if(pluginConfig[name]['config']){
			t.plugins[name].loadConfig(pluginConfig[name]['config']);
		}
	}

	t.isUndo=false;
	t.frameFocus=false;

	EvMan.Add(window,'load',function(){loadCSS(path,'rte.css');});

	var ss=document.getElementsByTagName('script');
	var root=ss[ss.length-1].parentNode.appendChild(cn('div')).cls('rteRoot');

	if(!isRichText){
		var b=ce2('div').cls('rteTArea').sp(root);
		b.add('h2','Rich edit capabilities not supported');
		b.ac2('textarea').att('name',rte).ac(ct(html));
		return false;
	}
/*
	if(isGecko){
		html=html.replace(/<strong(\s+|>)/g,"<b$1");
		html=html.replace(/<\/strong(\s+|>)/g,"</b$1");
		html=html.replace(/<em(\s+|>)/g,"<i$1");
		html=html.replace(/<\/em(\s+|>)/g,"</ei$1");
	}
*/
	if(t.getMaxWidth){
		EvMan.Add(window,'load',function(){
			root.s().width='100%';
			(root.offsetWidth>4)&&(t.iframe.s().width=(root.offsetWidth-4)+'px');
		});
		EvMan.Add(window,'resize',function(){
			if(root.offsetWidth>0){
				(root.offsetWidth>4)&&(t.iframe.s().width=(root.offsetWidth-4)+'px');
			}
		});
	}
	root.s().width=width+'px';

	t.root=root;
	t.name=rte;

	t.restricted=restricted;

	// inner vars
	t.noHideSlave=false;
	t.allowTags=[,'#text','a','em','h1','h2','h3','h4','h5','h6','img','li','ol','p','strong','ul','sup','sub','u','strike','address','table','tbody','tr','td','div','br','hr','q','blockquote',''];

	if(t.isFontTagValid){
		t.allowTags.splice(t.allowTags.length-1,1,'font','');
	}

	t.allowTagsCache=t.allowTags.join(':');

	html=html.validTags(this);

	for(var name in t.plugins){
		html=t.plugins[name].preDataConverter(html);
	}

	if(html==''){
		html = '<p>&nbsp;</p>';
	}

	t.names={td:'cell',tr:'row',table:'table',tbody:'table body',a:'link',ul:'unordered list',ol:'ordered list',li:'list item',p:'para',h1:'heading 1',h2:'heading 2',h3:'heading 3',h4:'heading 4',h5:'heading 5',h6:'heading 6',i:'italic',em:'italic',b:'bold',strong:'bold',u:'underline',s:'strikethrough',strike:'strikethrough'};
	//	allRTEs.push(this); //(?)

var buttonData=[
['b',0,'print','Print (Ctrl+P)','print'],
['s'],
['b',1,'selectall','Select All (Ctrl+A)','selectAll'],
['b',2,'removeformat','Clear text decoration'],
['s'],
['bIE',3,'cut','Cut (Ctrl+X)'],
['bIE',4,'copy','Copy (Ctrl+C)'],
['bIE',5,'paste','Paste (Ctrl+V)'],
['s'],
['b',6,'undo','Undo (Ctrl+Z)','doUndo'],
['b',7,'redo','Redo','doRedo'],
['s'],
['d',-1,'format','formatblock'],
['d',-2,'fontname','fontname'],
['d',-3,'fontsize','fontsize'],
['b',8,'bold','Bold (Ctrl+B)'],
['b',9,'italic','Italic (Ctrl+I)'],
['b',10,'underline','Underline (Ctrl+U)'],
['b',11,'strikethrough','Strikethrough (Ctrl+S)'],
['s'],
['b',24,'justifyleft','Align left'],
['b',25,'justifycenter','Align Center'],
['b',26,'justifyright','Align right'],
['b',27,'justifyfull','Justify Full'],
['s'],
['b',12,'insertorderedlist','Ordered list'],
['b',13,'insertunorderedlist','Unordered list'],
['b',14,'outdent','Outdent'],
['b',15,'indent','Indent'],
['b',28,,'Toggle highlight','toggleHighlight'],
['s'],
['b',22,'subscript','Subscript'],
['b',23,'superscript','Superscript'],
['s'],
['b',16,'inserthorizontalrule','Insert Horizontal Rule']
];

	var gf=0; //groupflag
	var node=cn('div').cls('rteButtons');
	var dropDData=[];
	dropDData[1]=[[''],['<h1>','Heading 1'],['<h2>','Heading 2'],['<h3>','Heading 3'],['<h4>','Heading 4'],['<h5>','Heading 5'],['<h6>','Heading 6'],['<p>','Para'],['<address>','Address'],['<pre>','Preformatted']];
	dropDData[2]=[[''],['Arial'],['Tahoma'],['Trebuchet MS'],['Times'],['Courier'],['Verdana'],['Comic Sans MS']];
	dropDData[3]=[[''],['-3'],['-2'],['-1'],['0',''],['+1'],['+2'],['+3']];

	for(var i=0,count=buttonData.length;i<count;i++){
		var item=buttonData[i];

		if(!isAllowed(item[2])){
			continue;
		}

		switch(item[0]){
			case 'b':
				t.cache[item[1]]=t.button(node,item);gf++;
			break;
			case 'bIE':
				if(isIE){
					t.cache[item[1]]=t.button(node,item);gf++;
				}
			break;

			case 'd':
				var data=dropDData[item[1]*-1];
				t.cacheDrops[item[1]*-1]=function(cmd){
					var s=node.ac2('select');
					s.Eadd('change',function(e){t.actionHandler(e,'stylize',cmd);});
					for(var j=0;j<data.length;j++){
						var oData=data[j];
						s.add('option',oData[1]||oData[0]).value=oData[0];
					}
					return s;
				}(item[3]);gf++;
			break;

			case 's':
				if(gf>0){
					node.ac2('em').cls('rteSeparator');gf=0;
				}
			break;
		}
	}

	for(var name in t.plugins){
		var pl=t.plugins[name];
		if(pl.test()){
			node.ac(pl.getPanelIcons());
		}
	}

	node.ac2('div').ss({clear:'both'});
	node.sp(root);
	t.buttons=node;

	// path
	t.route=cn('div').cls('route').sp(root);

	// edit area
	var fr=cn('iframe').sp(root);
	fr.att('frameBorder',0);
	fr.att('border',0);
	fr.src=path+'blank.htm';
	fr.s().width=width+'px';
	fr.s().height=height+'px';
	fr.Eadd('focus',function(){t.hideSlave();});
	t.iframe=fr;

	// show html
	var ft=cn('div').cls('rteFooter').sp(root);
	ft.add('a','view current html').att('href','javascript:void(0)').Eadd('click',function(e){alert(t);});

// RESIZE
	function mover(e){
		var dY=e.clientY-t.zeroY;
		var hy=t.height+dY;
		if(hy>=150){
			t.r.s().height=hy+'px';
			t.dY=dY;
		}
	}

	var resize=ft.ac2('em').cls('resize').att('title','Resize height').att('resizer',1);

	root.Eadd('mousedown',function(e){
		var el=e.srcElement||e.target;
		if(tag(el)=='em'&&el.getAttribute('resizer')){

			var r=t.root.parentNode.insertBefore(cn('div'),t.root);
			t.r=r;
			t.height=t.root.offsetHeight;
			t.iheight=t.iframe.offsetHeight;
			t.root.s().display='none';
			r.s().height=(t.height)+'px';
			t.zeroY=e.clientY;
			t.dY=0;
			r.cls('rteResize');

			EvMan.Add(window.document,'mousemove',mover);
			EvMan.Add(window.document,'mouseup',function(e){
				t.root.s().display='';
				t.iframe.s().height=(t.iheight+t.dY)+'px';
				t.r.s().display='none';
				EvMan.Rem(window.document,'mousemove',mover);
				t.initExec();
			});
		}
	});
// EO RESIZE

	t.hdn=t.root.ac(input('hidden',rte));
	t.hdn.value=t.html;

	t.enableDesignMode(html);
	if(t.hdn.form){
		EvMan.Add(t.hdn.form,'submit',function(){t.update();});
	}
}

var _b=_AWLrte.prototype;

_b.button=function(node,data){

	var self=this;
	var a=node.ac2('a').cls('rteAction').att('href','Action: '+data[3]).att('title',data[3]);
	a.s().backgroundPosition=(-data[1]*(this.icon.x+1))+'px 50%';
	a.Eadd('click',function(e){stopEvent(e);self.actionHandler(e,data[4],data[2]);});
	return a;
};

_b.actionHandler=function(e,method,param){

	var t=this;
	t.hideSlave();
	t.ffocus();
	t.saveRange();

	if(method==null){
		t.exec(param);
	}else{
		if(typeof(t[method])=='function'){
			t[method](e,param);
		}else{
			alert('AWLrte object: method "'+method+'" not found');
		}
	}
	t.checkState(true);
};

_b.enableDesignMode=function(html){

	var t=this;
	var data='<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html><head>';
	data+="<meta http-equiv='Content-Type' content='text/html; charset="+encoding+"' />";
	if(t.css){
		data+='<link rel="stylesheet" type="text/css" href="'+t.css+'"></link><link rel="alternate stylesheet" id="hints" type="text/css" href="'+t.cssHints+'"></link>';
	}

	data+='</head><body class="rteContent">'+html+'</body></html>';
	var fd=t.getFrameDoc();

	fd.open();
	fd.write(data);
	fd.close();

	if(isIE){
		fd.designMode='On';
	}

	EvMan.Add(window,'load',function(){

		t.paragraphise();
		setTimeout(function(){
			fd.designMode='on';
			t.initExec();
			t.ffocus();
			t.checkState(true);
			t.init=false;
//			self.saveRange();
		},300);
	});

	function clickMenu(e){

		t.saveRange();
		t.hideSlave();
		t.saveBookmark();

		if(e.button>1){
			t.contextMenu(e);
			stopEvent(e);
		}
	};

	EvMan.Add(t.getFrame(),'blur',function(){t.frameFocus=false;});
	EvMan.Add(fd,'dblclick',function(e){stopEvent(e);t.preventHide();t.contextMenu(e);});
	EvMan.Add(fd,'click',clickMenu);
	EvMan.Add(fd,'keyup',function(){t.saveRange();t.checkState();});
	EvMan.Add(fd,'mouseup',function(){t.clrRange();t.saveBookmark();t.checkState();});
	EvMan.Add(fd,'keydown',function(e){t.keydown(e);t.saveBookmark();});
	EvMan.Add(fd,'contextmenu',function(e){t.saveRange();stopEvent(e);t.contextMenu(e);});
};

_b.initExec=function(){with(this){
	exec('LiveResize',false);
	exec('useCSS',true);
	exec('styleWithCSS',false);
	exec('insertBrOnReturn',false);
	exec('enableObjectResizing',false);
	exec('enableInlineTableEditing',false);
}};

_b.ffocus=function(){

	if(this.frameFocus==true&&isIE){
		return;
	}

	this.frameFocus=true;
	this.getFrame().focus();

	var r=this.rng;
	if(r&&isIE){
		r.select();
	}
};

_b.exec=function(cmd,opt){
	opt=(typeof(opt)=='undefined'?'':opt);
	try{
		this.ffocus();
		this.getFrameDoc().execCommand(cmd,false,opt);
		this.ffocus();
	}catch(e){
//		alert('AWLrte object: errorous command '+cmd);
	}
};

_b.stylize=function(e,cmd){
	var el=e.srcElement||e.target;
	if(tag(el)=='select'){
		var val=el.options[el.selectedIndex].value;

		switch(cmd){
			case'fontname':
			case'fontsize':
			case'formatblock':
				this.exec(cmd,val);
			break;
		}
		el.selectedIndex=0;
	}
};

_b.getSlave=function(){
	if(!this.slave){
		this.slave=cn('div').cls('rteSlave').sp(this.root.ownerDocument.body);
	}
	return this.slave;
};

_b.hideSlave=function(){

	if(this.slave && !this.noHideSlave){
		this.slave.ss({visibility:'hidden',top:'-1000px',left:'-1000px'});
		EvMan.CleanTmp('dlg');
		this.ffocus();
	}

};

_b.getFrame=function(){
	return this.iframe.contentWindow;
};

_b.getFrameDoc=function(){
	return this.getFrame().document;
};

_b.saveRange=function(){
	if(this.frameFocus==true){
		this.rng=this.getRange().range;
	}
};

_b.clrRange=function(){
	this.rng=null;
};

_b.selectNode=function(el,avoid){
	var r;
	var d=el.ownerDocument;

	if(isIE){
		r=d.body.createTextRange();
		r.moveToElementText(el);
		r.select();
	}else{
		if(avoid==true && tag(el)=='td'){
			el=el.firstChild;
		}
		r=d.createRange();
		var sel=this.getFrame().getSelection();
		r.selectNode(el);
		sel.removeAllRanges();
		sel.addRange(r);
	}
};

_b.contextMenu=function(e){

	this.checkState();
	this.hideSlave();
	var el=e.target||e.srcElement;
	var self=this;
	var tg=tag(el);
	var config={};
	create=[];
	var noSel=true;

	for(var name in this.plugins){
		var pl=this.plugins[name];
		if(pl.isNeeded(el,[])){ // [] = should be named path
			config[name]=pl.list();
			noSel=false;
		}

		if(pl.test()){
			create=create.concat(pl.getAddAction());
		}
	}

	config[1]=create;
	config[0]=[['hideSlave','\u2205 Close']];

	if(!noSel){
		this.selectNode(el,true);
	}

	var c=this.getSlave().cls('rteSlave cMenu');//,s=c.s();
	clearNode(c);
	var sepClass='';

	for(var name in config){
		for(var j=0,block=config[name];j<block.length;j++){
			var cmd=block[j];
			this.menuItem(c,cmd,$(el),name).cls(sepClass);
			sepClass='';
		}
		delete config[name];
		sepClass='cMenuSeparated';
	}

	var pos=getXY(this.iframe);
	c.ss({left:(e.clientX+pos.x)+'px',top:(e.clientY+10+pos.y)+'px'});
	this.draw(c.s());
};

_b.menuItem=function(c,cmd,el,scope){

	var self=this;
	var host=this.plugins[scope];
	var a=c.add('a',cmd[1]).att('href','action: '+cmd[1]);

	if(host){
		EvMan.AddTmp('dlg',a,'click',function(e){host.action(el,cmd[0]);self.hideSlave();stopEvent(e)});
	}else{
		if(scope==0){
			EvMan.AddTmp('dlg',a,'click',function(e){self[cmd[0]](el);self.hideSlave();stopEvent(e)});
		}else if(scope==1){
			EvMan.AddTmp('dlg',a,'click',function(e){cmd[0].xy=null;cmd[0].add(cmd);self.hideSlave();stopEvent(e)});
		}
	}
	return a;
};

_b.draw=function(s){
	var self=this;
	this.oStyle=s;
	s.visibility='visible';
	this.setOpacity(0.2);
	window.clearInterval(this.oThread);
	this.oThread=window.setInterval(function(){self.opacityRoll();},40);
};

_b.opacityRoll=function(){
	var o=this.getOpacity();
	if(o>1){
		clearInterval(this.oThread);
	}
	this.setOpacity(o+0.3);
}

if(isIE){
	_b.getOpacity=function(){
		return parseFloat(this.oStyle.filter.replace(/[^0-9]/g,''))/100;
	}
	_b.setOpacity=function(v){
		this.oStyle.filter='alpha(opacity='+v*100+')';
	}
}else{
	_b.getOpacity=function(){
		return parseFloat(this.oStyle.opacity);
	}
	_b.setOpacity=function(v){
		this.oStyle.opacity=v;
	}
}

_b.hotkey=function(cmd,e){
	this.exec(cmd);
	stopEvent(e);
	this.checkState();
};

_b.keydown=function(e){
	if(e.ctrlKey){
		var self=this;
		var oldBookmark=this.bookmark;
		switch(e.keyCode){
			case 86:
				setTimeout(function(){self.cleanPaste();self.restoreBookmark(oldBookmark);self.checkState(true);},100);
			break;
			case 66:this.hotkey('bold',e);break;
			case 73:this.hotkey('italic',e);break;
			case 85:this.hotkey('underline',e);break;
			case 83:this.hotkey('strikethrough',e);break;
			case 76:/*addLink?*/break;
			case 80:/*Print?*/break;
			case 90:this.doUndo();stopEvent(e);break;
		}
	}else if(e.keyCode=='13'){
		// workarounds to insert paragraph instead of br
		if(isGecko){
			this.insertHTML('<p>&nbsp;</p>');
			stopEvent(e);
		}
		if(isOpera){
			//dunno whattodo
		}
	}
};

_b.saveBookmark=function(){

	var b=null;
	var doc=this.getFrameDoc();
	var sp,le,s,e,nl,i,si,ei;
	var trng,sx,sy,xx=-999999999;
	sx=doc.body.scrollLeft+doc.documentElement.scrollLeft;
	sy=doc.body.scrollTop+doc.documentElement.scrollTop;
	var r=this.getRange().range;
	if(isIE){
		if(r.item){
			e=r.item(0);
			nl=doc.getElementsByTagName(e.nodeName);
			for(i=0;i<nl.length&&e!=nl[i];i++);
			b={tag:tag(e),index:i,x:sx,y:sy};
		}else{
			trng=r.duplicate();
			trng.collapse(true);
			sp=Math.abs(trng.move('character',xx));
			trng=r.duplicate();
			trng.collapse(false);
			le=Math.abs(trng.move('character',xx))-sp;
			b={start:sp,length:le,x:sx,y:sy};
		}
	}else{
		var st=extractRangeNodeInfo(r.startContainer,doc);
		var en=extractRangeNodeInfo(r.endContainer,doc);
		b={startTag:st.tag,start:st.pos,startIndex:st.index,
		endTag:en.tag,end:en.pos,endIndex:en.index,
		startOffset:r.startOffset,endOffset:r.endOffset,x:sx,y:sy};
	}
	this.bookmark=b;
};

function extractRangeNodeInfo(s,doc){

	var pn=s;
	while((s=s.parentNode)!=null&&s.nodeType!=1);
	for(var si=0;si<s.childNodes.length&&s.childNodes[si]!=pn;si++);
	var nl=doc.getElementsByTagName(s.nodeName);
	for(var i=0;i<nl.length&&s!=nl[i];i++);
	return{tag:tag(s),pos:i,index:si};
}

_b.restoreBookmark=function(b){

	var r,d=this.getFrameDoc(),self=this;
if(isIE){
	if(b.tag){
		r=d.body.createControlRange();
		nl=d.getElementsByTagName(b.tag);

		if(nl.length>b.index){
			try{
				r.addElement(nl[b.index]);
			}catch(er){
				// Might be thrown if the node no longer exists
			}
		}
	}else{
		r=d.selection.createRange();
		r.moveToElementText(d.body);
		r.collapse(true);
		r.moveStart('character',b.start);
		r.moveEnd('character',b.length);
	}
	r.select();
	this.getFrame().scrollTo(b.scrollX,b.scrollY);
}else{
	setTimeout(function(){
		var r=d.createRange();
		var sel=self.getFrame().getSelection();

		var nl=d.getElementsByTagName(b.startTag);
		if(nl.length>b.start){
			var n=nl[b.start].childNodes[b.startIndex];
			r.setStart(n,n.nodeValue.length<b.startOffset?n.nodeValue.length:b.startOffset);
			r.setEnd(n,n.nodeValue.length<b.startOffset?n.nodeValue.length:b.startOffset);
//			r.setEnd(n,n.nodeValue.length<b.endOffset?n.nodeValue.length:b.endOffset);
		}
/*
		nl=d.getElementsByTagName(b.endTag);
		if(nl.length>b.end){
			var n=nl[b.end].childNodes[b.endIndex];
			r.setEnd(n,n.nodeValue.length<b.endOffset?n.nodeValue.length:b.endOffset);
		}
*/
		sel.removeAllRanges();
		sel.addRange(r);
	},1);
}
};

function changeNodeType(old,type){

	var p=$(old.parentNode),n=p.ce(type);
	if(p!==null){

		for(var i=0,count=old.childNodes.length;i<count;i++){
			n.ac(old.childNodes[i].cloneNode(true));
		}

		p.replaceChild(n,old);
	}
	return true;
};

function replaceNodeWithChildren(n){

	var p=n.parentNode;
	if(p!==null){
		for(var i=0,count=n.childNodes.length;i<count;i++){
			p.insertBefore(n.childNodes[i].cloneNode(true),n);
		}
		p.removeChild(n);
		return p;
	}
	return true;
}

_b.cleanPaste=function(){

	var html=this.getHTML();
	html=html.replace(/&nbsp;/gi,' ').replace(/\r/g,' ').replace(/\n/g,' ');
	html=html.validTags(this);

	html=html.replace(/%7b/gi,'{').replace(/%7d/gi,'}');

	for(var name in this.plugins){
		html=this.plugins[name].preDataConverter(html);
	}

	this.getFrameDoc().body.innerHTML=html;
	this.paragraphise();
};

_b.saveChanges=function(prev,r){

	var t=this;
	if(t.init){
		return;
	}

	if(t.isUndo){
		t.isUndo=false;
	}else{
		if(!t.undo[t.undo.length-1]||t.undo[t.undo.length-1].data!=prev){
			t.undo.push({data:prev,point:t.bookmark});
			t.redo=[];
		}
	}
};

_b.doRedo=function(){

	var step,t=this;
	if(!(step=t.redo.pop())){
		return;
	}

	t.undo.push({data:t.getHTML(),point:t.bookmark});
	t.isUndo=true;
	t.getFrameDoc().body.innerHTML=step.data;
	t.restoreBookmark(step.point);
};

_b.doUndo=function(){

	var len,b,t=this;
	if(!(step=t.undo.pop())){
		return;
	}
	t.redo.push({data:t.getHTML(),point:t.bookmark});

	t.isUndo=true;
	t.getFrameDoc().body.innerHTML=step.data;
	t.restoreBookmark(step.point);
};

_b.checkState=function(bForce){

	var html=this.getHTML();
	if(this.prevHTML!=html){
		this.saveChanges(this.prevHTML,this.prevRange);
		this.prevHTML=html;
	}

	var n=this.getRange().n;
	if(n==this.oldNode&&!bForce){
		return;
	}
	this.oldNode=n;

	var cache=this.cache;
	var cacheDrops=this.cacheDrops;

	cache.each(function(el,i){el&&el.cls('')});
	cacheDrops.each(function(el){el&&(el.selectedIndex=0)})

	var elPath=[];
	var no=[];

	while(tag(n)!='body'){

		var tg=tag(n);
		elPath.push(n);
		
		switch(tg){
			case'a':no.push(18);no.push(19);break;
			case'u':no.push(10);break;
			case's':case'strike':no.push(11);break;
			case'i':case'em':no.push(9);break;
			case'b':case'strong':no.push(8);break;
			case'ol':no.push(12);break;
			case'ul':no.push(13);break;
			case'sup':no.push(23);break;
			case'sub':no.push(22);break;
			case'h1':case'h2':case'h3':case'h4':case'h5':case'h6':case'p':case'pre':case'address':cacheDrops[1].value='<'+tg+'>';break;
			case'img':no.push(20);break;
			case'blockquote':no.push(14);no.push(15);break;
			case'font':

				if(n.getAttribute('face')&&cacheDrops[2]&&cacheDrops[2].selectedIndex==0){
					cacheDrops[2].value=n.getAttribute('face');
				}

				if(n.getAttribute('size')&&cacheDrops[3]&&cacheDrops[3].selectedIndex==0){
					var sz=n.getAttribute('size');
					if(!/[-+]\d/.test(sz)){ // IE recalculates +3 into 6
						sz=(sz-3);
						sz=sz>0?'+'+sz:'-'+sz;
					}
					cacheDrops[3].value=sz;
				}

				if(n.getAttribute('color')){
					no.push(29);
				}

			break;
		}
		n=n.parentNode;
	}

	no.each(function(no){cache[no]&&cache[no].cls('active')});

	var names=this.names;
	var r=this.route;
	clearNode(r);

	elPath=elPath.reverse();
	r.add('strong','Path: ');
	var text='',tg='';
	EvMan.CleanTmp('path');

	for(var i=0;i<elPath.length;i++){
		text=names[tag(elPath[i])]||tag(elPath[i]);
		this.pathItem(r,text,elPath[i]);
		if(i<(elPath.length-1)){
			r.add('span','\u2192');
		}
	}
};

_b.pathItem=function(n,t,el){

	var self=this;

	EvMan.AddTmp('path',n.add('a',t).att('href','action: Select element').att('title','Click to select element contents'),'click',function(e){

		var pi=(e.srcElement||e.target);
		self.cleanRouteHL();
		pi.s().background='#f90';

		self.selectNode(el);
		self.ffocus();

		EvMan.AddTmp('path',self.route.add('a','remove tag').cls('removeTag').att('href','action: remove current tag'),'click',function(e){
			if(tag(el).isInlineName()){
				replaceNodeWithChildren(el);
			}else if(':table:tbody:tr:td:ul:ol:'.indexOf(':'+tag(el)+':')!=-1){
				clearNode(el);
				el.parentNode.removeChild(el);
			}else{
				changeNodeType(el,'p');
			}
			self.checkState();
			self.ffocus();
			stopEvent(e);
		});
		stopEvent(e);
	});
};

_b.cleanRouteHL=function(){
	for(var i=0,list=this.route.childNodes;i<list.length;i++){
		list[i].s().background='';
	}
};

_b.update=function(){

	this.hideSlave();
	this.hdn.value=this;
};

_b.toString=function(){

	this.paragraphise();

	var s=this.getHTML();
	s=s.replace(/\r/g,' ').replace(/\n/g,' ').replace(/\t/g,' ').replace(/\s/g,' ');
	s=s.validTags(this);

	s=s.replace(/^\s+/,'');
	s=s.replace(/\s+$/,'');
	s=s.replace(/<(br|hr)>/g,"<$1 />");
	s=s.replace(/<br \/>\s*<\/(h1|h2|h3|h4|h5|h6|li|p)/g,"</$1");
	s=s.replace(/(<img [^>]+[^\/])>/g,"$1 />");

//	s=s.replace(/(<[^\/]>|<[^\/][^>]*[^\/]>)\s*<\/[^>]*>/g,'');

	s=s.replace(/(\s*)(<\/[^>]>)/g,'$2$1');
	s=s.replace(/\s*<(h1|h2|h3|h4|h5|h6|li|p|table|tbody|tr|td|hr)/g,"<$1");

	s=s.replace(/\s+/,' ');
	return replaceSpecialChars(s);
}

_b.getHTML=function(){
	return this.getFrameDoc().body.innerHTML;
};

_b.paragraphise=function(){

	var fd=this.getFrameDoc();
	var bd=fd.body;

	for(var i=0;i<bd.childNodes.length;i++){
		if(tag(bd.childNodes[i])=="#text" && bd.childNodes[i].data.search(/^\s*$/)!=-1){
			bd.removeChild(bd.childNodes[i]);
			i--;
		}
	}

	var els=[];

	for(i=0;i<bd.childNodes.length;i++){

		if(bd.childNodes[i].nodeName.isInlineName()){

			els.push(bd.childNodes[i].cloneNode(true));
			bd.removeChild(bd.childNodes[i]);
			i--;

		}else if(tag(bd.childNodes[i])=='br'){

			if((i+1)<bd.childNodes.length){

				if(tag(bd.childNodes[i+1])=='br'){
					while(i<bd.childNodes.length && tag(bd.childNodes[i])=='br'){
						bd.removeChild(bd.childNodes[i]);
					}
					if(els.length>0){
						this.insertNewParagraph(els,bd.childNodes[i]);
						els=[];
					}

				}else if(!bd.childNodes[i+1].nodeName.isInlineName()){
					bd.removeChild(bd.childNodes[i]);
				}else if(els.length>0){
					els.push(bd.childNodes[i].cloneNode(true));
					bd.removeChild(bd.childNodes[i]);
				}else{
					bd.removeChild(bd.childNodes[i]);
				}
				i--;

			}else{
				bd.removeChild(bd.childNodes[i]);
			}

		}else if(els.length>0){
			this.insertNewParagraph(els,bd.childNodes[i]);
			els=[];
		}
	}

	if(els.length>0){
		this.insertNewParagraph(els);
	}
};

_b.insertNewParagraph=function(els,next){

	var d=this.getFrameDoc(),body=d.body;
	var p=d.createElement('p');
	els.each(function(el){p.appendChild(el)});
	(next!==undefined)? body.insertBefore(p,next): body.appendChild(p);
	return true;
};

_b.initSlave=function(name,cls,title){
	return this.initSlaveXY(getXY(this.cache[name]),cls,title);
};

_b.initSlaveXY=function(xy,cls,title){

	var el=this.cache[name];
	var c=this.getSlave().cls('rteSlave '+cls);
	clearNode(c);

	this.controlSlave(c.add('h2',title));
	xy&&xy.x&&xy.y&&xy.h&&c.ss({top:(xy.y+xy.h+5)+'px',left:(xy.x+5)+'px'});

	this.draw(c.s());
	return c;
};

_b.controlSlave=function(hd){

	DragDrop.Bind(hd.parentNode);

	var em=hd.add('em','x').att('title','Close dialog');
	var t=this;

	EvMan.AddTmp('dlg',em,'click',function(){t.hideSlave();});
//	EvMan.AddTmp('dlg',em,'mousedown',function(e){self.isDragOn=false;stopEvent(e)});
	EvMan.AddTmp('dlg',em,'mouseover',function(){em.className='active'});
	EvMan.AddTmp('dlg',em,'mouseout',function(){em.className=''});
	hd.att('title','Click to move dialog');

/*
	EvMan.AddTmp('dlg',hd,'mousedown',function(e){

		var o=e.target||e.srcElement,c=o.parentNode;
		this.cS=c.s();

		this.Sx=e.clientX;
		this.Sy=e.clientY;
		this.x=c.offsetLeft;
		this.y=c.offsetTop;

		self.isDragOn=true;
		o.className='dragOn';
	});

	EvMan.AddTmp('dlg',hd,'mouseup',function(e){
		self.isDragOn=false;
		(e.target||e.srcElement).className='';
	});

	EvMan.AddTmp('dlg',hd,'mousemove',function(e){
		if(self.isDragOn){
			this.cS.top=((e.clientY-this.Sy)+this.y)+'px';
			this.cS.left=((e.clientX-this.Sx)+this.x)+'px';
		}
	});

	EvMan.AddTmp('dlg',hd,'mouseout',function(ev){
		self.isDragOn=false;
		this.className='';
	});
*/

};

function input(type,name){
	var e;
	try{
		e=cn('<input type="'+type+'" name="'+name+'">');
	}catch(er){
		e=cn('input');
		e.type=type;
		e.name=name;
	}
	EvMan.AddTmp('dlg',e,'keypress',function(ev){if(ev.keyCode==13)stopEvent(ev);});
	setHover(e);
	return e;
}

function tag(e){
	return e.nodeName.toLowerCase();
}

function setHover(el){
	EvMan.AddTmp('dlg',el,'mouseover',function(){el.className+=' hover';});
	EvMan.AddTmp('dlg',el,'mouseout',function(){el.className=el.className.replace(/hover/g,'');});
	EvMan.AddTmp('dlg',el,'focus',function(){el.className+=' focus';});
	EvMan.AddTmp('dlg',el,'blur',function(){el.className=el.className.replace(/focus/g,'');});
}

_b.getRange=function(){

	var d=this.getFrameDoc();
	var sel,text='',rng,n;
	if(isIE){
		rng=d.selection.createRange();
		sel=rng.text;
		try{
			n=rng.parentElement();
		}catch(e){
			// control
			n=rng.item(0);
		}
	}else{
		sel=this.getFrame().getSelection();
		rng=sel.getRangeAt(0);
		if(rng.startContainer==rng.endContainer&&rng.startOffset-rng.endOffset<2&&rng.startContainer.hasChildNodes()){
			n=rng.startContainer.childNodes[rng.startOffset];
		}
		if(!n){
			n=rng.commonAncestorContainer;
		}
	}

	while(n.nodeType==3){
		n=n.parentNode;
	}
	return{'range':rng,'sel':sel,'n':n};
};

_b.onBuiltMenu=function(){
	this.preventHide();
	var c=this.getSlave();
	if((c.offsetWidth+c.offsetLeft)>c.parentNode.offsetWidth){
		c.s().left=(c.parentNode.offsetWidth-c.offsetWidth-20)+'px';
	}
};

_b.preventHide=function(){
	var self=this;
	this.noHideSlave=true;
	setTimeout(function(){self.noHideSlave=false;},10);
};

_b.insertHTML=function(html){

	var f=this.getFrame();
	f.focus();
	this.hideSlave();
	if(isIE){
		var r=this.rng;
		if(r){
			r.pasteHTML(html);
			r.collapse(false);
			r.select();
		}
		this.clrRange();
	}else{
		this.exec('insertHTML',html);
	}
};

_b.toggleHighlight=function(){
	var ss=this.getFrameDoc().getElementById('hints');
	if(ss.getAttribute('rel')=='alternate stylesheet'){
		ss.disabled=false;
		ss.setAttribute('rel','stylesheet');
		ss.rel='stylesheet';
	}else{
		ss.disabled=true;
		ss.setAttribute('rel','alternate stylesheet');
		ss.rel='alternate stylesheet';
	}
};

_b.selectAll=function(){
	this.ffocus();
	this.getFrameDoc().execCommand('SelectAll',false,false);
};

_b.print=function(){
	this.getFrame().print();
};

function replaceSpecialChars(html){

	var s=getSpecials();
	var u=getUnicodes();

	for(var i=0;i<s.length;i++){
		var re=new RegExp(u[i],'gi');
		html=html.replace(re,s[i]);
	}

	return html;
};

function getSpecials(){
	return '&cent;:&euro;:&pound;:&curren;:&yen;:&copy;:&reg;:&trade;:&divide;:&times;:&plusmn;:&frac14;:&frac12;:&frac34;:&deg;:&sup1;:&sup2;:&sup3;:&micro;:&laquo;:&raquo;:&lsquo;:&rsquo;:&lsaquo;:&rsaquo;:&sbquo;:&bdquo;:&ldquo;:&rdquo;:&iexcl;:&brvbar;:&sect;:&not;:&macr;:&para;:&middot;:&cedil;:&iquest;:&fnof;:&mdash;:&ndash;:&bull;:&hellip;:&permil;:&ordf;:&ordm;:&szlig;:&dagger;:&Dagger;:&eth;:&ETH;:&oslash;:&Oslash;:&thorn;:&THORN;:&oelig;:&OElig;:&scaron;:&Scaron;:&acute;:&circ;:&tilde;:&uml;:&agrave;:&aacute;:&acirc;:&atilde;:&auml;:&aring;:&aelig;:&Agrave;:&Aacute;:&Acirc;:&Atilde;:&Auml;:&Aring;:&AElig;:&ccedil;:&Ccedil;:&egrave;:&eacute;:&ecirc;:&euml;:&Egrave;:&Eacute;:&Ecirc;:&Euml;:&igrave;:&iacute;:&icirc;:&iuml;:&Igrave;:&Iacute;:&Icirc;:&Iuml;:&ntilde;:&Ntilde;:&ograve;:&oacute;:&ocirc;:&otilde;:&ouml;:&Ograve;:&Oacute;:&Ocirc;:&Otilde;:&Ouml;:&ugrave;:&uacute;:&ucirc;:&uuml;:&Ugrave;:&Uacute;:&Ucirc;:&Uuml;:&yacute;:&yuml;:&Yacute;:&Yuml;'.split(':');
}

function getUnicodes(){
	return '\u00a2:\u20ac:\u00a3:\u00a4:\u00a5:\u00a9:\u00ae:\u2122:\u00f7:\u00d7:\u00b1:\u00bc:\u00bd:\u00be:\u00b0:\u00b9:\u00b2:\u00b3:\u00b5:\u00ab:\u00bb:\u2018:\u2019:\u2039:\u203a:\u201a:\u201e:\u201c:\u201d:\u00a1:\u00a6:\u00a7:\u00ac:\u00af:\u00b6:\u00b7:\u00b8:\u00bf:\u0192:\u2014:\u2013:\u2022:\u2026:\u2030:\u00aa:\u00ba:\u00df:\u2020:\u2021:\u00f0:\u00d0:\u00f8:\u00d8:\u00fe:\u00de:\u0153:\u0152:\u0161:\u0160:\u00b4:\u02c6:\u02dc:\u00a8:\u00e0:\u00e1:\u00e2:\u00e3:\u00e4:\u00e5:\u00e6:\u00c0:\u00c1:\u00c2:\u00c3:\u00c4:\u00c5:\u00c6:\u00e7:\u00c7:\u00e8:\u00e9:\u00ea:\u00eb:\u00c8:\u00c9:\u00ca:\u00cb:\u00ec:\u00ed:\u00ee:\u00ef:\u00cc:\u00cd:\u00ce:\u00cf:\u00f1:\u00d1:\u00f2:\u00f3:\u00f4:\u00f5:\u00f6:\u00d2:\u00d3:\u00d4:\u00d5:\u00d6:\u00f9:\u00fa:\u00fb:\u00fc:\u00d9:\u00da:\u00db:\u00dc:\u00fd:\u00ff:\u00dd:\u0178'.split(':');
}

String.prototype.validTags=function(orte){

	var s=this;
	s=s.replace(/%7b/gi,'{').replace(/%7d/gi,'}');
	s=s.replace(/<[^>\s]*/g,function(match){return match.toLowerCase();});
	s=s.replace(/<[^>]*>/g,function(match){
		match=match.replace(/\s[^=]+=/g,function(match2){return match2.toLowerCase();});
		return match;
	});
	s=s.replace(/<[^>]*>/g,function(match){
			match=match.replace(/( [^=]+=)([^"][^\s>]*)/g,"$1\"$2\"");
			return match;
	});
	s=s.replace(/<!\-\-.{0,}\-\->/g,'');
	s=s.replace(/<b(\s+|>)/g,"<strong$1");
	s=s.replace(/<\/b(\s+|>)/g,"</strong$1");
	s=s.replace(/<i(\s+|>)/g,"<em$1");
	s=s.replace(/<\/i(\s+|>)/g,"</em$1");

	var skip=['','object','param','embed',''].join(':');

	s=s.replace(/<[^>]*>/g,function(match){
			var tag=match.split(' ')[0].replace(/[<>\/]/g,'').toLowerCase();
			if(skip.indexOf(':'+tag+':')!=-1){
				return match;
			}else if(orte.allowTagsCache.indexOf(':'+tag+':')==-1){
				return '';
			}else{
				match=match.replace(/\s([^=]+)="([^"]*)"/g,function(match2,att,value){
					switch(att){
						case'alt':case'title':case'href':case'align':case'target':break;
						case'style':if(tag!='img'){match2='';}break;
						case'face':case'size':case'color':if(tag!='font'||!orte.isFontTagValid){match2='';}break;
						case'src':break;
						default:match2='';break;
					}
					return match2;
				});
				return match;
			}
		}
	);

	for(var name in orte.plugins){
		s=orte.plugins[name].postDataConverter(s);
	}

	return s;
};

String.prototype.isInlineName=function(){
	return ':#text:a:em:i:font:span:b:strong:u:strike:s:sup:sub:q:cite:'.indexOf(':'+this.toLowerCase()+':')!=-1;
};

function TTable(isEnabled,rte){
	this.isEnabled=isEnabled;
	this.rte=rte;
	this.title='table';
	this.panelIconConfig=[[21,'add','Insert Table']];
};

TTable.prototype=new TPlugin();

TTable.prototype.action=function(td,opc){

switch(opc){
	case 'addCol':
		var t=td.parentNode.parentNode,tr=null;
		for(var i=0;tr=t.rows[i];i++){
			$(tr).add('td','\u00a0');
		}
	break;
	case 'addRow':
		var t=$(td.parentNode.parentNode),row=t.lastChild,tr=t.ac2('tr');
		for(var i=0;i<row.cells.length;i++){
			tr.add('td','\u00a0');
		}
	break;
	case 'delRow':
		td.parentNode.parentNode.removeChild(td.parentNode);
	break;
	case 'delCol':
		var ci=td.cellIndex;
		var t=td.parentNode.parentNode;
		for(var i=0;i<t.rows.length;i++){
			t.rows[i].removeChild(t.rows[i].cells[ci]);
		}
	break;
	case 'delCell':
		var tr=td.parentNode;
		tr.removeChild(td);
		if(tr.cells.length==0){
			tr.parentNode.removeChild(tr);
		}
	break;
	case 'colSpan+':
		td.att('colSpan',(td.att('colSpan')||1)+1);
	break;
	case 'colSpan-':
		td.att('colSpan',((td.att('colSpan')||1)>1?td.att('colSpan')-1:1));
	break;
	case 'rowSpan+':
		td.att('rowSpan',(td.att('rowSpan')||1)+1);
	break;
	case 'rowSpan-':
		td.att('rowSpan',((td.att('rowSpan')||1)>1?td.att('rowSpan')-1:1));
	break;
	case 'cellBefore':
		td.before().add('td','\u00a0');
	break;
	case 'cellAfter':
		td.after().add('td','\u00a0');
	break;
}
};

TTable.prototype.list=function(n,path){
	return [
		['addRow','Add Row'],
		['addCol','Add Column'],
		['cellBefore','Add Cell Before'],
		['cellAfter','Add Cell After'],
		['colSpan+','Cell ColSpan+'],
		['colSpan-','Cell ColSpan-'],
		['rowSpan+','Cell RowSpan+'],
		['rowSpan-','Cell RowSpan-'],
		['delCell','Remove this Cell'],
		['delCol','Remove this Column'],
		['delRow','Remove this Row']
	];
};

TTable.prototype.isNeeded=function(n,path){
	return tag(n)=='td';
};

TTable.prototype.add=function(){

	var rte=this.rte;
	rte.saveRange();
	var c=rte.initSlaveXY(this.xy,'addTable','Insert Table');
	var rows=c.add('label','Number of rows: ').ac(input('text','rows'));
	rows.setAttribute('maxLength','2');

	var cols=c.add('label','Number of cols: ').ac(input('text','cols'));
	cols.setAttribute('maxLength','2');

	var b=c.add('button','do it');

	if(!isIE){
		b.att('type','button');
	}

	EvMan.AddTmp('dlg',b,'click',addTable);

	function addTable(){

		if(!(/^\d+$/.test(rows.value))){alert('Enter number of rows!');rows.focus();return;}
		if(!(/^\d+$/.test(cols.value))){alert('Enter number of columns!');cols.focus();return;}

		var html='',row='',col='';

		for(var i=0;i<cols.value;i++){
			col+='<td>&nbsp;</td>';
		}

		for(var i=0;i<rows.value;i++){
			row+='<tr>'+col+'</tr>';
		}

		rte.insertHTML('<table>'+row+'</table>');
	}
	rte.onBuiltMenu();
};




function Link(isEnabled,rte){
	this.isEnabled=isEnabled;
	this.rte=rte;
	this.title='link';
	this.panelIconConfig=[
		[18,'add','Insert Link'],
		[19,'remove','Remove link']
	];
}

Link.prototype=new TPlugin();

Link.prototype.add=function(){

	var targets=[
		['New window','_blank'],
		['Current window','']
	];

	var rte=this.rte;
	var rng=rte.getRange(),n=rng.n,sel=rng.sel,parentLink=n;

	while(tag(parentLink)!='a' && parentLink.parentNode){
		parentLink=parentLink.parentNode;
	}

	var text;
	var lu=input('text','lu');
	var lh=input('text','lh');
	var tg=cn('select');

	targets.each(function(el){tg.add('option',el[0]).att('value',el[1]);});

	if(tag(parentLink)=='a'){

		rte.selectNode(parentLink);
		lh.value=parentLink.title;
		lu.value=parentLink.href;
		text=parentLink.innerHTML;
		tg.value=parentLink.target||'';

	}else if(sel.toString()!==''||rng.range.htmlText!==''){

		lu.value='http://';
		var temp=ce('div');
		try{
			temp.appendChild(rng.range.cloneContents());
			text=temp.innerHTML;
		}catch(er){

			text=rng.range.htmlText;
		}
	}else{
		lu.value='http://';
	}

	rte.saveRange();
	var c=rte.initSlaveXY(this.xy,'addLink','add/edit link');

	c.add('label','link URL');
	c.ac(lu);
	c.add('label','link hover message');
	c.ac(lh);
	c.add('label','open in');
	c.ac(tg);
	c.add('label','link text (html)');
	var lt=c.add('textarea',text||'');
	setHover(lt);

	var b=c.add('button','do it');

	if(!isIE){
		b.att('type','button');
	}

	EvMan.AddTmp('dlg',b,'click',function(e){

		if(lu.value===''){
			lu.focus();
			alert('Please enter link URL');
			return;
		}

		if(lt.value===''){
			lt.focus();
			alert('Please enter link text');
			return;
		}

		var target='';
		if(tg.value!==''){
			target=' target="'+tg.value+'"';
		}
		var link='<a href="'+lu.value+'" title="'+lh.value+'"'+target+'>'+lt.value+'</a>';
		rte.insertHTML(link);
	});

	rte.onBuiltMenu();
};

Link.prototype.remove=function(){this.rte.exec('unlink','');}
Link.prototype.action=function(n,opc){
	switch(opc){
		case 'add':this.add();break;
		case 'remove':this.remove();break;
		case 'open':var w=window.open(n.href); window.setTimeout(function(){w.focus()},10);break;
	}
};

Link.prototype.list=function(n,path){
	return [
		['add','Edit Link'],
		['remove','Remove Link'],
		['open','Open link(new window)']
	];
};

Link.prototype.isNeeded=function(n,path){
	return tag(n)=='a';
};



function TSpecialChar(isEnabled,rte){
	this.isEnabled=isEnabled;
	this.rte=rte;
	this.title='Special Char';
	this.panelIconConfig=[[17,'add','Insert '+this.title]];
}

TSpecialChar.prototype=new TPlugin();
TSpecialChar.prototype.action=function(n,opc){};
TSpecialChar.prototype.add=function(){

	var rte=this.rte;
	rte.saveRange();
	var c=cn('div');

	EvMan.AddTmp('dlg',c,'click',click);
	EvMan.AddTmp('dlg',c,'mouseover',over);
	EvMan.AddTmp('dlg',c,'mouseout',out);

	getUnicodes().each(function(t){c.add('span',t)});

	function over(e){
		(e.srcElement||e.target).className='rteChar';
	}

	function out(e){
		(e.srcElement||e.target).className='';
	}

	function click(e){
		rte.insertHTML((e.srcElement||e.target).firstChild.nodeValue);
	}

	rte.initSlave(17,'addChar','Insert '+this.title).ac(c);
	rte.onBuiltMenu();
};

TSpecialChar.prototype.isNeeded=function(n,path){
	return false;
};






function TColor(isEnabled,rte){
	this.isEnabled=isEnabled;
	this.rte=rte;
	this.title='Text Color';
	this.panelIconConfig=[[29,'add','Set '+this.title]];
}

TColor.prototype=new TPlugin();

TColor.prototype.action=function(n,opc){
};

TColor.prototype.add=function(){

	var rte=this.rte;
	var c=cn('table').ac2('tbody');

	var pal=[
		[['fff'],['fcc'],['fc9'],['ff9'],['ffc'],['9f9'],['9ff'],['cff'],['ccf'],['fcf']],
		[['ccc'],['f66'],['f96'],['ff6'],['ff3'],['6f9'],['3ff'],['6ff'],['99f'],['f9f']],
		[['C0C0C0'],['f00'],['f90'],['fc6'],['ff0'],['3f3'],['6cc'],['3cf'],['66c'],['c6c']],
		[['999'],['c00'],['f60'],['fc3'],['fc0'],['3c0'],['0cc'],['36f'],['63f'],['c3c']],
		[['666'],['900'],['c60'],['c93'],['990'],['090'],['399'],['33f'],['60c'],['939']],
		[['333'],['600'],['930'],['963'],['660'],['060'],['366'],['009'],['339'],['636']],
		[['000'],['300'],['630'],['633'],['330'],['030'],['033'],['006'],['309'],['303']]
	];

	function h(e){(e.srcElement||e.target).cls('hover');}
	function o(e){(e.srcElement||e.target).cls('');}
	function _c(e){
		var v=(e.srcElement||e.target).style.backgroundColor;
		if(/^rgb/.test(v)){
			v='#'+v.replace(/[^0-9,]/g,'').replace(/\d+/g,function(m){return parseInt(m).toString(16).replace(/^(\d)$/,'0$1')}).replace(/,/g,'');
		}
		rte.exec('forecolor',v);
		rte.hideSlave();
	}

	EvMan.AddTmp('dlg',c,'mouseover',h);
	EvMan.AddTmp('dlg',c,'mouseout',o);
	EvMan.AddTmp('dlg',c,'click',_c);

	for(var i=0;i<pal.length;i++){
		var tr=c.ac2('tr');
		for(var j=0;j<(pal[i].length-1);j++){

			var td=tr.add('td','\u00a0');
			var col=pal[i][j].toString();

			if(col.length==3){
				td.s().backgroundColor='#'+col.replace(/(\S)/g,'$1$1');
			}else{
				td.s().backgroundColor='#'+col;
			}
			td=null;
		}
		tr=null;
	}

	rte.initSlaveXY(this.xy,'addColor','Set '+this.title).ac(c.parentNode);
	rte.onBuiltMenu();
};

TColor.prototype.isNeeded=function(n,path){
	return false;
};







function TImage(isEnabled,rte){
	this.isEnabled=isEnabled;
	this.rte=rte;
	this.title='image';
	this.panelIconConfig=[[20,'add','Insert Image']];
}

TImage.prototype=new TPlugin();

TImage.prototype.action=function(n,opc){
	switch(opc){
		case'left':
			this.align(n,'left');
		break;
		case'right':
			this.align(n,'right');
		break;
		case'none':
			n.style.position='relative';
			this.align(n,'');
		break;
		case'replace':
			this.add();
		break;
	}
};

TImage.prototype.align=function(el,al){
	el.align='';
	el.setAttribute('align','');
	el.removeAttribute('align');
	el.removeAttribute('style');
	if(al){
		el.style['float']=al;
		el.setAttribute('align',al);
	}
};

TImage.prototype.list=function(n,path){
	return [
		['replace','Replace image'],
		['left','Align: left'],
		['right','Align: right'],
		['none','Align: none']
	];
};

TImage.prototype.add=function(){

	var rte=this.rte;
	rte.saveRange();

	var c=rte.initSlaveXY(this.xy,'addImage','Insert Image');

	var ims=this.data;
	if(ims.length==0){
		c.add('h3','No images');
		EvMan.AddTmp('dlg',c.add('button','close'),'click',function(e){rte.hideSlave();stopEvent(e);});
	}

	var c2=c.ac2('div');
	var c3=c.ac2('p');

	for(var i=0;i<ims.length;i++){
		this.item_(c2,c3,ims[i]);
	}

	rte.onBuiltMenu();
};

TImage.prototype.item_=function(n,p,im){

	var o=n.add('a',im[0]).att('href','action: Click to preview').att('title','Click to preview'),self=this.rte;
	path = this.config.TPL_REL_IMG_URL+'//';

	EvMan.AddTmp('dlg',o,'click',function(e){
		clearNode(p);
		p.add('h2','Preview: '+im[0]);
		var maxX=200,maxY=150;
		var src=path+im[1];
		var img=ce('img');
		img.src=src;
		p.ac(img);
		img.width=maxX;
		img.height=maxY;

		var b=p.add('button','insert');
		if(!isIE){
			b.att('type','button');
		}

		EvMan.AddTmp('dlg',b,'click',function(e){
			var html='<img src="'+src+'" alt="'+im[0]+'" />';
			self.insertHTML(html);
		});
		stopEvent(e);
	});
};

TImage.prototype.isNeeded=function(n,path){
	return tag(n)=='img';
};

TImage.prototype.preDataConverter=function(html){
	return html.replace(/\{TPL_REL_IMG_URL\}/gi,this.config.TPL_REL_IMG_URL+'//');
};

TImage.prototype.postDataConverter=function(html){
	return html.replace(/<img[^>]*>/g,function(match){return match.replace(/src=".+\/\/\//,'src="{TPL_REL_IMG_URL}')});
};



THTMLObject=function(isEnabled,rte){

	this.isEnabled=isEnabled;
	this.rte=rte;
	this.title='HTML Object';
	this.panelIconConfig=null;
};

THTMLObject.prototype=new TPlugin();
THTMLObject.prototype.isNeeded=function(){return true};

THTMLObject.prototype.add=function(cmd){

	var id=cmd[2],list=[];
	for(var i=0;i<this.data.length;i++){
		if(this.data[i][0]==id && this.data[i][2].length>0){
			list=this.data[i][2];
		}
	}

	if(list.length==0){
		return false;
	}

	var rte=this.rte;
	var rng=rte.getRange();

	if(tag(rng.n)=='img'){
		rte.selectNode(rng.n.parentNode);
	}

	var c=rte.initSlaveXY(null,'addObject','Insert HTML Object');

	var c2=c.ac2('div');

	for(var i=0;i<list.length;i++){
		this.listItem(c2,list[i]);
	}

	rte.onBuiltMenu();
};

THTMLObject.prototype.listItem=function(c2,li){
	var rte=this.rte;
	EvMan.AddTmp('dlg',c2.add('a',li[0]).att('href','action: '+li[0]),'click',function(e){
		stopEvent(e);
		rte.insertHTML(li[1]);
	});
};

THTMLObject.prototype.action=function(n,opc){
	switch(opc){
		case 'add': this.add(); break;
	}
};

THTMLObject.prototype.isNeeded=function(){
	return false;
};

THTMLObject.prototype.getAddAction=function(){
	var titles=[],self=this;
	for(var i=0;i<this.data.length;i++){
		if(this.data[i].length>0){
			titles.push(function(de){return [self,de[1],de[0]]}(this.data[i]));
		}
	}
	return titles;
};



function THTMLEdit(isEnabled,rte){
	this.isEnabled=isEnabled;
	this.rte=rte;
	this.title='HTMLEditor';
	this.panelIconConfig=[[30,'action','Edit HTML']];
}

THTMLEdit.prototype=new TPlugin();

THTMLEdit.prototype.action=function(){

	var rte=this.rte;

	var root=rte.root.before().add('div','').cls('HTMLEdit');
	var oldToString = this.rte.toString;

	root.add('a','\u2190 back to editor').att('href','#').Eadd('click',function(e){
		stopEvent(e);
		rte.getFrameDoc().body.innerHTML=ta.value.validTags(rte);
		root.parentNode.removeChild(root);
		rte.toString=oldToString;
		rte.root.style.display='block';
		rte.paragraphise();
	});

	var ta=root.add('textarea',rte.toString().replace(/<\/p>/g,'</p>\n'));
	var xy=getXY(this.rte.root);
	var fxy=getXY(this.rte.iframe);
	var rs=root.style;

	rs.height=xy.h+'px';
	ta.focus();

	ta.style.width=(fxy.w-2)+'px';
	ta.style.height=fxy.h+'px';
	rte.toString=function(){return ta.value;};

	rte.root.style.display='none';
};

THTMLEdit.prototype.isNeeded=function(n,path){return false;};

function TPlugin(){
	this.xy=null;
	this.data=[];
	this.config={};
};

TPlugin.prototype.test=function(){return this.isEnabled;};
TPlugin.prototype.getTitle=function(){return this.title;};
TPlugin.prototype.getAddAction=function(){return [[this,'Add '+this.getTitle()]];};
TPlugin.prototype.getPanelIcons=function(){

	var rte=this.rte,frag=document.createDocumentFragment(),self=this;
	if(this.panelIconConfig){
		for(var i=0;i<this.panelIconConfig.length;i++){
			if(this.panelIconConfig[i]){

frag.appendChild(function(data){

	var a=cn('a').cls('rteAction').att('href','Action: '+data[2]).att('title',data[2]);
	a.s().backgroundPosition=(-data[0]*(rte.icon.x+1))+'px 50%';
	a.Eadd('click',function(e){
		self.rte.hideSlave();
		stopEvent(e);
		self.xy=getXY(a);
		self[data[1]]();
	});
	rte.cache[data[0]]=a;
	return a;

}(this.panelIconConfig[i]));

			}
		}
	}
	return frag;
};

TPlugin.prototype.loadData=function(data){this.data=data;};
TPlugin.prototype.loadConfig=function(config){this.config=config;};
TPlugin.prototype.preDataConverter=function(html){return html;};
TPlugin.prototype.postDataConverter=function(html){return html;};
