/*
 wysiwyg редактор
*/

/*
 contentEdiytable IE, FireFox >= 3
 computedStyle в em подчёркнутый не определяется
 Зазор в опере между тулбаром и редактором
 isPropertyImplicit
*/

function editor(){
	
	var self=this;
	
	this.version='0.4 beta';
	
	//Создание редактора (id textarea)
	this.create=function(param){
		
		//Применяем параметры
		switch(typeof param){
			case 'string':
				self.sourceID=param;
				break;
			case 'object':
				var p=['sourceID','appendCSS','characterSet'];
				for(var i in p){
					self[p[i]]=param[p[i]];
				}
				break;
			case 'undefined':
				setError('Undefined editor parametr.');
				return;
				break;
		}
		
		//Ждём построения DOM
		addEvent(window,'load',this._create);
		
	}
	
	//
	this._create=function(){
		
		//Источник
		self.source=document.getElementById(self.sourceID);
		if(!self.source)return;
		self.source.className='source';
			
		var parent=self.source.parentNode;
		
		//Определение кодировки
		if(!self.characterSet)self.characterSet=self._getCharset(document);
		
		//Блок редактора
		self.block=parent.insertBefore(createElement('div'),self.source);
		self.block.id=self.source.id;
		self.source.removeAttribute('id');
		
		//Тулбар
		self.toolbar=self.block.appendChild(createElement('div'));
		self.toolbar.className='toolbar';
		
		//iframe для редактора
		self.frame=self.block.appendChild(createElement('iframe'));
		self.frame.className='frame';

		//Переносми textarea в блок редактора
		self.block.appendChild(self.source);
			
		//Ищем родительскую форму
		var p=self.source.parentNode;
		while(p.nodeName.toLowerCase()!='form')p=p.parentNode;
		
		//Перед отправкой формы производим генерацию кода
		addEvent(self.form=p,'submit',self._eBeforeSubmit);
		
		//Переводим фрейм в режим редактирования
		setTimeout(self._designMode, 150);//Задержка
	}
	
	//Переводим в режим редактирования
	this._designMode=function(){
		
		//Устанавливаем режим
		if(self.frame.contentDocument){//Gecko
			self.frame.contentDocument.designMode='on';
			try{
				self.frame.contentDocument.execCommand("useCSS", false, true) //Форматирование тегами
			}catch(e){ }
		}
		else if(self.frame.contentWindow){//IE
			self.frame.contentWindow.document.designMode='On'
		}
		else{
			setError('Your browser do not support iframe designMode.');
			return;
		}
			
		//Запоминаем переменные
		self.document=self.frame.contentWindow.document;
		self.content=self.frame.contentWindow;

		//Наполняем фрейм контентом
		setTimeout(self._setContent, 5);//Задержка
	}
	
	//Наполнение контентом
	this._setContent=function(){
		
		self.element=self.document.documentElement;
		
		self.body=self.element.getElementsByTagName('body')[0];
		if(!self.body){
			self.body=self._createElement('body');
			self.element.appendChild(self.body)
		}
		
		self.head=self.element.getElementsByTagName('head')[0];
		if(!self.head){
			self.head=self._createElement('head');
			self.element.insertBefore(self.head,self.body)
		}
		
		//Кодировка (т.к. наблюдаются проблемы с Opera для Mac)
		if(window.opera){
			var meta=self._createElement('meta');
			meta.setAttribute('http-equiv','Content-Type');
			meta.setAttribute('content','text/html; charset='+self.characterSet);
			self.head.appendChild(meta);
			
			self._setCharset(self.document,self.characterSet);
		}
	
		//Подключаем таблицу стилей
		if(self.appendCSS){
			var link=self._createElement('link');
			link.setAttribute('rel','stylesheet');
			link.setAttribute('type','text/css');
			link.setAttribute('href',self.appendCSS);
			self.head.appendChild(link)
		}

		//Наполняем из textarea
		var content='';
		/*if(navigator.userAgent.indexOf('MSIE')>-1){//IE*/
		//	if(self.source.firstChild)content=self.source.firstChild.nodeValue
		//	content=self.source.innerHTML
		//}
		var nodes = self.source.childNodes;
		for(var i = 0; i < nodes.length; i++){
			if(nodes[i].nodeType == 1){ // Узел Элемента
				if(nodes[i].outerHTML){ // IE, Opera
					content += nodes[i].outerHTML
				}else if(typeof XMLSerializer != 'undefined'){ // Gecko, WebKit
					content += new XMLSerializer().serializeToString(nodes[i]);
				}
				
			}else if(nodes[i].nodeType == 3){ // Узел Текста
				content += nodes[i].nodeValue
			}
		}
		
		if(content)self.body.innerHTML=content.replace(/^\s*|\s*$/,'');
		
		//Показываем панель инструментов
		self._loadToolbar();

		//Передаём фокус
		self._setFocus();

	}
	
	//Фокус в редакторе
	this._setFocus=function(){
		
		/* Исправляет проблему с размером курсива Gecko
		var range=self._getRange();
		range.setStart(self.body.firstChild,0);
		range.collapse(true);
		*/
		
		//Opera >= 9.6, Gecko (проблемы с размером курсива!!!), IE, WebKit (Проблема двойного срабатывания onload млжет из-за XSLT)
		self.content.focus();
		//Opera < 9.6
		if(window.opera)self.frame.focus();
		
	}
	
	//Возвращает кодировку
	this._getCharset=function(doc){
		
		return (doc.charset||doc.defaultCharset||doc.characterSet)
	
	}
	
	//Назначает кодировку
	this._setCharset=function(doc,charset){
		
		doc.charset=doc.defaultCharset=doc.characterSet=charset
	
	}
	
	//Область выделения
	this._getRange=function(){

		var range;
		if(self.content.getSelection){//Gecko
			range=self.content.getSelection().getRangeAt(0);
		}
		else if(typeof(self.document.selection)!='undefined'){//IE
			var sel=self.document.selection;
			if(self.content.range){
				range=self.content.range
			}else if(!sel.createRange().parentNode){
				self._setFocus();
				range=sel.createRange()
			}else{
				range=sel.createRange()
			}
			
		}
		return range
	}
	
	//Родитель области
	this._getRangeParent=function(range){
		
		if(range.parentElement){//IE
			return range.parentElement();
		}else if(range.commonParentElement){//IE
			return range.commonParentElement();
		}else if(range.startContainer){//Gecko
			return range.startContainer.parentNode
		}
	}
	
	//Текст области
	this._getRangeText=function(range){
		
		if(range.toString){//Gecko
			return range.toString()
		}else if(range.text){//IE
			return range.text
		}
	}
	
	//Вставка узла
	this._insertNode=function(node){
	
		var range=self._getRange();
		
		if(range.deleteContents){//Gecko, WebKit, Opera
			
			var selection=self.content.getSelection();
			range.deleteContents();
			range.insertNode(node);
			var newRange=self.document.createRange();
			newRange.setStartAfter(node);
			newRange.setEndAfter(node);
			selection.removeAllRanges();
			range.detach();
			selection.addRange(newRange);

		}
		else if(range.pasteHTML){//IE
			range.select();
			range.pasteHTML(node.nodeType==3 ? node.nodeValue : node.outerHTML)
		}
	}
	
	//Создание элемента с учётом пространства имён
	this._createElement=function(name){

		return self.document.createElement(name)
	}
	
	//Расчитаный стиль элемента
	this._getStyle=function(el,prop){
		
		if(self.content.getComputedStyle){//Gecko, WebKit, Opera
			return self.document.defaultView.getComputedStyle(el,null).getPropertyValue(prop)
		}else if(el.currentStyle){//IE
			//Перевод из css начертания в верблюжее начертание
			var re=/(\-([a-z]){1})/g;
			if(prop=='float')prop='styleFloat';
			if(re.test(prop)){
				prop=prop.replace(re,function(){
					return arguments[2].toUpperCase()
				});
			}
			//
			return el.currentStyle[prop]
		}
	}
	
	//Добавление кнопки
	this._addButton=function(name,text){
		
		var el;
	
		if(name=='_br'){
			el=createElement('div');
			el.className='br'
		}
		else if(name){
			/*
				Использование ссылки в качестве кнопки
				позволяет избежать потери выделения в iframe,
				при отсутствии которого не возможно форматировать выделенную область
			*/
			el=createElement('a');
			el.className='button '+name.toLowerCase();
			el.title=text;
			el.action=name;
			el.href='#';
			self.toolbar[name]=el;
			el.onclick=self._action;
			el.sel=function(){addClass(this,'selected')};
			el.unsel=function(){removeClass(this,'selected')};
		}else{
			el=createElement('div');
			el.className='separator'
		}
		
		self.toolbar.appendChild(el);
		
	}
	
	//Проверка стилей текста в заданной точке
	this._checkStyle=function(){
		
		var el=self._getRangeParent(self._getRange());
		var style;
		var value;
		
		//Полужирный
		style=self._getStyle(el,'font-weight');
		value=(/\bbold\b/.test(style) || parseInt(style)>400)?'sel':'unsel';
		self.toolbar.Bold[value]();
		
		//Курсив
		style=self._getStyle(el,'font-style');
		value=/\bitalic\b/.test(style)?'sel':'unsel';
		self.toolbar.Italic[value]();
		
		//Подчёркнутый, Перечёркнутый
		//Поднимаемся вверх пока не найдём без значения
		style='';
		var p=el;
		while(p){
			var val=self._getStyle(p,'text-decoration');
			if(/\bnone\b/.test(val))break;
			style+=val+' ';
			p=p.parentNode
		};
		value=/\bunderline\b/.test(style)?'sel':'unsel';
		self.toolbar.Underline[value]();
		value=/\bline\-through\b/.test(style)?'sel':'unsel';
		self.toolbar.StrikeThrough[value]();

	}
	
	//Событие : Обработка отжатия клавиши
	this._eKeyUp=function(e){
		
		var key=e.keyCode ? e.keyCode : e.which ? e.which : null;
		if(key==116){//Отменяем перезагрузку фрейма по f5
			doSomething(e)
		}
		//Клавиши навишации по редактору
		if( key>=36 || key<=40){
			//Проверка стиля текста в данной точке
			self._checkStyle();
		}
		return true
	}
	
	//Событие : Обработка отжатия мыши
	this._eMouseUp=function(e){

		//Запоминаем область выделения т.к в IE сбои при вставке с потеряным фокусом
		if(self.document.selection && self.document.selection.createRange().duplicate)self.content.range=self.document.selection.createRange().duplicate();
		
		//Проверка стиля текста в данной точке
		self._checkStyle();
		return true
	}
	
	//Событие : Отправка формы
	this._eBeforeSubmit=function(e){

		var xhtml=xhtmlChild(self.document.body);

		removeChild(self.source);

		//self.source.appendChild(document.createTextNode(xhtml));
		self.source.value=xhtml;

	}
	
	//Событие : Действие при клике на тулбаре
	this._action=function(e){
		
		e=e || window.event;
		var el=e.target || e.srcElement;

		//Прячем окна
		self._hidePopupAll();
		
		var act=el.action;

		switch(act){
			//Показываем окно смайлов
			case 'popupSmile':
				self.popup.smile.show(el);
				break;
			
			//Вставка смайла
			case 'appendSmile':
				/^url\([",']?([^\',",\)]+)/.test(self._getStyle(el,'background-image'));
				//self.document.execCommand('insertimage',false,RegExp.$1);
				var img=self.document.createElement('img');
				img.setAttribute('src',RegExp.$1);
				self._insertNode(img);
				self.popup.smile.hide();
				
				break;
			
			//Показываем окно символов
			case 'popupSymbol':
				self.popup.symbol.show(el);
				break;
			
			//Вставка символа
			case 'appendSymbol':
				self._insertNode(self.document.createTextNode(el.firstChild.nodeValue));
				self.popup.symbol.hide();
				break;
			
			//Показываем окно выбора цвета
			case 'popupColor':
				self.popup.color.show(el);
				break;
			
			//Назначаем цвет
			case 'setColor':
				self.document.execCommand('foreColor',false,rgbNormal(el.style.backgroundColor));//rgbNormal для Gecko
				self.popup.color.hide();
				break;
			
			case 'Bold':
			case 'Italic':
			case 'Underline':
			case 'StrikeThrough':
				if(existsClass(el,'selected')){
					removeClass(el,'selected')
				}else{
					addClass(el,'selected')
				}
				self.document.execCommand(act,false,false);
				break;
			case 'JustifyLeft':
			case 'JustifyCenter':
			case 'JustifyRight':
			case 'JustifyFull':
			case 'InsertUnorderedList':
			case 'InsertOrderedList':
				self.document.execCommand(act,false,false);
				break;
			
			//Вставка ссылки на пользователя
			case 'appendUser':
				var name=prompt('Введите никнейм пользователя','');
				if(name){
					var a=self.document.createElement('a');
					a.setAttribute('href','/'+name);
					a.appendChild(self.document.createTextNode(name));
					self._insertNode(a);
				}
				break;

			//Создание ссылки
			case 'CreateLink':
				var url=prompt('Введите URL ссылки','http://');
				if(url){
					if(self._getRangeText(self._getRange())){
						self.document.execCommand('CreateLink',false,url);
					}else{//Выделение пустое
						var a=self.document.createElement('a');
						a.setAttribute('href',url);
						a.appendChild(self.document.createTextNode(url));
						self._insertNode(a);
					}
				}

				break;

			//Вставка изображения по ссылке
			case 'appendImage':
				var url=prompt('Введите URL ссылки','http://');
				//if(url)self.document.execCommand('insertimage',false,url);
				if(url){
					var img=self.document.createElement('img');
					img.setAttribute('src',url);
					self._insertNode(img);	
				}
				break;
			break;

			//Показываем окно загрузки картинки
			case 'popupImage':
				self.popup.image.show(el);
				break;
		}
		
		self._setFocus();
		
		doSomething(e);
		
		return false;
		
	}
	
	//Строим панель иснструментов
	this._loadToolbar=function(){
		
		//Созданеи тулбара
		self._addButton('Bold','Жирный');
		self._addButton('Italic','Курсив');
		self._addButton('Underline','Подчёркнутый');
		self._addButton('StrikeThrough','Перечёркнутый');
		self._addButton();
		self._addButton('InsertUnorderedList','Список');
		self._addButton('InsertOrderedList','Нумерованый список');
		self._addButton();
		self._addButton('JustifyLeft','По левому краю');
		self._addButton('JustifyCenter','По центру');
		self._addButton('JustifyRight','По правому краю');
		self._addButton('JustifyFull','По ширине');
		self._addButton();
		self._addButton('popupColor','Выбрать цвет');
		self._addButton();
		self._addButton('appendUser','');
		self._addButton();
		self._addButton('popupSymbol','Символы');
		self._addButton();
		self._addButton('popupSmile','Смайлы');
		self._addButton();
		self._addButton('CreateLink','Ссылка');
		self._addButton();
		self._addButton('appendImage','Картинка по ссылке');
		self._addButton('popupImage','Картинка');
		self._addButton('_br');
		
		//Создание окон
		self._createPopup('color');
		self._createPopup('symbol');
		self._createPopup('smile');
		self._createPopup('image');
		
		//Обработчик для отслеживания стиля области
		addEvent(self.document,'keyup',self._eKeyUp);
		addEvent(self.document,'mouseup',self._eMouseUp);
		
/*

		//Запрет встаки
		//FF > 3, Safari, IE
		addEvent(self.body,'paste',function(event){
			//IE
			//alert(window.clipboardData.getData('Text'));
			
			//alert('Вставка запрещена');
			doSomething(event);
			return false;
		});

*/
		
		//Обрабочики начатия в редакторе и основном документе для закрытия окон
		addEvent(self.document,'mouseup',self._hidePopupAll);
		addEvent(document,'mouseup',self._hidePopupAll);
	}
	
	//Создаём модальные окна
	this._createModal=function(name){
		
	}
	
	//Создаём окна
	this._createPopup=function(name){
		
		//Создаём элемент окна
		//var popup=self.block.insertBefore(createElement('div'),self.block.firstChild);
		var popup=self.block.appendChild(createElement('div'));
		
		//Записываем в массив окон
		if(!self.popup)self.popup={};
		self.popup[name]=popup;

		switch(name){
			//Выбор цвета
			case 'color':
				var color=[null,'FF0000','FFFF00','00FF00','00FFFF','0000FF','FF00FF','FFFFFF','E6E6E6','DADADA','CECECE','C1C1C1','B5B5B5','A9A9A9','9C9C9C','8F8F8F','838383','D00025','FFEB00','00863F','0090DB','221CCD','D5005C','767676','696969','5C5C5C','4F4F4F','434343','363636','292929','1C1C1C','0E0E0E','000000','E5795D','EC9467','F3B272','FFF386','BBD384','96C584','76B983','71BDB5','6BC1EB','7293C3','757DAF','76689C','8F6E9F','AA75A1','E581A5','E57C7F','DA4937','E26D3E','ED8546','FFEE53','9EC459','6EB15B','37A05C','28A59C','09AAE4','3C72AC','465892','4E407C','70447D','92497F','DD5183','DC4C5B','D00025','D84324','E57420','FFEB00','7DB330','359B39','00863F','008B80','0090D8','005294','003777','221C5D','50175C','79115C','D5005C','D2003A','7B0012','802C12','874A10','9A9201','4B711F','1E6425','005829','005B52','005E8B','00345D','042049','170638','340938','4D0939','820037','7D0023','570000','5A1E03','5F3605','6C6A06','335417','0F4A1C','00421E','00443C','004566','002442','001233','110026','260026','390027','5F0027','5A0015','B5A186','81705E','5B4B40','3E3028','271E1F','B18857','8D653C','704A2A','59351E','462414','EDEDED'];
				for(var i=1;i<color.length-1;i++){
					var a=popup.appendChild(createElement('a'));
					a.style.backgroundColor='#'+color[i];
					a.href='#';
					a.action='setColor';
					a.onclick=self._action;
					if(i%16==0)popup.appendChild(createElement('br'));
				}
				break;
			
			//Выбор символа
			case 'symbol':
				var symbol=[null,"\u00A3","\u00A5","\u00B6","\u00BD","\u00BC","\u00B9","\u00B2","\u00B3","\u00DF","\u20AC","\u00AE","\u2122","\u2660","\u2663","\u2665","\u2666","\u00B1","\u00BC","\u2264","\u2265"];
				for(var i=1;i<symbol.length;i++){
					var a=popup.appendChild(createElement('a'));
					a.appendChild(document.createTextNode(symbol[i]));
					a.href='#';
					a.action='appendSymbol';
					a.onclick=self._action;
					if(i%4==0)popup.appendChild(createElement('br'));				
				}		
				break;
			
			//Выбор смайла
			case 'smile':
				for(var i=1;i<=37;i++){
					var a=popup.appendChild(createElement('a'));
					a.style.background='url("/img/smile/'+i+'.gif") center center no-repeat';
					a.href='#';
					a.action='appendSmile';
					a.onclick=self._action;
					if(i%7==0)popup.appendChild(createElement('br'));					
				}
				break;
			
			//Загрузка изображения
			case 'image':
				
				//Создание формы
				var form=createElement('form');
				popup.appendChild(form);
				
				//Создание объекта загрузчика
				var request=new iframeRequest();
				
				//Инициализация загрузчика
				request.init({
				  'form':form,
				  'url':'/cgi-bin/upload.pl',
				  'method':'post',
				  'encode':'multipart/form-data',
				  'target':'file-iframe'
				});
				
				//Параметры
				request.appendInput('hidden','mode','wysiwyg');
				request.appendInput('file','file','');
				request.appendInput('submit','','Загрузить');
				
				//Обработка событий загрузчика
				request.onReadyStateChange=function(){
				  if(request.readyState==4){			
					var imgID=request.getDocument().documentElement.getAttribute('id');
					var url='http://'+document.location.host+'/pic/images/'+imgID+'.jpg';	
					if(url){
						//self.document.execCommand('insertimage',false,url);
						var img=self.document.createElement('img');
						img.setAttribute('src',url);
						self._insertNode(img);
						self.popup.image.hide();
					}
				  }
				}
				break;
		}

		//
		popup.className='popup '+name;
		addEvent(popup,'mouseup',doSomething);
		popup.show=self._showPopup;
		popup.hide=self._hidePopup;
		
		//Скрываем окно
		popup.hide()
	}
	
	//Показываем окно
	this._showPopup=function(el){
		
		this.style.display='block';
		//Позиционируем относительно кнопки тулбара
		if(el){
			this.style.top=el.offsetHeight+'px';
			this.style.left=el.offsetLeft+el.offsetWidth-this.offsetWidth+'px'
		}
	}
	
	//Прячем окно
	this._hidePopup=function(){
		
		this.style.display='none'
	}
	
	//Прячем все окна
	this._hidePopupAll=function(){

		//Перебираем все окна
		for(var i in self.popup){
			self.popup[i].hide()
		}
	}
}


//Генерируем валидный xhtml из собержимого элемента
function xhtmlChild(el)
{
	var xhtml='';
	
	var child=el.childNodes;
	
	for(var i=0;i<child.length;i++){
		//Если елемент
		if(child[i].nodeType==1){
			var nodeName=child[i].nodeName.toLowerCase();
			//Если br, img
			if(nodeName=='br' || nodeName=='img'){
				xhtml+='<'+nodeName+xhtmlAttribute(child[i])+' />';
			}else{
				xhtml+='<'+nodeName+xhtmlAttribute(child[i])+'>'+xhtmlChild(child[i])+'</'+nodeName+'>';		
			}
		}
		//Если текстовый узел
		else if(child[i].nodeType==3){
			//Если родитель pre
			//if(child[i].parentNode.nodeName.toLowerCase()=='pre'){
			//	xhtml+=child[i].nodeValue
			//}else{
				xhtml+=xhtmlEscsape(child[i].nodeValue)
			//}
		}
	}
	
	return xhtml
}

//Генерируем валидный xhtml из атрибутов элемента
function xhtmlAttribute(el)
{
	var xhtml='';
	var attr=el.attributes;
	
	for(var i=0;i<attr.length;i++){
		
		var nodeName=attr[i].nodeName.toLowerCase();
		var nodeValue=attr[i].nodeValue;
		
		if(
		   nodeValue &&
		   (
		    nodeName=='style' ||
		    nodeName=='src' ||
		    nodeName=='color' ||
		    nodeName=='align' ||
		    nodeName=='href'
		   )
		){
			xhtml+=' '+nodeName+'="'+xhtmlEscsape(nodeValue)+'"'			
		}
	}
	
	return xhtml
}

//
function xhtmlEscsape(text)
{
	text=text.replace(/</g,'&#60;'); //&lt;
	text=text.replace(/>/g,'&#62;'); //&rt;
	text=text.replace(/"/g,'&#34;'); //&quot;
	text=text.replace(/'/g,'&#039;');
	text=text.replace(/&/g,'&#38;'); //&amp;
	text=text.replace(/\s\s/g,' &#160;'); //&nbsp;
	
	return text;
}
