var	_TBL_ACT_ADD_ = 0x01,
	_TBL_ACT_EDT_ = 0x02,
	_TBL_ACT_DEL_ = 0x03,
	_TBL_ACT_MOVE_UP_ = 0x08,
	_TBL_ACT_MOVE_DOWN_ = 0x09,
	_TBL_ACT_LEVEL_UP_ = 0x0A,
	_TBL_ACT_LEVEL_DOWN_ = 0x0B;

var CSrvConnect = Class.create();
CSrvConnect.prototype = {
	initialize: function(container, root, url, isJson, options) {
		this.root = root;
		this.container = container;
		this.cnt = $(container);
		this.url = url;
		this.isJson = isJson==true;
		this.options = { 'showOkMessage':true, 'showErrMessage':true, 'gotoMsgOnErr':true };
		if(typeof(options)!='undefined') {
			if(typeof(options['showOkMessage'])!='undefined') this.options['showOkMessage'] = options['showOkMessage'];
			if(typeof(options['gotoMsgOnOk'])!='undefined') this.options['gotoMsgOnOk'] = options['gotoMsgOnOk'];
			if(typeof(options['showErrMessage'])!='undefined') this.options['showErrMessage'] = options['showErrMessage'];
			if(typeof(options['gotoMsgOnErr'])!='undefined') this.options['gotoMsgOnErr'] = options['gotoMsgOnErr'];
			if(typeof(options['loadContentInContainer'])!='undefined') this.isLoadContentInContainer = options['loadContentInContainer'];
		}
	},
	
	load: function(params, async){
		this.params = params;
		var url = this.url[1]=='/'? this.url : this.root+this.url;
		
		if(typeof(async)=='undefined') async = false;
		if(this.showHideOnLoad) this.cnt.show();

		new Ajax.Request(url, {
			method: 'post',
			asynchronous: async,
			parameters: params,
			onLoading: function(obj) {
				return function(){
					obj.loadStatus(_t('loading'));
				}
			}(this),
			onSuccess: function(obj) {
				return function(t){
					obj.parseResult(t);
				}
			}(this),
			onFailure: function(obj) {
				return function() {
					obj.loadStatus(_t('server_connection_failure'), 'load-error');
				}
			}(this)
		});
	},//---------------------------------------------------------------------
	
	loadStatus: function(str, className) {
		this.cnt.update();
		if(!className) className = 'loading';
		this.cnt.appendChild( crElem('div', { 'class': className }, '', [crElem('p', {}, '', str), crElem('img', {'src':'/img/loader.white.gif'}, '', '')] ) );
		this.insertRefreshButton();
	},//---------------------------------------------------------------------
	
	parseResult: function(t) {
		try { this.onLoad && this.onLoad(t); }
		catch(e) {}
		
		if(this.isJson) {
			this.cnt.update();
			this.cnt.appendChild( crElem('div', { 'class': 'loading' }, '', [crElem('p', {}, '', _t('answer_processing'))] ) );

			var json;
			try { json = eval('(' + t.responseText + ')'); }
			catch(e) { this.cnt.update('<div class="msg-err">' + _t('error') + '</div>'+t.responseText); }

			if(json.status) {// Операция выполнена успешно
				if (json.message && this.options['showOkMessage']) {
					this.cnt.update('<div class="msg-ok">' + json.message + '</div>');
					if(this.options['gotoMsgOnOk'] && this.cnt.id) document.location = '#' + this.cnt.id;
				}
				else this.cnt.update();
				this.onJsonDone && this.onJsonDone(json);
				if(this.clearMsgTimer!=null) window.clearTimeout(this.clearMsgTimer);
				this.clearMsgTimer = window.setTimeout( function(obj){
					return function(){
						obj.clearMsg();
					}
				}(this), this.clearMsgTimeout);
			}
			else {// Ошибка
				if(this.options['showErrMessage']) {
					this.cnt.update();
					var elem,
						div = this.cnt.appendChild( elem = crElem('div', { 'class': 'msg-err' }, '', [crElem('b',null,null, _t('error_'))]) );
					elem.innerHTML += json.error.message;
					if(this.options['gotoMsgOnErr'] && this.cnt.id) document.location = '#' + this.cnt.id;
				}
				this.onJsonError && this.onJsonError(json);
			}
		}
		else if(this.isLoadContentInContainer) this.cnt.innerHTML = t.responseText;
	},//---------------------------------------------------------------------
	
	// Добавление кнопки "обновить" в контент. Используется при ошибках соединения и парсинга ответа 
	insertRefreshButton: function(){
		var btn;
		this.cnt.appendChild( btn = crElem('div', {'class':'buttons'}, '', [crElem('a', { 'href':'#', 'class': 'link-update' }, '', _t('repeat_request'))] ) );
		Event.observe(btn, 'click', function(obj){
			return function(event){
				obj.load(obj.params);
				Event.stop(event);
				return false;
			}
		}(this) );
	},//---------------------------------------------------------------------
	
	params: null,	// параметры используемые при запросе
	onLoad: null,	// функция выполняемая после загрузки контента
	onJsonDone: null,
	onJsonError: null,
	isJson: false,
	options: null,
	isLoadContentInContainer: false,	// загруженное содержимое будет помещено в контейнер cnt (container)
	clearMsgTimeout: 5000,
	clearMsgTimer: null,
	clearMsg: function() {
		this.cnt.update();
		this.clearMsgTimer = null;
		if(this.showHideOnLoad) this.cnt.hide();
	},//---------------------------------------------------------------------
	showHideOnLoad: false
};
/////////////////////////////////////////////////////////////////////////////


/////////////////////////////////////////////////////////////////////////////
////////////////////////////  С п и с о к  //////////////////////////////////
var CSrvList = Class.create();
CSrvList.prototype = {
	initialize: function(content, positionsType) {
		this.content = content;
		this.onLoad = this.setEvents;
		if(!positionsType || positionsType=='tr') this.createAdditionalPosition = this.createAddPosAsTableRow;
		else if(positionsType=='div') this.createAdditionalPosition = this.createAddPosAsDiv;
	},//---------------------------------------------------------------------
	
	///////////  Устанавливает события после загрузки контента  /////////////
	setEvents: function(t) {
		if(t) this.cnt.innerHTML = t.responseText;
		
		// ----------------------  A d d  R e c o r d  ----------------------
		this.cntAdd = $(this.content+'AddLayer');
		this.cntTable = $(this.content+'TableLayer');
		this.btnAdd = $(this.content+'AddBtn');
		
		if(this.btnAdd && !this.btnAdd.getAttribute('event')) {
			if(this.connAdd!=null) delete this.connAdd;
			if(this.cntAdd && this.btnAdd) {
				this.connAdd = Object.extend(new CSrvConnect(this.cntAdd, this.root+this.addRecPostfix, this.btnAdd.getAttribute('URL')), new CSrvAddEdt(this.content, 'process/', '', this.content+'AddLayer') );
				this.connAdd.onRecordAdded = function(obj){ // обновление таблицы
					return function(){
						obj.refreshTable();
					}
				}(this);
				if(this.onFormLoaded) this.connAdd.onFormLoaded = this.onFormLoaded;

				// Добавление новой записи - кнопка, onClick
				Event.observe(this.btnAdd, 'click', function(obj){
					return function() {
						if(obj.cntAdd.visible()) obj.cntAdd.hide();
						else {
							obj.cntAdd.show();
							if( obj.cntAdd.innerHTML=='' ) obj.connAdd.load();
						}
						return false;
					}
				}(this) );
			}// Add record [End]
			
			this.btnAdd.setAttribute('event', true);
		}
		
		if(!this.cnt.getAttribute('event')) {
			this.connRow = {};
			this.connEdt = {};
			this.cnt.setAttribute('event', true);
		}
		
		var obj = this;
		// ---------------------  Additional Info  ---------------------
		// Кнопки редактирования данных записи
		$(this.container).getElementsBySelector('.btn_info').each( function(elem){
			if(!elem.getAttribute('event')) obj.setInfoEvents(elem);
			elem.setAttribute('event', true);
		} );
		// Edit Record [End]
		
		// ---------------------  E d i t  R e c o r d  ---------------------
		// Кнопки редактирования данных записи
		$(this.container).getElementsBySelector('.btn_edt').each( function(elem){
			if(!elem.getAttribute('event')) obj.setEdtEvents(elem);
			elem.setAttribute('event', true);
		} );
		// Edit Record [End]
		
		// -------------------  D e l e t e  R e c o r d  -------------------
		$(this.container).getElementsBySelector('.btn_del').each( function(elem){
			if(!elem.getAttribute('event'))	Event.observe( elem, 'click', function(event){
				if(!confirm(_t('delete_record_confirmation'))) {
					Event.stop(event);
					return false;
				}
				var indx = elem.id.split('-')[1];
				if (obj.connDel == null) {
					obj.connDel = Object.extend(new CSrvConnect(obj.content + 'Msg', obj.root + 'process/', obj.url), new CSrvDel(obj.content));
					if(obj.connDel) obj.connDel.onDeleteSuccess = obj.onDeleteSuccess;
				}
				obj.connDel.doDelete(indx, elem.name);
				Event.stop(event);
				return false;
			} );
			elem.setAttribute('event', true);
		} );
		
		// --------------------  M o v e  U p / D o w n  --------------------
		$(this.container).getElementsBySelector('.btn_move').each( function(elem){
			if(!elem.getAttribute('event'))	Event.observe( elem, 'click', function(event){
				if(obj.connMove==null) {
					obj.connMove = new CSrvConnect(obj.content+'Msg', obj.root+obj.edtRecPostfix+'process/', obj.url, true);
					obj.connMove.onLoad = function(){
						obj.refreshTable();
					};
				}
				obj.connMove.load( elem.name );
				Event.stop(event);
				return false;
			} );
			elem.setAttribute('event', true);
		} );
		// Edit Record [End]
		
		//------------------  P a g e  N a v i g a t i o n  -----------------
		$(this.container).getElementsBySelector('.page-nav a').each( function(elem){
			if(!elem.getAttribute('event')) Event.observe( elem, 'click', function(event){
				var page = this.id.split('-')[1];
				if(page=='x') return false;
				obj.pageN = page;
				obj.refreshTable();
				return false;
			} );
			elem.setAttribute('event', true);
		} );
		
		//-----------------  S e t  o r d e r  c o l u m n  -----------------
		$(this.container).getElementsBySelector('th a.order').each( function(elem){
			if(!elem.getAttribute('event')) Event.observe( elem, 'click', function(event){
				var order = this.id.split('-')[1];
				obj.refreshTable( {'order':order} );
				return false;
			} );
			elem.setAttribute('event', true);
		} );
		
		if(this.cntTmp) { // Restore content container
			this.cnt = this.cntTmp;
			this.cntTmp = null;
		}
		
		if(this.onListRefresh) {
			if(typeof(this.onListRefresh)=='function') this.onListRefresh();
			else {
				var i;
				for(i=0; i<this.onListRefresh.length; i++) {
					this.onListRefresh[i]();
				}
			}
		}
	},//- setEvents ---------------------------------------------------------
	
	// Кнопка редактирования и обновление содержимого строки
	setEdtEvents: function(elem) {
		var indx = elem.id.split('-')[1],
			obj = this;
		// Создание коннектора для каждой из строк (конектор создается только для редактирования т.к. для удаления он не нужен)
		var rowLayerName = this.content+'RowLayer-'+indx,
			edtLayerName = this.content+'EdtLayer-'+indx,
			edtRowName = this.content+'EdtRow-'+indx;
		this.connRow['rec-'+indx] = new CSrvConnect(rowLayerName, this.root+this.rowPostfix, this.url);
		// Операции выполняемые после перезагрузки строки
		this.connRow['rec-'+indx].onLoad = function(t) {
			// подменяем собственно строку
			new Insertion.After(this.cnt, t.responseText);
			this.cnt.parentNode.removeChild( this.cnt );
			obj.setEvents();
		};

		// Редактирование записи - кнопка, onClick
		Event.observe(elem, 'click', function(obj){
			return function(event) {
				var edtRow = $(edtRowName), edtLayer;
				// добавление строки ниже для загрузки в неё формы редактирования
				if(!edtRow) {
					var infoRow = $(obj.content+'InfoRow-'+indx),
						rowLayer = $(rowLayerName),
						next;
					edtRow = obj.createAdditionalPosition(edtRowName, edtLayerName, false, rowLayer);
					// Если есть строка дополнительной информации - форму редактирования располагаем ниже
					if(infoRow) rowLayer = infoRow;
					next = rowLayer.nextSibling;
					if(next) rowLayer.parentNode.insertBefore(edtRow, next);
					else rowLayer.parentNode.appendChild(edtRow);

					edtLayer = $(edtLayerName);
					obj.connEdt['rec-'+indx] = Object.extend(new CSrvConnect(edtLayerName, obj.root+obj.edtRecPostfix, elem.name), new CSrvAddEdt(obj.content, 'process/', indx, obj.container) );
					obj.connEdt['rec-'+indx].connRow = obj.connRow;
					obj.connEdt['rec-'+indx].connInfo = obj.connInfo;
					if(obj.onFormLoaded) obj.connEdt['rec-'+indx].onFormLoaded = obj.onFormLoaded;
				} else edtLayer = $(edtLayerName);

				// Спрятать/показать форму редактирования. Загрузка формы
				if(edtRow.visible()) edtRow.hide();
				else {
					edtRow.show();
					if( edtLayer.innerHTML=='' ) obj.connEdt['rec-'+indx].load();
				}
				obj.doAutocloseExts(indx);
				obj.activeComponents['edtRow'] = edtRow;
				Event.stop(event);
				return false;
			}
		}(this) );
	},//- setEdtEvents ------------------------------------------------------
	
	// Кнопка просмотра дополнительной информации
	setInfoEvents: function(elem){
		var indx = elem.id.split('-')[1],
			obj = this;
		// Создание коннектора для каждой из строк (конектор создается только для редактирования т.к. для удаления он не нужен)
		var rowLayerName = this.content+'RowLayer-'+indx,
			infoLayerName = this.content+'InfoLayer-'+indx,
			infoRowName = this.content+'InfoRow-'+indx;

		// Кнопка дополнительной информации
		Event.observe(elem, 'click', function(obj){
			return function(event) {
				var infoRow = $(infoRowName), infoLayer;
				// добавление строки ниже для загрузки в неё формы редактирования
				if(!infoRow) {
					var rowLayer = $(rowLayerName), next = rowLayer.nextSibling;
					infoRow = crElem('tr', {'id':infoRowName}, {'display':'none'}, '');
					infoRow.appendChild( 
						crElem('td', {'colSpan':rowLayer.cells.length, 'class':'open-box'}, '',  
							[crElem('div', {'id':infoLayerName}, '', '')] )
					);
					if(next) rowLayer.parentNode.insertBefore(infoRow, next);
					else rowLayer.parentNode.appendChild(infoRow);

					infoLayer = $(infoLayerName);
					obj.connInfo['rec-'+indx] = new CSrvConnect(infoLayerName, obj.root, elem.getAttribute('URL'));
					obj.connInfo['rec-'+indx].onLoad = function(t){
						if(t) this.cnt.innerHTML = t.responseText;
					};
				} else infoLayer = $(infoLayerName);

				// Спрятать/показать форму редактирования. Загрузка формы
				if(infoRow.visible()) infoRow.hide();
				else {
					infoRow.show();
					if(infoLayer.innerHTML=='') obj.connInfo['rec-'+indx].load();
				}
				obj.doAutocloseExts(indx);
				obj.activeComponents['infoRow'] = infoRow;
				Event.stop(event);
				return false;
			}
		}(this) );
	},//- setExtViewEvents --------------------------------------------------
	
	refreshTable: function(addParams, all){
		var params = {'page':this.pageN};
		if(!all) { // Если all задано - обновить не только таблицу но и форму добавления - всё
			this.cntTmp = this.cnt;
			this.cnt = this.cntTable;
			params['tblOnly'] = 1;
		}
		
		if(addParams) params = Object.extend( params, addParams );
		this.load( params );
	},//- refreshTable ------------------------------------------------------
	
	//-----------------------------------------------------------------------
	createAdditionalPosition: null,
	createAddPosAsTableRow: function(addRowId, addLayerId, addRowVisible, rowLayer) {
		var additionalRow = crElem('tr', {'id':addRowId}, (addRowVisible? {}:{'display':'none'}), '');
		additionalRow.appendChild( 
			crElem('td', {'colSpan':rowLayer.cells.length, 'class':'open-box'}, '', 
				[crElem('div', {'id':addLayerId}, '', '')] )
		);
		return additionalRow;
	},//---------------------------------------------------------------------
	createAddPosAsDiv: function(addRowId, addLayerId, addRowVisible, rowLayer) {
		var additionalDiv = crElem('div', {'id':addRowId}, (addRowVisible? {}:{'display':'none'}), '');
		additionalDiv.appendChild( crElem('div', {'id':addLayerId}, '', '')	);
		return additionalDiv;
	},//---------------------------------------------------------------------
	
	doAutocloseExts: function(id) {
		if(this.activeComponents['id']==id) return;
		if(this.activeComponents['infoRow']) {
			this.activeComponents['infoRow'].hide();
			this.activeComponents['infoRow'] = null;
		}
		if(this.activeComponents['edtRow']) {
			this.activeComponents['edtRow'].hide();
			this.activeComponents['edtRow'] = null;
		}
		this.activeComponents['id'] = id;
	},//---------------------------------------------------------------------
	
	rowPostfix: 'row/',
	addRecPostfix: '',
	edtRecPostfix: '',
	cntAdd: null,		// слой для формы добавления
	cntTable: null,		// слой для таблицы
	cntTmp: null,
	connAdd: null,		// коннектор для добавления
	connTable: null,	// коннектор для таблицы
	connRow: {},		// коннекторы для каждой из строк { 'rec-{id}':{conn}, 'rec-{id}':{conn} }
	connEdt: {},		// коннекторы редактирования для каждой из строк { 'rec-{id}':{conn}, 'rec-{id}':{conn} }
	connInfo: {},		// коннекторы дополнительной информации для каждой из строк { 'rec-{id}':{conn}, 'rec-{id}':{conn} }
	connDel: null,		// коннектор для удаления записей
	connMove: null,		// коннектор для перемещения записи вверх/вниз
	autocloseExts: true,	// автоматически закрывать поля типа "extended_view", "edit form" при открытии другого
	activeComponents: { id:0, infoRow:null, edtRow:null },
	onListRefresh: [],	// обработчик исполняемый после обновления списка
	onFormLoaded: null,
	onDeleteSuccess: null,
	pageN: 0			// номер страницы отображаемой в данный момент
};
////////////////////////////  С п и с о к  //////////////////////////////////
/////////////////////////////////////////////////////////////////////////////


/////////////////////////////////////////////////////////////////////////////
//////  Ф о р м а  д о б а в л е н и я / р е д а к т и р о в а н и я  ///////
var CSrvAddEdt = Class.create();
CSrvAddEdt.prototype = {
	initialize: function(content, subUrl, recId, container) {
		this.content = content;
		this.subUrl = subUrl;
		this.recId = recId;
		this.container = container;
		this.onLoad = this.setEvents;
	},//---------------------------------------------------------------------
	
	// Устанавливает события после загрузки контента
	setEvents: function(t) {
		if(t) this.cnt.innerHTML = t.responseText;
		
		var obj = this;
		this.form = $(this.content+'Form-'+this.recId);
		this.btnApply = $(this.content+'ApplyBtn-'+this.recId);
		this.btnReset = $(this.content+'ResetBtn-'+this.recId);
		this.msg = $(this.content+'Msg-'+this.recId);
		
		// ----------------  ApplyBtn - кнопка "Применить"  -----------------
		if(this.btnApply) Event.observe(this.btnApply, 'click', function(obj){
			return function() {
				obj.applyData();
				return false;
			}
		}(this) );
		// ----------------  ResetBtn - кнопка "Очистить"  -----------------
		if(this.btnReset) Event.observe(this.btnReset, 'click', function(obj){
			return function() {
				obj.form.reset();
				return false;
			}
		}(this) );
		
		// --------------------  U p l o a d  i m a g e  --------------------
		obj.connImg = {};
		$(this.container).getElementsBySelector('.btn_img_upload').each( function(elem){
			var arr = elem.id.split('-'),
				indx = arr[1],
				col = arr[2];
			obj.connImg[col] = new CImgUpload(indx, col);
			
			Event.observe( elem, 'click', function(){
				var arr = elem.id.split('-'),
					indx = arr[1],
					col = arr[2];
				obj.connImg[col].upload();
			} );
		} );
		
		// ---------------------  U p l o a d  f i l e  ---------------------
		obj.connFile = {};
		$(this.container).getElementsBySelector('.btn_file_upload').each( function(elem){
			var arr = elem.id.split('-'),
				indx = arr[1],
				col = arr[2];
			obj.connFile[col] = new CFileUpload(indx, col);
			
			Event.observe( elem, 'click', function(){
				var arr = elem.id.split('-'),
					indx = arr[1],
					col = arr[2];
				obj.connFile[col].upload();
			} );
		} );
		
		// Обработчики на зависимые вып. списки
		$(this.content+'Form-'+this.recId).getElementsBySelector('.relation').each( function(elem){
			var i, N,
				res = elem.getAttribute('relation_elems').split('|'),
				func;
			for(i=0, N=res.length; i<N; i++) {
				Event.observe(elem, 'change', func = function(obj, dst, elem){
					return function() {
						var dstName = $(dst).name;
						var params = {'cont':obj.content, 'row_id':obj.recId, 'dstName':dstName};
						params[elem.name] = $F(elem);
						params[dstName] = $F(dst);
						new Ajax.Updater($(dst).parentNode, '/srv/dropdown/', {parameters: params } );
					}
				}(obj, res[i], elem) );
				func();
			}
		} );
		
		// Enable tinyMCE textareas
		if(typeof(tinyMCE)!='undefined') {
			$(this.content+'Form-'+this.recId).getElementsBySelector('.txt-tiny').each( function(elem){
				tinyMCE.execCommand('mceAddControl', false, elem.id);
			} );
		}
		
		if(this.onFormLoaded) this.onFormLoaded(this);
	},//---------------------------------------------------------------------
	
	applyData: function() {
		var i, N, params, paramsTranslated,
			addParams = [];
		if(!this.form) this.form = $(this.content+'Form-'+this.recId);
		// Clear previously markers
		this.clearMarkers();
		if(this.errFieldRow) this.errFieldRow.className = '';
		if(this.errFieldCell) this.errFieldCell.className = 'caption';

		if(this.onBeforeApply) {
			if(!this.onBeforeApply()) return false;
		}

		// Параметры, переданные на форму при её вызове
		//paramsTranslated = eval('(' + this.form.params.value + ')');
		if(typeof(tinyMCE)!='undefined') addParams = this.form.getElementsBySelector('.txt-tiny');
		for(i=0, N=addParams.size(); i<N; i++) {
			addParams[i].value = tinyMCE.getInstanceById( addParams[i].id ).getContent();
			addParams[i].show();
		}
		//if(paramsTranslated) params = Object.extend( paramsTranslated, this.form.serialize() );
		params = this.form.serialize();
		for(i=0, N=addParams.size(); i<N; i++) addParams[i].hide();

		new Ajax.Request(this.root+this.subUrl, {
			method: 'post',
			parameters: params,
			onLoading: function(obj) {
				return function(){
					obj.msg.update();
					obj.msg.appendChild( crElem('div', { 'class': 'loading' }, '', [crElem('p', {}, '', _t('loading'))] ) );
				}
			}(this),
			onLoaded: function(obj) {
				return function(){
					obj.msg.update();
					obj.msg.appendChild( crElem('div', { 'class': 'loading' }, '', [crElem('p', {}, '', _t('loading'))] ) );
				}
			}(this),
			onSuccess: function(obj) {
				return function(t){
					obj.parseSrvAnswer(t);
				}
			}(this),
			onFailure: function(obj) {
				return function(){
					obj.msg.update();
					obj.msg.appendChild( crElem('div', { 'class': 'loading' }, '', [crElem('p', {}, '', _t('server_connection_failure'))] ) );
				}
			}(this)
		});
	},//---------------------------------------------------------------------
	
	parseSrvAnswer: function(t) {
		this.msg.update();
		this.msg.appendChild( crElem('div', { 'class': 'loading' }, '', [crElem('p', {}, '', _t('answer_processing'))] ) );
		var json;
		try {
			json = eval('(' + t.responseText + ')');
		}
		catch(e) {
			this.msg.update('<div class="msg-err">' + _t('error') + '</div>' + t.responseText);
		}

		if(json.status) // Операция выполнена успешно
		{
			this.msg.update('<div class="msg-ok">'+json.message+'</div>');
			if(this.form.btnReset && this.form.action.value=="1"/*add new record*/)
			{
				this.form.reset();
				try {
					if(this.form.btnReset.onclick) this.form.btnReset.onclick();
				}
				catch (e) {}

				// Clear the tinyMCE fields
				var mceFields = this.form.getElementsBySelector(' .mceEditorContainer');
				for(i=0, N=mceFields.size(); i<N; i++) {
					tinyMCE.getInstanceById( mceFields[i].previousSibling.id ).setHTML('');
				}
				// Clear the images fields if it exist
				this.cnt.getElementsBySelector('.images_info').each( function(elem){ elem.innerHTML = ''; } );
				this.cnt.getElementsBySelector('.images_list').each( function(elem){ elem.innerHTML = ''; } );
				// Clear the files fields if it exist
				this.cnt.getElementsBySelector('.files_info').each( function(elem){ elem.innerHTML = ''; } );
				this.cnt.getElementsBySelector('.files_list').each( function(elem){ elem.innerHTML = ''; } );
			}
			if(this.clearMsgTimer!=null) window.clearTimeout(this.clearMsgTimer);
			this.clearMsgTimer = window.setTimeout( function(obj){
				return function(){
					obj.clearMsg();
				}
			}(this), 5000);
			try {
				// Перезагрузка строки в таблице
				if(this.connRow) this.connRow['rec-'+this.recId].load( {'row_id':this.recId} );
				// Если есть доп. информация обновляем и её
				if(this.connInfo && this.connInfo['rec-'+this.recId]) this.connInfo['rec-'+this.recId].load( {'row_id':this.recId} );
			
				if(this.onRecordAdded) this.onRecordAdded();
			}
			catch(e) {}
			if(this.onDataApplySuccess) this.onDataApplySuccess(json);
		}
		else // Ошибка
		{
			this.msg.update();
			var elem,
				div = this.msg.appendChild( elem = crElem('div', { 'class': 'msg-err' }, '', [crElem('b',null,null,_t('error_'))]) );
			elem.innerHTML += json.error.message;

			if(json.error.field) {
				this.errFieldRow = $(json.error.field + '-field_row-' + this.recId);
				this.errFieldCell = $(json.error.field + '-field_cell-' + this.recId);
				if(this.errFieldRow) this.errFieldRow.className = 'error';
				if(this.errFieldCell) this.errFieldCell.className = 'caption td-error';
			}
			if(json.errorList)
			{
				var i, N, elem, wraper;
				for(i=0, N=json.errorList.length; i<N; i++)
				{
					if(json.errorList[i].text) div.appendChild( crElem('div', null, null, json.errorList[i].text) );

					elem = $(json.errorList[i].fname);
					if(elem) {
						wraper = crElem('div', {'class':'marker'}, {'width':elem.getWidth()+'px'}, null);
						elem.wrap( wraper );
					}
				}
			}
			if(this.onDataApplyError) this.onDataApplyError(json);
		}
	},//---------------------------------------------------------------------
	
	clearMarkers: function(){
		if(!this.form) return false;
		var i, N, elems = this.form.getElementsByClassName('marker');
		for(N=elems.length, i=N-1; i>=0; i--) {
			elems[i].childNodes[0].unwrap('div', 'marker');
		}
	},//---------------------------------------------------------------------
	
	clearMsg: function() {
		this.msg.update();
		this.clearMsgTimer = null;
	},//---------------------------------------------------------------------
	
	container: null,
	form: null,		// form dom object
	connImg: {},	// коннекторы для загрузки изображений { '{column}':{conn}, '{column}':{conn} }
	connFile: {},	// коннекторы для загрузки файлов { '{column}':{conn}, '{column}':{conn} }
	connRow: null,	// передается из CSrvList, служит для обновления исходной строки
	msg: null,
	clearMsgTimer: null,
	onFormLoaded: null,
	onRecordAdded: null,	// обычно устанавливается из CSrvList, перегружает список после добавления записи
	onBeforeApply: null,	// use for data checking, preparing or preprocessing
	onDataApplySuccess: null,
	onDataApplyError: null,
	errFieldRow: null,
	errFieldCell: null
};
//////  Ф о р м а  д о б а в л е н и я / р е д а к т и р о в а н и я  ///////
/////////////////////////////////////////////////////////////////////////////


/////////////////////////////////////////////////////////////////////////////
///////////////////  У д а л е н и е  з а п и с и  //////////////////////////
var CSrvDel = Class.create();
CSrvDel.prototype = {
	initialize: function(content) {
		this.content = content;
		this.onLoad = this.parseSrvAnswer;
		
		this.msg = $(this.content+'Msg');
	},
	
	// запрос удаления
	doDelete: function(indx, url) {
		this.indx = indx;
		this.rowLayer = $(this.content+'RowLayer-'+indx),
		this.addInfoRow = $(this.content+'InfoRow-'+indx),
		this.edtRow = $(this.content+'EdtRow-'+indx),
		this.load( url );
	},//---------------------------------------------------------------------
	
	// Устанавливает события после загрузки контента
	parseSrvAnswer: function(t) {
		this.msg.update();
		this.msg.appendChild( crElem('div', { 'class': 'notice' }, '', _t('answer_processing')) );
		
		var json;
		try {
			json = eval('(' + t.responseText + ')');
		}
		catch(e) {
			this.msg.update('<div class="msg-err">' + _t('error') + '</div>' + t.responseText);
		}

		if(json.status) // Операция выполнена успешно
		{
			this.msg.update('<div class="msg-ok">'+json.message+'</div>');
			this.rowLayer.remove();
			if(this.addInfoRow) this.addInfoRow.remove();
			if(this.edtRow) this.edtRow.remove();
			if(this.clearMsgTimer!=null) window.clearTimeout(this.clearMsgTimer);
			this.clearMsgTimer = window.setTimeout( function(obj){
				return function(){
					obj.clearMsg();
				}
			}(this), 5000);
			if(this.onDeleteSuccess) this.onDeleteSuccess(json);
		}
		else // Ошибка
		{
			this.msg.update();
			var div = this.msg.appendChild( crElem('div', { 'class': 'msg-err' }, '', [crElem('b',null,null,_t('error_')), json.error.message]) );
		}
	},//---------------------------------------------------------------------
	
	clearMsgTimer: null,
	clearMsg: function() {
		this.msg.update();
		this.clearMsgTimer = null;
	},//---------------------------------------------------------------------
	
	indx: 0,
	rowLayer: null,
	addInfoRow: null,
	edtRow: null,
	onDeleteSuccess: null
};
///////////////////  У д а л е н и е  з а п и с и  //////////////////////////
/////////////////////////////////////////////////////////////////////////////


/////////////////////////////////////////////////////////////////////////////
/////////////////  З а г р у з к а  и з о б р а ж е н и я  //////////////////
var CImgUpload = Class.create();
CImgUpload.prototype = {
	initialize: function(indx, column) {
		this.id_ = indx;
		this.column = column;
		this.indx = '-'+indx+'-'+column;
		this.formName = 'form_image'+this.indx;
		this.frameName = 'upload_frame'+this.indx;
		this.msg = $('image_msg'+this.indx);
		this.imagesListName = 'images_list'+this.indx;
		
		this.setEvents();
	},//---------------------------------------------------------------------

	upload: function() {
		document[this.formName].operation.value = 'upload';
		this.process();
	},//---------------------------------------------------------------------
	
	delete_: function(elem) {
		document[this.formName].operation.value = 'del';
		document[this.formName].operation_item_id.value = this.column+n;
		this.process();
	},//---------------------------------------------------------------------
	
	process: function() {
		window.frames[this.frameName].window.document.inProgress = true;
		$(this.formName).submit();
		if(this.timer!=null) window.clearTimeout(this.timer);
		this.timer = window.setTimeout( function(obj){
			return function(){
				obj.checkUploadedFile();
			}
		}(this), 200);
		return true;
	},//---------------------------------------------------------------------
	
	checkUploadedFile: function(obj) {
		if(!window.frames[this.frameName].window.document.inProgress) {
			this.msg.update();
			this.showImages();
			this.setEvents();
		}
		else {
			this.msg.update();
			this.msg.appendChild( crElem('div', { 'class': 'loading' }, '', [crElem('p', {}, '', _t('loading'))] ) );
			this.timer = window.setTimeout(function(obj){
				return function(){
					obj.checkUploadedFile();
				}
			}(this), 200);
		}
	},//---------------------------------------------------------------------
	
	showImages: function() {
		var json;
		
		try {
			json = window.frames[this.frameName].window.document.getElementById('json').innerHTML;
			json = eval('(' + json + ')');
		}
		catch (e) { this.msg.innerHTML = '<B>' + _t('error') + '</B> ' + json; return; }
		if(json.status)	{
			$(this.imagesListName).innerHTML = window.frames[this.frameName].window.document.getElementById('images').innerHTML;
			$('images_info'+this.indx).innerHTML = window.frames[this.frameName].window.document.getElementById('images_info').innerHTML;
			document[this.formName]['image'+this.indx].value = '';
		}
		else {
			this.msg.innerHTML = '<B>' + _t('error_') + '</B>'+json.error.message;
		}
	},//---------------------------------------------------------------------
	
	setEvents: function() {
		var obj = this;
		
		// -----------  I m a g e  c o l s  d a t a  a p p l y  -------------
		$(this.imagesListName).getElementsBySelector('.btn_image_cols_apply').each( function(elem){
			if(!elem.getAttribute('event')) Event.observe( elem, 'click', function(){
				var arr = this.form.id.split('-'), rowId = arr[1], colName = arr[2], imageNum = arr[3],
					msgId = 'image_cols-' + rowId + '-' + colName + '-' + imageNum + '-Msg',
					conn = new CSrvConnect(msgId, '/srv/add_edt/cols_data/', '', true);
				
				this.form.cont.value = $(obj.formName).cont.value;
				var params = Element.extend(this.form).serialize();
				conn.load( params );

				return false;
			} );
			elem.setAttribute('event', true);
		} );
		
		// -------------------  D e l e t e  I m a g e  ---------------------
		$(this.imagesListName).getElementsBySelector('.lnk_image_delete').each( function(elem){
			if(!elem.getAttribute('event')) Event.observe( elem, 'click', function(){
				if(!confirm(_t('delete_image_confirmation'))) return false;
				
				var n = this.id.split('-')[3];
				document[obj.formName].operation.value = 'del';
				document[obj.formName].operation_item_id.value = obj.column+n;
				obj.process();
				return false;
			} );
			elem.setAttribute('event', true);
		} );
	},//---------------------------------------------------------------------
	
	id_: null,
	column: null,
	indx: null,
	formName: null,
	frameName: null,
	imagesListName: null,
	timer: null
};
/////////////////  З а г р у з к а  и з о б р а ж е н и я  //////////////////
/////////////////////////////////////////////////////////////////////////////


/////////////////////////////////////////////////////////////////////////////
///////////////////////  З а г р у з к а  ф а й л а  ////////////////////////
var CFileUpload = Class.create();
CFileUpload.prototype = {
	initialize: function(indx, column) {
		this.id_ = indx;
		this.column = column;
		this.indx = '-'+indx+'-'+column;
		this.formName = 'form_file'+this.indx;
		this.frameName = 'upload_frame'+this.indx;
		this.msg = $('file_msg'+this.indx);
		this.filesListName = 'files_list'+this.indx;
		
		this.setEvents();
	},//---------------------------------------------------------------------

	upload: function() {
		document[this.formName].operation.value = 'upload';
		this.process();
	},//---------------------------------------------------------------------
	
	delete_: function(elem) {
		document[this.formName].operation.value = 'del';
		document[this.formName].operation_item_id.value = this.column+n;
		this.process();
	},//---------------------------------------------------------------------
	
	process: function() {
		window.frames[this.frameName].window.document.inProgress = true;
		$(this.formName).submit();
		if(this.timer!=null) window.clearTimeout(this.timer);
		this.timer = window.setTimeout( function(obj){
			return function(){
				obj.checkUploadedFile();
			}
		}(this), 200);
		return true;
	},//---------------------------------------------------------------------
	
	checkUploadedFile: function(obj) {
		if(!window.frames[this.frameName].window.document.inProgress) {
			this.msg.update();
			this.showFiles();
			this.setEvents();
		}
		else {
			this.msg.update();
			this.msg.appendChild( crElem('div', { 'class': 'loading' }, '', [crElem('p', {}, '', _t('loading'))] ) );
			this.timer = window.setTimeout(function(obj){
				return function(){
					obj.checkUploadedFile();
				}
			}(this), 200);
		}
	},//---------------------------------------------------------------------
	
	showFiles: function() {
		var json;
		try { json = eval('(' + window.frames[this.frameName].window.document.getElementById('json').innerHTML + ')'); }
		catch (e) { this.msg.innerHTML = '<B>' + _t('error') + '</B>'; return; }
		if(json.status)	{
			$(this.filesListName).innerHTML = window.frames[this.frameName].window.document.getElementById('files').innerHTML;
			$('files_info'+this.indx).innerHTML = window.frames[this.frameName].window.document.getElementById('files_info').innerHTML;
			document[this.formName]['file'+this.indx].value = '';
		}
		else {
			this.msg.innerHTML = '<B>' + _t('error_') + '</B>'+json.error.message;
		}
	},//---------------------------------------------------------------------
	
	setEvents: function() {
		var obj = this;
		
		// --------------------  D e l e t e  F i l e  ----------------------
		$(this.filesListName).getElementsBySelector('.lnk_file_delete').each( function(elem){
			if(!elem.getAttribute('event')) Event.observe( elem, 'click', function(){
				if(!confirm(_t('delete_file_confirmation'))) return false;
				
				var n = this.id.split('-')[3];
				document[obj.formName].operation.value = 'del';
				document[obj.formName].operation_item_id.value = n;
				obj.process();
				return false;
			} );
			elem.setAttribute('event', true);
		} );
	},//---------------------------------------------------------------------
	
	id_: null,
	column: null,
	indx: null,
	formName: null,
	frameName: null,
	filesListName: null,
	timer: null
};
///////////////////////  З а г р у з к а  ф а й л а  ////////////////////////
/////////////////////////////////////////////////////////////////////////////


/////////////////////////////////////////////////////////////////////////////
///  Р е д а к т и р о в а н и е  " с о б с т в е н н о й "  з а п и с и  ///
var CSrvSelf = Class.create();
CSrvSelf.prototype = {
	initialize: function(content, url) {
		this.content = content;
		this.urlSecond = url;
		this.onLoad = this.getSelfId;
		
		this.msg = $(this.content+'Msg');
	},//---------------------------------------------------------------------

	// Получение с сервера ID
	getSelfId: function(t) {
		var json;
		try {
			json = eval('(' + t.responseText + ')');
		}
		catch(e) {
			this.msg.update('<div class="msg-err">' + _t('error') + '</div>');
		}

		if(json.status) {// Операция выполнена успешно
			this.msg.update();
			this.urlFirst = this.url;	// store the first url for the refresh button
			this.url = this.urlSecond + '&row_id=' + json.indx;
			
			this.connEdt = Object.extend(new CSrvConnect(this.cnt, this.root, this.url), new CSrvAddEdt(this.content, 'process/', json.indx, this.container) );
			this.connEdt.load();
			this.url = this.urlFirst;	// refresh first url as current
		}
	}
};
///  Р е д а к т и р о в а н и е  " с о б с т в е н н о й "  з а п и с и  ///
/////////////////////////////////////////////////////////////////////////////
