// ============================= UI =============================

var UI={}

UI._proto=function(params){
	this.constructor=function(params){
		// инит значений по умолчанию (params дополняется значениями из this.defaults)
		if(typeof(this.defaults)=='object')
			params=function(from,to){
				var ret=to;
				for(var k in from)if(typeof(from[k])=='object'){
					if(to[k]==undefined)to[k]={}
					ret[k]=arguments.callee(from[k],to[k]);
				}else if(to[k]==undefined)ret[k]=from[k];
				return ret;
			}(this.defaults,params);
		
		// инициализируем местоположение объекта
		switch(typeof params){
		case 'string': this.itemLink=byId(params); break;
		case 'object':
			if(params.placeTo){
				this.itemLink=typeof(params.placeTo)=='string'?byId(params.placeTo):params.placeTo;
			}else{// placeTo is not defined, create new...
				this.createStructure(params);
			}
			for(var k in params)switch(k){
				case 'placeTo':break;
				default: this[k]=params[k];
			}
			break;
		case 'null':
		case 'undefined':
		default:// placeTo is not defined, create new...
			this.createStructure(params);
			break;
		}
		this.itemLink.parentObject=this;
	}
	
	/* добавляет обработчик события на объект. События и где их обрабатывать определяются самим классом. */
	this.addEvent=function(type,handler){
		//alert(this);
		//alert(self);
		var self=self?(self==window?this:self):this;
		if(!self.events)self.events={};
		if(!self.events[type])self.events[type]=[];
		self.events[type][self.events[type].length]=handler;
	}
	
	this.removeEvent=function(type,handler){
		var self=self?(self==window?this:self):this;
		if(!self.events[type])return false;
		for(var k in self.events[type])
			if(self.events[type][k]==handler)
				self.events[type][k]=null;
	}
	
	/* Вызывает установленные обработчики события.
	*/
	this.handleEvent=function(type,params){
		var self=self?(self==window?this:self):this;
		if(!self.events)return false;
		if(!self.events[type])return false;
		for(var k in self.events[type])
			if(self.events[type][k])
				self.events[type][k](params);
	}
}

/* Экспериментальная функция, поэтому не заменять функционал по умолчанию */
UI.generateName=function(namespace,objType,element){
	//var objType=element.getAttribute('data-obj');
	if(!namespace[objType])namespace[objType]={}
	var i=1;var k=objType+i;
	while(namespace[objType][k]!=undefined){
		k=objType+i;
		i++;
	}
	k=element.getAttribute('data-id')?element.getAttribute('data-id'):k;
	return k;
}

UI.liven=function(element){
	if(element.getAttribute('data-obj') && UI[element.getAttribute('data-obj')] && !element.parentObject){// this tag is object
		// select/generate object name
		var i=1;
		var objType=element.getAttribute('data-obj');
		if(!document.objects[objType])document.objects[objType]={}
		var k=objType+i;
		while(document.objects[objType][k]!=undefined){
			k=objType+i;
			i++;
		}
		var k=element.getAttribute('data-id')?element.getAttribute('data-id'):k;
		
		// prepare init params
		var _init={}
		if(element.getAttribute('data-init'))
			var _init=eval('('+element.getAttribute('data-init')+')');
		_init.placeTo=element;
		_init.objType=objType;
		_init.objName=k;
		//_init.objects={};
		//if(element.__objects)for(var kk in element.__objects)_init.objects[k]=
		
		// object init
		document.objects[objType][k]=new UI[objType](_init);
	}else if(element.getAttribute('data-init'))
		element.data=eval('('+element.getAttribute('data-init')+')');
}

/** Подобно функции nodeWalk пробегает, но уже по объектам, по их иерархии
	В хэндлер первым аргументом передает ссылку на объект.
*/
UI.objWalk=function(obj,handler){
	if(typeof obj=='object'){
		if(obj.objType){//if(obj instanceof UI[obj.objType])
			handler(obj);
			var walk=obj.objects?obj.objects:false;
		}else var walk=obj;
		for(var k in walk){
			if(typeof walk[k]=='object')
				arguments.callee(walk[k],handler);
		}
	}else return false;
}

/*UI.nestObjects=function(element,parentObject){
	element=!element?document.body:element;
	//handler(element);
	//parentObject
	if(element.getAttribute('data-obj')){// element.parentObject
		var newParent=element;//.parentObject;
		if(parentObject &&  element.getAttribute('data-id')){
			if(!parentObject.__objects)parentObject.__objects={}
			parentObject.__objects[element.getAttribute('data-id')]=newParent;
		}
	}else newParent=parentObject;

	for(var _i=0;_i<element.childNodes.length;_i++)
		if(element.childNodes[_i].nodeType==1)
			arguments.callee(element.childNodes[_i],newParent);
}*/

UI.nestObjects=function(element,parentObject){
	element=!element?document.body:element;
	if(element.parentObject){
		var newParent=element.parentObject;
		if(parentObject){
			if(!parentObject.objects)parentObject.objects={}
			parentObject.objects[newParent.objName]=newParent;
		}
	}else newParent=parentObject;

	for(var _i=0;_i<element.childNodes.length;_i++)
		if(element.childNodes[_i].nodeType==1)
			arguments.callee(element.childNodes[_i],newParent);
}

UI.__initObjectsHandle=function(element){
	if(element.parentObject)
		element.parentObject.handleEvent('initobjects');
}


// ============== find elements ==============

// массив всех элементов интерфейса по типам
document.objects={}

// применяем 
addEvent(window,'load',function(){
	nodeWalk(function(element){
		if(element.getAttribute('data-onload')!=null)
			eval('('+element.getAttribute('data-onload')+')');
	});
	nodeWalk(UI.liven);
	UI.nestObjects();
	nodeWalk(UI.__initObjectsHandle);
});


/* ************************************************************************* */
/* ******************************** OBJECTS ******************************** */
/* ************************************************************************* */


/* ============================= slideshow =============================
аргументы:
	

*/


UI.slideshow=function(params){
	var self=this;

	/* Переключает на указанный слайд (без эффектов) */
	this.fastSwitchTo=function(number){
		var oldIndex=self.current;

		self.slides[self.current].style.display='none';
		self.current=number;
		self.slides[self.current].style.display='block';

		self.handleEvent('onswitch',{
			newIndex:self.current,
			oldIndex:oldIndex
		});
	}
	
	/* Переключает на указанный слайд, сопровождая эффектами */
	this.switchTo=function(number){
		var oldIndex=self.current;
		switch(self.switchStyle){
		case 1:
			self.slides[number].style.opacity=0;
			var i=0;
			self.slides[number].style.display='block';
			
			var stepTime=self.switchStyleParams.time/self.switchStyleParams.steps;
			//alert(stepTime);
			var opacity=setInterval(function(){
				i+=(1/self.switchStyleParams.steps);
				self.slides[number].style.opacity=i;
				//alert(self.slides[number].style.opacity);
				if(self.slides[number].style.opacity>=1){
					clearInterval(opacity);
					self.slides[self.current].style.display='none';
					self.current=number;
					self.handleEvent('onswitch',{
						newIndex:self.current,
						oldIndex:oldIndex
					});
				}
			},stepTime);
			
			break;
		default:// без эффектов
			self.slides[self.current].style.display='none';
			self.current=number;
			self.slides[self.current].style.display='block';
			self.handleEvent('onswitch',{
				newIndex:self.current,
				oldIndex:oldIndex
			});
		}
	}
	
	/* переключает на следующий слайд */
	this.switchNext=function(event){
		var next=(self.current==self.slides.length-1)?0:self.current+1;
		if(self.current==self.slides.length && !self.loop)self.stop();
			else self.switchTo(next);
	}
	
	/* запускает переключение слайдов */
	this.play=function(){
		if(self.slideshow!=undefined)self.stop();
		self.slideshow=setInterval(self.switchNext,self.delay*1000);
	}
	
	/* останавливает переключение слайдов */
	this.stop=function(){
		if(self.slideshow===undefined)return false;
		clearInterval(self.slideshow);
		self.slideshow=undefined;
	}

	this.createStructure=function(params){
		alert('createStructure slides!');
		this.itemLink=new node({
			tagName:'div',
			className:'slideshow'
		});
	}
	
	/* constructor */
	this.events={
		onswitch:[]			// срабатывает, когда переключается слайд
	}
	this.defaults={
		delay:10,
		current:0,
		loop:true,
		launch:true,
		switchStyle:1,
		switchStyleParams:{steps:20,time:1000}
	}
	this.constructor(params);// конструктор по умолчанию
	
	// find slides
	this.slides=[];
	for(var k in this.itemLink.childNodes){
		var slide=this.itemLink.childNodes[k];
		if(slide.tagName=='DIV'&&slide.className=='slide'){
			if(this.slides.length!=this.current)slide.style.display='none';
			this.slides[this.slides.length]=slide;
		}
	}
	
	// launch slideshow
	if(this.launch)
		this.play();
}

UI.slideshow.prototype=new UI._proto;

/* ============================= gallery =============================

аргументы:
	scrollStyle - параметры стиля прокрутки.
		type - тип стиля прокрутки. Одно из:
			linear - линейная прокрутка. За один шаг меняется на фиксированное число пикселей
				(1/steps от ширины одной картинки).
			hyperbolic - гиперболическая прокрутка. За 1 шаг подвигается на 1/ratio пикселей, от того,
				сколько осталось докрутиться.
		timeout - время в миллисекундах на один шаг
		steps - параметр для линейной прокрутки
		ratio - параметр для гиперболической прокрутки
	scrollPosition - элемент, на котором находится прокрутка. Нач. с нуля.
	scrollOffset - смещение прокрутки в пикселах (положительное число)
	scrollReverse - если тру, меняет поведение колеса мыши

*/

UI.gallery=function(params){
	this.createStructure=function(params){
		alert('createStructure gallery!');
		this.itemLink=new node({
			tagName:'div',
			className:'gallery',
			childNodes:[
				{tagName:'a',className:'previous'},
				{tagName:'ul'},
				{tagName:'a',className:'next'}
			]
		});
		params={};
	}
	
	/* Прокручивает галерею на pos шагов. (если pos<0, прокручивает влево. Если больше нуля - вправо )
	*/
	this.scroll=function(pos){
		var newPos=self.scrollPosition+pos<0?0:
			(self.scrollPosition+pos > _itemsAmount-_itemsVisibly?
				_itemsAmount-_itemsVisibly:
				self.scrollPosition+pos);
		self.scrollPosition=newPos;
		_scrollEnd();
	}
	
	/* выделяет элемент с номером index */
	this.select=function(index){
		if(self.selected!=undefined)
			self.itemLinks.items[self.selected].selectChild('a').className='';
		self.selected=index;
		self.itemLinks.items[self.selected].selectChild('a').className='selected';
	}
	
	/* Прокручивает элемент с номером index в поле зрения. Если index не указан, применяется к выделенному пункту. */
	this.scrollIntoView=function(index){
		var index=index||self.selected;
		var hidden=(index>=self.scrollPosition+_itemsVisibly)||(index<self.scrollPosition);
		if(hidden){// элемент не в поле зрения
			var scrollDiff=(index>=self.scrollPosition+_itemsVisibly)?
				(index-(self.scrollPosition+_itemsVisibly-1)):
				(index-self.scrollPosition);
			self.scroll(scrollDiff);
		}
	}
	
	/* возвращает значение (в пикселах), на сколько надо прокрутить до нормы.
	Если минус - значит вправо, если плюс, значит в лево.
	*/
	var _scrolled=function(){
		self.scrollOffset=-parseInt(self.itemLinks.list.style.left);
		var need=self.scrollPosition*self.itemWidth;
		return self.scrollOffset-need;
	}
	
	/* докручивает до состояния, когда совпадает прокрутка с позицией */
	var _scrollEnd=function(){
		if(_scrolled()!=0 && _scrollFn==null)
			_scrollFn=setInterval(function(){
				var delta=_scrolled();// недопрокрутили
				if(delta==0){
					clearInterval(_scrollFn);
					_scrollFn=null;
				}else switch(self.scrollStyle.type){// стиль прокрутки
					case 'linear':
						var step=Math.floor(self.itemWidth/self.scrollStyle.steps)*(delta>0?1:-1);
						if(Math.abs(step)>Math.abs(delta))step=delta;
				 		self.scrollOffset=self.scrollOffset-step;
						break;
					default: // hyperbolic
				 		self.scrollOffset=self.scrollOffset-Math.ceil(delta/self.scrollStyle.ratio);
				}
				self.itemLinks.list.style.left=-self.scrollOffset+'px';
			},self.scrollStyle.timeout);
	}

	/* constructor */
	var self=this;
	this.events={				// support?
		'itemclick':[],			// *			срабатывает, когда кликаешь мышкой по любому элементу
		'scroll':[],			// 
		'scrollleft':[],		// 
		'scrollright':[],		// 
		'previousclick':[],		// 
		'nextclick':[],			// 
		'keypress':[]			// 
	}
	this.defaults={
		scrollStyle:{type:'hyperbolic',ratio:5,timeout:20,steps:10},
		scrollPosition:0,
		scrollOffset:0,
		scrollReverse:false,
		selected:undefined
	}
	this.constructor(params); // конструктор по умолчанию
	
	// отыскиваем остальные элементы
	this.itemLinks={
		previous:this.itemLink.selectChild('a.previous'),
		next:this.itemLink.selectChild('a.next'),
		list:this.itemLink.selectChild('ul'),
		items:this.itemLink.selectChild('ul').selectChilds('li')
	}
	
	// инит общих значений
	if(this.selected!=undefined)this.select(this.selected);
	this.itemWidth=this.itemLinks.list.selectChild('li').clientWidth;// ширина одного элемента в прокрутке
	if(this.itemLinks.list.style.left=='')this.itemLinks.list.style.left=-this.scrollOffset+'px';
	var _scrollFn=null; // функция скролла. Если нулл - значит не выполняется в данный момент
	var _itemsAmount=this.itemLinks.list.selectChilds('li').length;
	var _itemsVisibly=Math.floor(this.itemLink.clientWidth/this.itemWidth);
	for(var k in this.itemLinks.items){
		//if(this.itemLinks.items[k].getAttribute('data-init'))
		//	this.itemLinks.items[k].data=eval(this.itemLinks.items[k].getAttribute('data-init'));
		this.itemLinks.items[k].index=k;
		if(this.itemLinks.items[k].selectChild('a.selected'))
			this.selected=this.itemLinks.items[k].index;
		this.itemLinks.items[k].selectChild('a').addEvent('click',function(event){
			if(event.currentTarget.parentNode.data)
				event.data=event.currentTarget.parentNode.data;
			for(var k2 in self.itemLinks.items)
				if(self.itemLinks.items[k2].selectNode('a')==event.currentTarget)
					event.index=k2;
			self.handleEvent('itemclick',event);
		});
	}

	this.addEvent('itemclick',function(event){
		//alert('selected item #'+event.index);
		self.select(event.currentTarget.parentNode.index);
	});
	
	
	// прокрутка
	this.itemLink.addEvent('mousewheel',function(event){
		event.preventDefault();
		self.scroll(event.wheelDirect()*(self.scrollReverse?-1:1));
		self.handleEvent('scroll',event);
		self.handleEvent((event.wheelDirect()==-1?'scrollleft':'scrollright'),event);
	});
	this.itemLinks.next.addEvent('mousedown',function(ev){self.scroll(self.scrollReverse?-1:1);});
	this.itemLinks.previous.addEvent('mousedown',function(ev){self.scroll(self.scrollReverse?1:-1);});
}

UI.gallery.prototype=new UI._proto;

// ============================= toolBar =============================

UI.toolBar=function(params){
	var self=this;
	
	/* toolpanel. Arguments:
		
	*/
	this.toolPanel=function(params){
		var self=this;
		
		/* tool. Arguments:
			open
			icon
			caption
			onClick
		*/
		this.tool=function(params){
			var self=this;

			this.createStructure=function(params){
				this.itemLink=new node({
					tagName:'a',
					childNodes:[
						params.icon?{tagName:'img',src:params.icon,alt:'['+params.caption+']',title:params.caption}:'',
						params.open?{tagName:'span',className:'open'}:''
					]
				});
			}
			
			/* constructor */
			this.defaults={}
			this.constructor(params); // конструктор по умолчанию
			if(params.onClick)
				this.itemLink.addEvent('click',params.onClick);
		}
		this.tool.prototype=new UI._proto;
		
		this.addTool=function(params){
			var tool=new self.tool(params);
			self.itemLink.appendChild(tool.itemLink);
			return tool;
		}
		
		this.addSeparator=function(){
			self.itemLink.appendChild(new node({tagName:'span',className:'sep'}));
		}
		
		this.createStructure=function(params){
			this.itemLink=new node({
				tagName:'div',
				className:'toolpanel',
				childNodes:[{tagName:'span',className:'move'}]
			});
		}
		
		/* constructor */
		this.defaults={}
		this.constructor(params); // конструктор по умолчанию
		this.itemLinks={
			move:this.itemLink.selectChild('span.move'),
		}
		this.itemLinks.move.addEvent('click',function(){});//alert('move!');
	}
	this.toolPanel.prototype=new UI._proto;

	this.panelAdd=function(params,tools){
		var panel=new self.toolPanel(params);
		self.itemLink.appendChild(panel.itemLink);
		if(tools)for(var k in tools){
			if(tools[k]=='separator')panel.addSeparator();
			else panel.addTool(tools[k]);
		}
		return panel;
	}
	
	this.createStructure=function(params){
		this.itemLink=new node({
			tagName:'div',
			className:'toolbar'
		});
	}	

	/* constructor */
	this.defaults={}
	this.constructor(params); // конструктор по умолчанию
}

UI.toolBar.prototype=new UI._proto;


// ============================= editBBML =============================

UI.editBBML=function(params){
	var self=this;

	this.createStructure=function(params){
		alert('createStructure editBBML!');
		this.itemLink=new node({
			tagName:'textarea',
		});
	}

	/* constructor */

	this.constructor(params);
	this.objects={
		toolBar:new UI.toolBar()
	}
	
	// функции обработки текста
	var actions={
		bold:function(text){return {text:'<b>'+text+'</b>',start:3,end:3+text.length};},
		italic:function(text){return {text:'<i>'+text+'</i>',start:3,end:3+text.length};},
		underline:function(text){return {text:'<u>'+text+'</u>',start:3,end:3+text.length};},
		strike:function(text){return {text:'<s>'+text+'</s>',start:3,end:3+text.length};},
		variable:function(text){return {text:'<var>'+text+'</var>',start:5,end:5+text.length};},
		link:function(text){
			var newtext=prompt('Вставка ссылки.\nВведите URL (вместе с "http://"):');
			if(newtext){
				var ret1='<a href="'+newtext+'" target="_blank">';
				return {text:ret1+text+'</a>',start:ret1.length,end:ret1.length+text.length};
			}else return {text:text,start:0,end:text.length};
		},
		code:function(text){return {text:'\n<code language="no-highlight"><![CDATA[\n'+text+'\n]]></code>\n',start:41,end:41+text.length};},
		kbd:function(text){return {text:'<kbd>'+text+'</kbd>',start:5,end:5+text.length};},
		off:function(text){return {text:'\n<off text="">\n'+text+'\n</off>\n',start:15,end:15+text.length};},
		cut:function(text){return {text:'\n<cut text=""/>\n',start:15,end:15};},
		quote:function(text){return {text:'\n<quote author="">\n'+text+'\n</quote>\n',start:19,end:19+text.length};},
		escape:function(text){text=php.htmlspecialchars(text);return {text:text,start:0,end:text.length};},
		header:function(text){return {text:'<h2>'+text+'</h2>',start:4,end:4+text.length};},
		sub:function(text){return {text:'<sub>'+text+'</sub>',start:5,end:5+text.length};},
		sup:function(text){return {text:'<sup>'+text+'</sup>',start:5,end:5+text.length};},
		list:function(text,tagName){
			var tag=tagName?tagName:'ul';
			if(text!=''){
				var splitted=text.split('\n');
				for(var i=0;i<splitted.length;i++)
					splitted[i]='\t<li>'+splitted[i]+'</li>';
				var newtext='<'+tag+'>\n'+splitted.join('\n')+'\n</'+tag+'>';
				return {text:newtext,start:0,end:newtext.length};
			}else{
				return {text:'<'+tag+'>\n\t<li></li>\n</'+tag+'>',start:10,end:10};
			}
		},
		listorder:function(text){
			var tagName='ol';
			return actions.list(text,'ol');
		},
		table:function(text){var newtext='\n<table>\n\t<tr>\n\t\t<th></th>\n\t</tr>\n\t'+
			'<tr>\n\t\t<td></td>\n\t</tr>\n</table>\n'; return {text:newtext,start:0,end:(newtext.length-1)};},
		video:function(text){
			var newtext=prompt('Вставка видео.\nПоддерживаются следующие сервисы:'+
				'\n\t- YouTube;\n\t- RuTube;\n\t- Vkontakte;\n\t- Прямая ссылка на *.flv-файл.'+
				'\n\nВведите адрес видео:');
			if(newtext)return {text:'\n<video src="'+newtext+'"/>\n',start:0,end:0};
			else return {text:text,start:0,end:0};
		},
		image:function(text){
			var newtext=prompt('Вставка изображения. Введите URL изображения:');
			if(newtext)return {text:'\n<img src="'+newtext+'"/>\n',start:0,end:0};
			else return {text:text,start:0,end:0};
		}
	}
	
	// toolbar
	this.itemLink.parentNode.insertBefore(this.objects.toolBar.itemLink,this.itemLink);
	this.objects.toolBar.panelAdd({},[
		{
			icon:COMMON_SKINFOLDER+'img/icons/edit-bold.png',
			caption:'Жирный',
			onClick:function(){self.itemLink.processSelected(actions.bold);}
		},{
			icon:COMMON_SKINFOLDER+'img/icons/edit-italic.png',
			caption:'Курсив',
			onClick:function(){self.itemLink.processSelected(actions.italic);}
		},{
			icon:COMMON_SKINFOLDER+'img/icons/edit-underline.png',
			caption:'Подчеркнутый',
			onClick:function(){self.itemLink.processSelected(actions.underline);}
		},{
			icon:COMMON_SKINFOLDER+'img/icons/edit-strike.png',
			caption:'Зачеркнутый',
			onClick:function(){self.itemLink.processSelected(actions.strike);}
		},'separator',{
			icon:COMMON_SKINFOLDER+'img/icons/edit-heading.png',
			caption:'Заголовок',
			open:true,
			onClick:function(){self.itemLink.processSelected(actions.header);}
		},{
			icon:COMMON_SKINFOLDER+'img/icons/edit-superscript.png',
			caption:'Верхний индекс',
			onClick:function(){self.itemLink.processSelected(actions.sup);}
		},{
			icon:COMMON_SKINFOLDER+'img/icons/edit-subscript.png',
			caption:'Нижний индекс',
			onClick:function(){self.itemLink.processSelected(actions.sub);}
		},{
			icon:COMMON_SKINFOLDER+'img/icons/chain.png',
			caption:'Ссылка',
			onClick:function(){self.itemLink.processSelected(actions.link);}
		},
		'separator',{
			icon:COMMON_SKINFOLDER+'img/icons/edit-list.png',
			caption:'Ненумерованный список',
			onClick:function(){self.itemLink.processSelected(actions.list);}
		},{
			icon:COMMON_SKINFOLDER+'img/icons/edit-list-order.png',
			caption:'Нумерованный список',
			onClick:function(){self.itemLink.processSelected(actions.listorder);}
		},'separator',{
			icon:COMMON_SKINFOLDER+'img/icons/edit-code.png',
			caption:'Экранировать HTML-символы',
			onClick:function(){self.itemLink.processSelected(actions.escape);}
		}
	]);
	this.objects.toolBar.panelAdd({},[
		{
			icon:COMMON_SKINFOLDER+'img/icons/edit-number.png',
			caption:'Код',
			onClick:function(){self.itemLink.processSelected(actions.code);}
		},{
			icon:COMMON_SKINFOLDER+'img/icons/edit-quotation.png',
			caption:'Цитата',
			onClick:function(){self.itemLink.processSelected(actions.quote);}
		},{
			icon:COMMON_SKINFOLDER+'img/icons/grid.png',
			caption:'Таблица',
			onClick:function(){self.itemLink.processSelected(actions.table);}
		},{
			icon:COMMON_SKINFOLDER+'img/icons/scissors.png',
			caption:'Спрятать под спойлер',
			onClick:function(){self.itemLink.processSelected(actions.off);}
		},{
			icon:COMMON_SKINFOLDER+'img/icons/cutter.png',
			caption:'Обрезать',
			onClick:function(){self.itemLink.processSelected(actions.cut);}
		}
	]);
	this.objects.toolBar.panelAdd({},[
		{
			icon:COMMON_SKINFOLDER+'img/icons/film.png',
			caption:'Видео',
			onClick:function(){self.itemLink.processSelected(actions.video);}
		},{
			icon:COMMON_SKINFOLDER+'img/icons/image.png',
			caption:'Изображение',
			onClick:function(){self.itemLink.processSelected(actions.image);}
		}
	]);

	// auto expand (not worx in firefox)
	addEvent(this.itemLink,'keyup',this.itemLink.autoExpand);

	// markup hot keys (not worx in opera)
	addEvent(this.itemLink,'keypress',function(event){
		if(event.ctrlKey==true){
			if(php.in_array(event.charCode,[98,105,117,52,51,107,111,113,101]))event.preventDefault();
			if(event.charCode){
				var func={
					98:actions.bold,
					105:actions.italic,
					117:actions.underline,
					52:actions.variable,/*ctrl + 4*/
					51:actions.code,/*ctrl + 3*/
					107:actions.kbd,/*ctrl + k*/
					111:actions.off,/*ctrl + o*/
					113:actions.quote,/*ctrl + q*/
					101:actions.escape/*ctrl + e*/
				}[event.charCode];
			}
		}else{// ctrl not pressed
			if(event.keyCode==9){// tab
				event.preventDefault();
				var func=event.shiftKey?
					function(text){// shift+tab
						if(text!=''){
							var splitted=text.split('\n');
							for(var i=0;i<splitted.length;i++)
								splitted[i]=splitted[i].replace(/^([\t ]{1,1})/,'');
							var newtext=splitted.join('\n');
							return {text:newtext,start:0,end:newtext.length};
						}
					}:function(text){// only tab
						if(text!=''){
							var newtext='\t'+text.split('\n').join('\n\t');
							return {text:newtext,start:0,end:newtext.length};
						}else
							return {text:'\t',start:1,end:1};
					}
			}
		}
		if(func)this.processSelected(func);
	});
}

UI.editBBML.prototype=new UI._proto;


// ============================= grouping =============================

UI.grouping=function(params){
	var self=this;
	
	this.createStructure=function(params){
		self.itemLink=new node({
			tagName:'ul',
			className:'grouping'
		});
	}
	
	/* элемент группировки. Параметры:
		caption
		show
		content
	*/
	this.groupItem=function(params){
		var self=this;
		this.createStructure=function(params){
			self.itemLink=new node({
				tagName:'li',
				childNodes:[
					{tagName:'a',innerHTML:params.caption},
					{tagName:'span',className:params.show?'show':'hide'},
					{tagName:'div',innerHTML:params.content,style:'display:'+(params.show?'block':'none')},
				]
			});
		}
		
		this.toggle=function(show){
			show=show==undefined?!self.show:show;
			self.itemLinks.toggle.className=show?'hide':'show';
			self.itemLinks.content.style.display=show?'block':'none';
			self.show=show;
		}
		
		/* constructor */

		this.defaults={show:false}
		this.constructor(params);
		
		this.itemLinks={
			caption:this.itemLink.selectChild('a'),
			toggle:this.itemLink.selectChild('span'),
			content:this.itemLink.selectChild('div')
		}
		this.caption=this.itemLinks.caption.innerHTML;
		this.toggle(this.show);
		this.itemLinks.toggle.addEvent('click',function(){self.toggle()});
		this.itemLinks.caption.addEvent('click',function(){self.toggle()});
	}
	this.groupItem.prototype=new UI._proto;

	/* constructor */
	this.itemLinks={}
	this.defaults={show:false}
	this.objects={}
	this.constructor(params);
	
	this.itemLinks.list=this.itemLink.selectChilds('li');
	for(var i=0;i<this.itemLinks.list.length;i++){
		var newName=UI.generateName(this.objects,'groupItem',this.itemLinks.list[i]);
		this.objects.groupItem[newName]=new this.groupItem(
			{placeTo:this.itemLinks.list[i],objType:'groupItem',objName:newName,show:this.show});
	}
			

}

UI.grouping.prototype=new UI._proto;


// ============================= menu, abstract class =============================

UI.menu=function(params){
	
	this.createStructure=function(params){
		self.itemLink=new node({
			tagName:'ul',
			className:params.className?params.className:'menu'
		});
	}

	// OLD FUNCS
	this.changeCaption=function(itemIndex,newcap){
		self.menuItems[itemIndex].caption=newcap;
		self.menuItems[itemIndex].objLinks.caption.innerHTML=newcap;
		return true;
	}
	
	this.changeDesc=function(itemIndex,newdesc){
		self.menuItems[itemIndex].desc=newdesc;
		self.menuItems[itemIndex].objLinks.desc.innerHTML=newdesc;
		return true;
	}
	
	this.changeIcon=function(itemIndex,newsrc){
		self.menuItems[itemIndex].icon=newsrc;
		self.menuItems[itemIndex].objLinks.icon.src=newsrc;
		return true;
	}
	
	this.activateItem=function(itemIndex,isActive){
		self.menuItems[itemIndex].active=isActive;
		self.menuItems[itemIndex].objLinks.a.className=self.stylePrefix+(isActive?'_active':'_caption')
		return true;
	}
	
	// сворачивалка субменю.
	this.collapse=function(itemIndex,collapse){
		// collapse=true - свернуть, collapse=false - развернуть.
		self.menuItems[itemIndex].collapsed=collapse;
		if(self.menuItems[itemIndex].isDir){
			self.menuItems[itemIndex].objLinks.childNodes.style.display=collapse?'none':'block';
			self.menuItems[itemIndex].objLinks.collapser.className=
				self.stylePrefix+(collapse?'_collapsed':'_uncollapsed');
			return !self.menuItems[itemIndex].isEmpty;
		}else return false;
	}

	this.deactivate=function(){
		self.isActive=false;
		for(var i=0;i<self.menuItems.length;i++){
			self.activateItem(i,false);
		}
	}
	
	this.activate=function(item){
		self.isActive=true;
		self.activeItem=item;
		for(var i=0;i<self.menuItems.length;i++){
			self.activateItem(i,self.activeItem==i);
		}
	}

	// NEW FUNCS
	
	this.menuItem=function(params){ // abstract class
		this.createStructure=function(params){
			self.itemLink=new node({
				tagName:'li',
			});
		}
	}
	this.menuItem.prototype=new UI._proto;

}

UI.menu.prototype=new UI._proto;


// ============================= tree, extends menu =============================

/* Определиться с английским переводом терминов:
	сворачивалка (плюсик-минусик)		toggler
	свернуть							collapse
	развернуть							expand
	свернуть/развернуть					toggle
	свернутость (статус)				show

*/
UI.tree=function(params){
	var self=this;
	
	this.menuItem=function(params){ // abstract class
		var self=this;
		
		this.createStructure=function(params){
			self.itemLink=new node({
				tagName:'li',
				childNodes:[
					{
						tagName:'img',
						src:params.icon,
					},{
						tagName:'a',
						href:params.url,
						innerHTML:params.caption
					},(params.desc?{
						tagName:'small',
						innerHTML:params.desc
					}:''),(params.isDir?{
						tagName:'span',
						className:params.show?'hide':'show',
						style:params.amount==0?'display:none':''
					}:''),(params.isDir?{
						tagName:'div',
						style:params.show?'':'display:none',
						innerHTML:params.childNodes?params.childNodes:''
					}:'')
				]
			});
		}
		
		this.toggle=function(){
			self.show=!self.show;
			self.itemLinks.toggler.className=self.show?'hide':'show';
			if(self.itemLinks.container)
				self.itemLinks.container.style.display=self.show?'block':'none';
			self.handleEvent('toggle',{object:self});
			self.handleEvent(self.show?'expand':'collapse',{object:self});
		}

		/* constructor */
		this.events={
			expand:[],			// при разворачивании
			collapse:[],		// при сворачивании
			toggle:[],			// при нажатии разворачивании/сворачивании
			itemclick:[],		// при клике на пункт
			itemdblclick:[],	// при двойном клике на пункт
			keypress:[],		// при нажатии на клавишу когда меню активно
			activate:[],		// при активировании пункта
			deactivate:[],		// при деактивировании пункта
		}
		this.defaults={show:false}
		this.objects={}
		this.constructor(params);
		var _isdir=this.itemLink.selectChild('div')!=undefined;
		var _showstatus=_isdir?(this.itemLink.selectChild('div').style.display!='none'):false;
		this.itemLinks={
			icon:this.itemLink.selectChild('img'),
			toggler:(this.itemLink.selectChild('span.show') || this.itemLink.selectChild('span.hide')),
			link:this.itemLink.selectChild('a'),
			desc:this.itemLink.selectChild('span.desc'),
			container:this.itemLink.selectChild('div'),
		}
		this.icon=this.itemLinks.icon.src;
		this.isDir=_isdir;
		this.show=_showstatus;
		this.caption=this.itemLinks.link.innerHTML;
		this.url=this.itemLinks.link.href;
		
		// add events
		if(this.itemLinks.toggler)
			this.itemLinks.toggler.addEvent('click',this.toggle);

	}
	this.menuItem.prototype=new UI._proto;
		//UI.menu.menuItem;


	this.createStructure=function(params){
		self.itemLink=new node({
			tagName:'ul',
			className:'tree'
		});
	}


	/* constructor */
	this.events={
		expand:[],			// при разворачивании любого элемента
		collapse:[],		// при сворачивании любого элемента
		toggle:[],			// при нажатии разворачивании/сворачивании любого элемента
		itemclick:[],		// при клике на любой пункт
		itemdblclick:[],	// при двойном клике на любой пункт
		keypress:[],		// при нажатии на клавишу когда меню активно
		activate:[],		// при активировании дерева
		deactivate:[],		// при деактивировании дерева
	}
	this.defaults={show:false}
	this.objects={
		items:[]
	}
	this.constructor(params);
	this.itemLinks={
		items:[]
	}

	if(params.menuItems){
		for(var k in params.menuItems){
			var _ik=this.objects.items.length;
			this.objects.items[_ik]=new this.menuItem(params.menuItems[k]);
			this.itemLink.appendChild(this.objects.items[_ik].itemLink);
			this.objects.items[_ik].addEvent('expand',function(event){
				self.handleEvent('expand',event);
			});
		}
	}else{
		var _items=this.itemLink.selectChilds('li');
		for(var k in _items){
			var _initdata=_items[k].getAttribute('data-init')?eval('('+_items[k].getAttribute('data-init')+')'):{};
			_initdata.placeTo=_items[k];
			var _ik=this.objects.items.length;
			this.objects.items[_ik]=new this.menuItem(_initdata);
			this.objects.items[_ik].addEvent('expand',function(event){
				self.handleEvent('expand',event);
			});
		}
	}
}

UI.tree.prototype=new UI.menu; // class tree extends menu



// ============================= box =============================
/*
UI.box=function(params){
	var self=this;
	this.createStructure=function(params){
		self.itemLink=new node({
			tagName:'li',
		});
	}
	
	// constructor
	this.events={}
	this.defaults={}
	this.objects={}
	this.itemLinks={}
	this.constructor(params);
	
}

UI.box.prototype=new UI._proto;
*/

UI.box=newClass(UI._proto,{
	constructor:function(params){
		this.constructor.prototype.constructor.call(this,params);
		var self=this;
		this.events={}
		this.defaults={}
		this.objects={}
		this.itemLinks={}
		this.constructor(params);
		//alert('UI.box constructor! '+this.constructor.prototype.constructor);//+this.objType
	}
});










