/*	file: panel.js
	LJEX Panels. © 2008-2009 t.schweda

	Description:
	Alle von ljex.Panel abgeleiteten Klassen sind hier definiert.

	Provides:
	<ljex.Panel>, <ljex.TreePanel>, <ljex.GridPanel>, <ljex.TabPanel>

	Requires:
	<toolbar.js>, <json2.js>, <core.js>
*/

/* 	class: ljex.Panel
	Basisklasse aller Panels. ljex.Panel stellt die Grundfunktionalitäten für alle Panelarten bereit.
*/
// {{{1 Dokumentation
/*	properties: Konfigurationsoptionen
	id (string) - ID des Panels (optional. default = uniqueID)
	width (int) - Breite des Panels in Pixel. Wird keine Breite angegeben, so ist default=100%.
	height (int) - Höhe des Panels in Pixel. (default = 100%).
	float (-) - wenn angegeben erhält das Panel die Eigenschaft "float:left;"
	clear (-) - wenn angegeben, erhält das Panel die Egenschaft "clear:left;"
	title (string) - Text in Titelleiste. Wenn keine Angabe, dann wird auch keine Titelleiste dargestellt.
	tb (hash) - JSON Array mit Konfiguration für <ljex.Toolbar>.
	html (string) - Inhalt des Panels in HTML Notation.
	padding (int) - Innenabstand in Pixel.
	renderTo (string) - Das Panel soll dahin gerendert werden. Meist ID eines div-Containers.
*/
// }}}1
// {{{1 Code
/*	constructor: ljex.Panel
	Erzeugt eine neue Objektinstanz.

	parameters:
	args (hash) - JSON Array mit <Konfigurationsoptionen>.
*/
ljex.Panel = function(args){
	$assimilate.call(this, args);
	
	$setdef.call(this,{
		id: 'lx-panel#'+$genid()
	});

	this.el=null;
	this.contentEl=null;

	this.args=args;

	this.vStyles = ['backgroundColor', 'width', 'height', 'left', 'top', 'marginLeft', 'marginRight', 'marginTop', 'marginBottom', 'margin'];

}

/*	method:	render
	Rendert das Panel nach Angaben in den <Konfigurationsoptionen> und hängt es
	in den DOM-Baum ein.

	returns:
	(object) - Node-Objekt des Panels.
*/
ljex.Panel.prototype.render = function(){ // {{{ Code
	var thisObj=this;
	this.el = document.createElement("div");
	this.el.id = this.id;

	this.el.className="lx-panel-frame";
	this.el.style.width=(this.width!=undefined)?this.width+'px':'100%'; //-borderOffset-paddingOffset);

	if(this.height!=undefined){
		this.el.style.height=this.height+'px';
	}else{ 
		this.el.style.height='100%';
	}

	for(var j=0;j<this.vStyles.length;j++){
		var s = this.args[this.vStyles[j]];
		if(s!=undefined){
			this.el.style[this.vStyles[j]]=s;
		}
	}

	if(this.args['float']!=undefined){
	//	if(this.args['float']=='left') this.el.style.position='relative';
		this.el.className="lx-panel-frame lx-panel-frame-float";

	}
	if(this.args['clear']!=undefined){
		this.el.className="lx-panel-frame lx-panel-frame-clear";

	}

	if(this.args['title']!=undefined){
		var titleEl = document.createElement("div");
		titleEl.style.width=(this.args.width+5)+'px';
		titleEl.className='lx-panel-title';
		var titleCenterWidth=this.args.width-50;

		// Panel-Title
		var titleHtml="";
		titleHtml+="<div class='lx-panel-title-left'></div>";
		titleHtml+="<div class='lx-panel-title-center' "+
		( (this.args.width!=null)?'style="width:'+titleCenterWidth+'px;"':'' )+"><div style='padding-top:7px'>"+$shadow(this.args.title)+"</div></div>";
		titleHtml+="<div class='lx-panel-title-right'>";
//	winHtml+="<img id='"+this.id+'-close'+
//				  "' style='position:absolute;left:"+(this.width-22)+"px;top:4px;cursor:pointer;' src='"+ljex.path+"/themes/"+ljex.theme+"/images/windows/close.png'>";
		titleHtml+="</div>";
		titleEl.innerHTML=titleHtml;
		titleEl.style.clear='left';

		this.el.appendChild(titleEl);
	}

	if(this.args.tb!=undefined){
		this.toolBar = new ljex.ToolBar({
			id: this.id+'-toolbar',
			width: this.args.width,
			items: this.args.tb
		});

		this.el.appendChild(this.toolBar.render());
	}

	// Panel COntent
	this.contentEl=document.createElement("div");
	with(this.contentEl){
		id=this.id+"-content";
		className="lx-panel-content";

		if(this.args['title']==undefined){
			var titleHeight=0;
		}else{
			var titleHeight=26;
		}

		if(this.args.tb!=undefined ){
			titleHeight+=28;
		}

		if(this.args.padding!=undefined){
			style.padding=this.args.padding;
			var paddingOffset=(ljex.isIE())?0:this.args.padding*2;
		}else{
			var paddingOffset=0;
		}
		
		var borderOffset=(ljex.isIE())?2:0; // IE rechnet border mit!

		if(this.html!=undefined) innerHTML=this.html;

		if(this.contentBgColor!=undefined){
			switch(this.contentBgColor){
				case 'transparent':
					style.backgroundImage='url(/ljex/images/tp.png)';
					style.backgroundRepeat='repeat';
					this.el.style.backgroundColor='transparent';
					break;
				default:
					style.backgroundColor=this.contentBgColor;
			}
		}

	}

	if(this.height!=undefined) this.contentEl.style.height=this.height-titleHeight-paddingOffset-borderOffset;
	else this.contentEl.style.height="100%"; 
	if(this.width!=undefined) this.contentEl.style.width=this.width-paddingOffset-borderOffset;
	else this.contentEl.style.width="100%"; 

	this.el.appendChild(this.contentEl);
	//alert("Panel.render(): "+this.contentEl.id);

	if(this.renderTo!=undefined){
		$(this.renderTo).appendChild(this.el);
	}

	return this.el;
}
// }}}
// }}}1

/*	class:	ljex.GridPanel
	Erzeugt ein Panel zur Darstellung von Listen. Diese Klasse ist eine direkte Ableitung
	von <ljex.Panel> und erbt daher auch dessen Optionen: <ljex.Panel.Konfigurationsoptionen>. Diese sind hier nicht nochmal erwähnt.
*/
// {{{1 Dokumentation
/*
	Beispiel JavaScript:
	Im folgenden JS-Auszug wird ein GridPanel innerhalb eines Ajax Requests erzeugt. Die Angabe "items: data['list']"
	bezieht sich dabei auf das vom PHP-Skript zurückgegebene Array.
	(code)
		...
		callback: function(response) {
			var data = eval("("+response.responseText+")");

			// data['list'] ist das SQL-Abfrageergebnis.

			var listPanel = new ljex.GridPanel({
				id: 'newsletter-open-listpanel',
				width: 650,
				height: 350,
				maxItems: 20,
				rowclicked: function(){ // Nur Demo...
				},
				
				cols: [{id: 'nl_id', display: false},{ id: 'nl_ci'}, 
					   {id: 'lang'}, {id: 'nl_name'}, {id: 'nl_author'}, 
					   {id: 'nl_date'},	{id: 'modification_date'}],
				items: data['list'] 
			});
			...
		}
		...
	(end)

	Beispiel PHP:
	Hier ein Auszug aus dem PHP-Skript, welches die Daten aus der DB liest und für das GridPanel verpackt.
	(code)
		...
		$sql="select nl_id, nl_ci, lang, nl_name, nl_author, nl_date from cms_newsletters";
		$res = $db->fetchAll($sql);
		echo json_encode(array("success" => true,  "list" => $res));
	(end)

	Beispiel JSON:
	Möchte man die Daten nicht von einem PHP-Skript aus DB-Einträgen generieren lassen, so könnte eine Listendefinition
	auch so aussehen:
	(code)
	[{'nl_id':'12',nl_ci:'cs','nl_name':'Newsletter 2/09',...}, 
	 {'nl_id':'13','nl_ci':'cs','nl_name':'Newsletter 3/09',...}, ...]
	(end)

*/
/*	properties: Konfigurationsoptionen
	items (hash) - JSON Array mit Listeneinträgen. Der Aufbau ist abhängig von den cols.
	cols (hash) - JSON Array das die einzelnen Spalten definiert. Siehe: <Columns>
	maxItems (int) - Maximale Anzahl anzuzeigender Items auf einer Seite.
	url (string) - URL die <reload> benutzt um neue Daten anzufordern.
	params (object) - POST Parameter kodiert als JSON Key:Value Paare. Ebenfalls z.Z. nur von <reload> genutzt.
	rowclicked (function) - Funktion, die bei Klick auf eine Zeile ausgeführt wird.
*/
/*	properties: Klasseneigenschaften
	selectedRow (object) - Pointer auf das Row-Object, welches aktuell ausgewählt ist.
	selectedCell (object) - Pointer auf das aktuell gewählte (geklickte) Cell-Objekt.
*/
/*	properties: Columns
	id (string) - ID der Spalte.
	title (string) - Titel der Spalte (noch ohne Wirkung)
	display (bool) - true = Spalte darstellen, false = Spalte nicht darstellen.
*/
// }}}1
// {{{1 Code
/*	constructor: ljex.GridPanel
	Initialisiert das GridPanel.

	parameters:
	args (hash) - <Konfigurationsoptionen>
*/
ljex.GridPanel = function(args){
	$assimilate.call(this, args);
	ljex.Panel.call(this, args);


	this.gridEl = null;
	this.selectedRow=null;
	this.selectedCell=null;
	this.rows=[];

	this.itemsUnfiltered=this.items; 
	this.aktFilterRegEx=[];
	this.aktFilterCols=[];
	this.filtered=false;

	if(!this.items.length==0){
		if(!this.maxItems) this.maxItems=this.items.length;
		this.lastPage = Math.ceil(this.items.length/this.maxItems);
		this.aktPage=1;
	}else{
		this.maxItems=0;
		this.lastPage=0;
		this.aktPage=0;
	}
}

ljex.GridPanel.prototype = new ljex.Panel({});
ljex.GridPanel.prototype.constructor = ljex.GridPanel;

/*	method: deleteRow
	Löscht eine Zeile aus der Anzeige. Etwaige hinterlegte Daten bleiben jedoch unberührt.

	parameters:
	num (int) - Zeilennummer
*/
ljex.GridPanel.prototype.deleteRow = function(num){
	this.gridEl.deleteRow(num);
}

/* 	method: reload
	Das GridPanel mit aktuellen Daten neu laden. Dabei kommen die <Konfigurationsoptionen> "param" und "url"
	ins Spiel. Eine Manipulation dieser Parameter könnte beispielsweise die GET-Parameter ändern und
	somit das Suchergebnis beeinflussen.

	parameters:
	itemsVar (string) - Bezeichner des Schlüssels hinter dem sich die Daten aus dem Rückgabearray befinden. Siehe obiges Beispiel.
*/
ljex.GridPanel.prototype.reload = function(itemsVar){ // {{{ Code
	var items=itemsVar;
	new ljex.Ajax({
			url: this.url,
			method: 'POST',
			param: this.param,
			scope: this,
			callback: function(response){ 
				var data = JSON.parse(response.responseText);

				if(!this.maxItems) this.maxItems=data[items].length;
				this.lastPage = Math.ceil(data[items].length/this.maxItems);
				this.aktPage=1;

				this.update(data[items]);
				this.itemsUnfiltered=data[items];
			}
		}).request();
}
// }}}

/*	method:	update
	Listeneinträge updaten. Erfüllt im Grunde diesselbe Funktion wie <reload>, jedoch
	ohne selbst einen Ajaxrequest durchzuführen. Das muss in diesem Fall vorher erledigt worden sein.

	parameters:
	items (hash) - vollständige Itemstruktur mit neuen Listeneinträgen.
*/
ljex.GridPanel.prototype.update = function(items){ // {{{ Code
	this.items=items;
	if(!this.items.length==0){
		if(!this.maxItems) this.maxItems=this.items.length;
		this.lastPage = Math.ceil(this.items.length/this.maxItems);
	}

	this.selectedRow=null;
	this.render(true);

	var pageInfo=$("ljex-open-pageinfo-"+this.id);
	pageInfo.innerHTML=this.aktPage+" / "+this.lastPage;
	
	$("ljex-grid-total-"+this.id).innerHTML="total: "+this.items.length;

//	this.el.innerHTML = el.innerHTML;
//	el.replaceChild(this.contentEl,this.contentEl);
}
// }}} 

ljex.GridPanel.prototype.filter = function(items){
	var thisObj=this;
	if(items) thisObj.items=items;
	var newitems=[]; var c=0;

	if(thisObj.itemsUnfiltered.length<=1) thisObj.itemsUnfiltered=thisObj.items;


	for(var j=0;j<thisObj.cols.length;j++){
			if((thisObj.cols[j].display==undefined || thisObj.cols[j].display) &&
				(thisObj.cols[j].filterCol==undefined || thisObj.cols[j].filterCol)	){

				if($(thisObj.cols[j].id+'-fld') && $(thisObj.cols[j].id+'-fld').value!=""){
					this.filtered=true;
					this.aktFilterRegEx[thisObj.cols[j].id]=$(thisObj.cols[j].id+'-fld').value;
					this.aktFilterCols.push(thisObj.cols[j]);
				}

			}
	}

	for(var i=0;i<thisObj.items.length;i++){
		var matched=0;
		for(var j=0;j<this.aktFilterCols.length;j++){

			var filterString=this.aktFilterRegEx[this.aktFilterCols[j].id];

			var regex=new RegExp(".*"+String(filterString)+".*","gi");
			var matchs=String(thisObj.items[i][this.aktFilterCols[j].id]).match(regex);
			if(matchs!=null && matchs.length==1 && matchs[0]!=""){
				matched++;
			}
		}
		if(matched==this.aktFilterCols.length){
			newitems[newitems.length]=thisObj.items[i];
		}
	}

	return newitems;
}


/*	method: render
	Erstellt das GridPanel und zeigt es an (wenn renderTo definiert ist).

	parameters:
	renew (bool) - true = nur updaten, false/keine Angabe = komplett neu erstellen

	returns:
	(object) - HTML Node des GridPanels.
*/
ljex.GridPanel.prototype.render = function(renew,bodyOnly){ // {{{2 Code
	var thisObj=this;
	this.rows=[];
	this.renew=renew; // Wrapper für RenderHead

	if(renew){
		this.contentEl.removeChild($(this.id+'-elctr'));
		if($(this.id+'-elheader')) this.contentEl.removeChild($(this.id+'-elheader'));
	}else{
		ljex.Panel.prototype.render.apply(this);
	}

	this.contentEl.style.overflow="hidden";

//----------------------------------------------------------------------------------------------	
	var elCtr = $create();
	elCtr.id = this.id+'-elctr';
	elCtr.style.width=(this.width)?((ljex.isIE())?this.width-2:this.width):"100%";
	elCtr.style.overflowY='auto';
	elCtr.style.overflowX='hidden';
	elCtr.style.height=(ljex.isIE())?this.height-57:this.height-55;

//	if(bodyOnly==undefined || !bodyOnly) {
//	}

	this.gridEl = document.createElement("table");
	this.gridEl.className='lx-grid-panel';
	this.gridEl.id = this.id+'-grid';
	this.gridEl.style.width = '100%'; 
	this.gridEl.cellSpacing=0; this.gridEl.cellPadding=0;



//	this.gridEl.appendChild(gridHead);

//	var vanz=(this.items.length<( (this.maxItems)?this.maxItems:20) )?this.items.length:( (this.maxItems)?this.maxItems:20);
	var ioffset = (this.aktPage-1)*this.maxItems;

	if( (this.maxItems+ioffset) > this.items.length){
		var	vanz = this.items.length - ioffset;
	}else{
		var vanz = this.maxItems;
	}

	var gridBody = document.createElement("tbody");
	this.gridBodyPtr=gridBody;
	gridBody.style.overflow='hidden';


	this.gridEl.appendChild(gridBody);

	for(var i=0;i<vanz;i++){
		var row = document.createElement("tr");
		gridBody.appendChild(row); //insertRow(i);
	
		row.idx = i;
		row.style.cursor='pointer';
		if(ljex.isIE()) row.style.height="100%";
//		if(i==0) row.style.position='fixed';
		row.onmouseover = function(){
			this.style.backgroundColor='#CDDEF8';
		}
		row.onmouseout = function(){
			if(this !== thisObj.selectedRow)
				this.style.backgroundColor='#eee';
		}
		row.onclick = function(){
			if(thisObj.selectedRow)
				thisObj.selectedRow.style.backgroundColor='#eee';
			
			if(thisObj.selectedRow === this){
				thisObj.selectedRow=null;
			}else{
				this.style.backgroundColor='#CDDEF8';
				thisObj.selectedRow=this;
			}

			if(thisObj.rowclicked){
				thisObj.rowclicked.call(this);
			}

			return true;
		}
		
		for(var j=0;j<this.cols.length;j++){
			var cell=row.insertCell(j);
		//	cell.id=this.cols[j]['id']+'_'+i;
			cell.colName = this.cols[j]['id'];
			if(this.cols[j]['width']!=undefined){
				cell.style.width=this.cols[j]['width']+'px';
			}			

			if(j==this.cols.length-1){
				cell.className="lx-grid-panel-td-last";
			}else{
				cell.className="lx-grid-panel-td";
			}

			if(this.cols[j]['display']==undefined || this.cols[j].display===true){
				cell.innerHTML=this.items[i+ioffset][this.cols[j]['id']];
			}else{
				cell.style.width="0px";
			}
			
			cell.value=this.items[i+ioffset][this.cols[j]['id']];
			cell.rowIdx=i;
			cell.idx=j;
			cell.onclick = function(){
				thisObj.selectedCell=this;
			}
		}
	
	/*
		if(this.rowclicked ){
			if(ljex.isIE())
				row.attachEvent("onclick", function(){ thisObj.rowclicked.call(window.event.srcElement); });
			else
				row.addEventListener('click', this.rowclicked, false);
		}
	*/	
		if(this.rowdblclicked ){
			if(ljex.isIE())
				row.attachEvent("ondblclick", this.rowclicked);
			else
				row.addEventListener('dblclick', this.rowclicked, false);
		}

		row.onmousedown = function(e){
			if(ljex.isIE()){
				var rightClick = (event.button==2)?true:false;
			}else{
				var rightClick = (e.which==3)?true:false;
			}
			if(rightClick && thisObj.onrightclick!=undefined){
				this.onclick();

				if(typeof(thisObj.onrightclick)=="string"){
					eval(thisObj.onrightclick+".call(this, thisObj, e);");
				}else{
					thisObj.onrightclick.call(this, thisObj, e);
				}
			}
			return false;
		}

		this.rows.push(row);
	}


	elCtr.appendChild(this.gridEl);

	// ---------------------------- FOOTER ------------------------------------------------
	// {{{3

	var footer = $create();
	with(footer.style){
		backgroundColor='#ccc';
		height='30px';
		//width=this.el.offsetWidth; //"100%";
	}

	
	var tblEl=document.createElement("table");
	tblEl.cellPadding=0; tblEl.cellSpacing=0;
	tblEl.style.color='#000';
	tblEl.align='center';

	var tblRow=tblEl.insertRow(0);
	tblCell=tblRow.insertCell(0);

	var total = $create();
	total.id = "ljex-grid-total-"+this.id;
	with(total.style){
		marginTop='7px';
		marginRight='10px';
		fontSize='9px';
		cssFloat='left';
		display='inline';
	}

	total.innerHTML="total: "+this.items.length+"";
	tblCell.appendChild(total);


	var pprevious = $create();
	with (pprevious.style){
		margin='5px 5px 0px 0px';
		cursor='pointer';
		cssFloat='left';
		display='inline';
	}

	var pprevious_img = document.createElement("img");
	pprevious_img.src=ljex.path+"/images/back.png";

	pprevious.appendChild(pprevious_img);

	pprevious.onclick = function(){
		if(thisObj.aktPage>1){
			thisObj.aktPage--;
			thisObj.update(thisObj.items);

			var pageInfo=$("ljex-open-pageinfo-"+thisObj.id);
			pageInfo.innerHTML=thisObj.aktPage+" / "+thisObj.lastPage;
		}
	}

	tblCell.appendChild(pprevious);

	var pageInfo = $create();
	pageInfo.id = "ljex-open-pageinfo-"+this.id;
	with(pageInfo.style){
		marginTop='7px';
		marginRight='5px';
		fontSize='9px';
		cssFloat='left';
		display='inline';
	}

	pageInfo.innerHTML=this.aktPage+" / "+this.lastPage;

	tblCell.appendChild(pageInfo);

	var pnext = $create();
	with (pnext.style){
		margin='5px 5px 0px 0px';
		cursor='pointer';
		cssFloat='left';
		display='inline';
	}


	var pnext_img = document.createElement("img");
	pnext_img.src=ljex.path+"/images/forward.png";

	pnext.appendChild(pnext_img);

	pnext.onclick = function(){
		if(thisObj.maxItems*(thisObj.aktPage) < thisObj.items.length){
			thisObj.aktPage++;
			thisObj.update(thisObj.items);
			
			var pageInfo=$("ljex-open-pageinfo-"+thisObj.id);
			pageInfo.innerHTML=thisObj.aktPage+" / "+thisObj.lastPage;
		}
	}


	tblCell.appendChild(pnext);

	tblCell2 = tblRow.insertCell(1);

	var filterBtnCt = $create();
	filterBtnCt.id=this.id+'-btn-filter-ct';
//	filterBtnCt.style.cssFloat="left";
	filterBtnCt.style.marginLeft="10px";

	var filterBtn = new ljex.Button({
		id: this.id+'-btn-filter',
		icon: ljex.path+'/images/filter.png',
		tooltip: (ljex.lang=='de')?'Klicken um Liste zu filtern':'click to filter entries',
		onclick: function(e){
			var fItems=[];
			for(i=0;i<thisObj.cols.length;i++){
				if( (thisObj.cols[i].display==undefined || thisObj.cols[i].display) &&
					(thisObj.cols[i].filterCol==undefined || thisObj.cols[i].filterCol) ){
					fItems.push({
						xtype: 'textfield',
						id: thisObj.cols[i].id+'-fld',
						label: thisObj.cols[i].title,
						width: (thisObj.cols[i].width)?thisObj.cols[i].width:250,
						handler: {
							"keypress": function(e){
								if(ljex.isIE()) var keycode = event.keyCode;
								else var keycode = e.which;
								if(keycode==13){
									$(thisObj.id+'-filter-btn-accept').onclick();
								}
							}
						}

					});
				}
			}

			var filterWin = new ljex.FormWindow({
				title: 'Filter',
				icon: ljex.path+'/images/filter.png',

				form: {
					id: this.id+'-fw-frm',
					labelWidth: 110,
					onrender: function(){
						$(fItems[0].id).focus();
					},

					items: fItems,

					buttons:[{
						id: thisObj.id+'-filter-btn-accept',
						icon: ljex.path+'/images/ok.png',
						text: 'Anwenden',
						handler: function(){
							// Filtern ausgelagert
							thisObj.update(thisObj.filter());

							filterWin.close();
						}
					}]
				}
			});

			filterWin.open();
		}
	});

	filterBtnCt.appendChild(filterBtn.render());

	tblCell3 = tblRow.insertCell(2);
	tblCell2.appendChild(filterBtnCt);

	var unfilterBtn = new ljex.Button({
		id: this.id+'-btn-unfilter',
		icon: ljex.path+'/images/unfilter.png',
		tooltip: (ljex.lang=='de')?'Klicken um Liste ungefiltert anzuzeigen':'click to view all (unfiltered) entries',
		onclick: function(e){
			thisObj.aktPage=1;
			thisObj.update(thisObj.itemsUnfiltered);
			thisObj.aktFilterRegEx=[];
			thisObj.aktFilterCols=[];
			thisObj.filtered=false;
		}
	});

	var unfilterBtnCt = $create();
	unfilterBtnCt.id=this.id+'-btn-unfilter-ct';
//	unfilterBtnCt.style.cssFloat="left";
	unfilterBtnCt.style.marginLeft="10px";

	unfilterBtnCt.appendChild(unfilterBtn.render());


	tblCell4 = tblRow.insertCell(3);
	tblCell4.appendChild(unfilterBtnCt);


	// Positionierungsknöpfchen
	if(this.positionable){
		var moveUpBtn = new ljex.Button({
			id: this.id+'-btn-moveUp',
			icon: ljex.path+'/images/up.png',
			tooltip: (ljex.lang=='de')?'Datensatz nach oben schieben':'move dataset up',
			onclick: function(e){
				if(thisObj.selectedRow==null){
					$error("Bitte wählen Sie zunächst einen Datensatz zum verschieben aus!");
				}else{
					var pos=thisObj.selectedRow.cells[0].value;
					thisObj.moveUp(pos,thisObj.selectedRow.idx);
				}
			}
		});

		var moveUpBtnCt = $create();
		moveUpBtnCt.id=this.id+'-btn-moveUp-ct';
		moveUpBtnCt.style.marginLeft="10px";

		moveUpBtnCt.appendChild(moveUpBtn.render());


		tblCell5 = tblRow.insertCell(4);
		tblCell5.appendChild(moveUpBtnCt);

		var moveDownBtn = new ljex.Button({
			id: this.id+'-btn-moveDown',
			icon: ljex.path+'/images/down.png',
			tooltip: (ljex.lang=='de')?'Datensatz nach unten schieben':'move dataset down',
			onclick: function(e){
				if(thisObj.selectedRow==null){
					$error("Bitte wählen Sie zunächst einen Datensatz zum verschieben aus!");
				}else{
					var pos=thisObj.selectedRow.cells[0].value;
					thisObj.moveDown(pos,thisObj.selectedRow.idx);
				}
			}
		});

		var moveDownBtnCt = $create();
		moveDownBtnCt.id=this.id+'-btn-moveDown-ct';
		moveDownBtnCt.style.marginLeft="10px";

		moveDownBtnCt.appendChild(moveDownBtn.render());


		tblCell6 = tblRow.insertCell(5);
		tblCell6.appendChild(moveDownBtnCt);

		var moveToBtn = new ljex.Button({
			id: this.id+'-btn-moveTo',
			icon: ljex.path+'/images/go-jump.png',
			tooltip: (ljex.lang=='de')?'Datensatz an Position verschieben':'move dataset to position',
			onclick: function(e){
				if(thisObj.selectedRow==null){
					$error("Bitte wählen Sie zunächst einen Datensatz zum verschieben aus!");
				}else{
					var pos=thisObj.selectedRow.cells[0].value;
					var win=new ljex.FormWindow({
						title: 'Verschiebe Datensatz',
						center: true,

						form: {
							labelWidth: 100,
							onrender: function(){
								$('mt-position').focus();
							},

							items:[{
								id: 'mt-position',
								width: 80,
								label: 'Position',
								xtype: 'textfield',
								handler: {
									"keypress": function(e){
										if(ljex.isIE()) var keycode = event.keyCode;
										else var keycode = e.which;
										if(keycode==13){
											$('mt-btn-accept').onclick();
										}
									}
								}

							}],

							buttons:[{
								id: 'mt-btn-accept',
								text: '<b>Verschieben</b>',
								handler: function(){
									var to=$('mt-position').value;
									var lastPossiblePos=-1;
									for(var i=0;i<thisObj.items.length;i++){
										lastPossiblePos=(lastPossiblePos<thisObj.items[thisObj.items.length-1].position)?thisObj.items[thisObj.items.length-1].position:lastPossiblePos;
									}
									if(to>lastPossiblePos){
										$error("Sie können den Datensatz nicht weiter als bis zur Position "+lastPossiblePos+" verschieben!");
									}else{
										if(pos==to){
											$error("Ähm... der Datensatz befindet sich bereits an Position "+pos);
										}else{
											thisObj.moveTo(pos,to);
											win.close();
										}
									}
								}
							},{
								id: 'mt-btn-cancel',
								text: 'Abbrechen',
								handler: function(){
									win.close();
								}
							}]
						}
					});

					win.open();

				}
			}
		});

		var moveToBtnCt = $create();
		moveToBtnCt.id=this.id+'-btn-moveTo-ct';
		moveToBtnCt.style.marginLeft="10px";

		moveToBtnCt.appendChild(moveToBtn.render());


		tblCell7 = tblRow.insertCell(6);
		tblCell7.appendChild(moveToBtnCt);

	}


	footer.appendChild(tblEl);

	// {{{3 FOOTER

/*	var headTbl = document.createElement("div");
	headTbl.style.height=30;
	headTbl.style.overflow='hidden';*/

	//headTbl.cellPadding=0;headTbl.cellSpacing=0;
//	headTbl.id=this.id+'-elheader';
//	headTbl.width="100%";

	this.headTable = document.createElement("table");
	this.headTable.cellPadding=0; this.headTable.cellSpacing=0;
	this.headTable.style.height='25px';
	this.headTable.style.backgroundColor='#fff';
	this.headTable.style.width=(this.width)?this.width:"100%"; //totalWidth;
//	headTable.width="100%";
	this.headTable.id=this.id+'-elheader';

	var titleOffset=(this.rows.length>0)?30:0;
	var borderOffset=(ljex.isIE())?2:0;
	if(this.height){
		this.contentEl.style.height=this.height-titleOffset-borderOffset;
	}else if(this.el.offsetHeight!=0){
		this.contentEl.style.height=this.el.offsetHeight-titleOffset-borderOffset;
	}

	if(renew){
		this.contentEl.appendChild(this.headTable);
		this.contentEl.appendChild(elCtr);
	//	$(this.contentEl.id).appendChild(footer);
	}else{
		this.contentEl.appendChild(this.headTable);
		this.contentEl.appendChild(elCtr);

		this.el.appendChild(footer);
		if(this.renderTo) $(this.renderTo).appendChild(this.el);
	}



	// "Unsichtbare" letzte Zeile anhängen. Somit ist mindestens das Fakebild da...
	var blankGIF=new Image();
	if(ljex.isIE()) // Fehler für IE erzeugen
	blankGIF.src="/ljex/images/blak.gif";
	else
	blankGIF.src="/ljex/images/blank.gif";

	var lastRow=document.createElement("tr");
	for(var i=0;i<this.cols.length;i++){
		if(this.cols[i].display==undefined || this.cols[i].display===true){
			var cell=document.createElement("td");
			if(i==this.cols.length-1) cell.appendChild(blankGIF);
			else cell.innerHTML="<div></div>";
			lastRow.appendChild(cell);
		}
	}

	gridBody.appendChild(lastRow);
	
	// Alle ausser IE warten, bis alle Bilder (mindestens das "Fakebild") geladen sind.
	// Damit ist sichergestellt, das die Spaltenbreiten in clientWidth (halbwegs) korrekt sind.
	if(!ljex.isIE()){
		var imagess=elCtr.getElementsByTagName("img");
		this.images_total=imagess.length;

		if(this.images_total>0){
			this.images_loaded=0;
			for(var i=0;i<imagess.length;i++){
				imagess[i].onload = function(){
					thisObj.images_loaded++;
					if(thisObj.images_loaded>=thisObj.images_total){
						thisObj.renderHead(gridBody);						
					}
				}
				imagess[i].onerror = function(){
					thisObj.images_loaded++;
					if(thisObj.images_loaded>=thisObj.images_total){
						thisObj.renderHead(gridBody);						
					}
				}
			}
		}else{
						this.renderHead(gridBody);						
		}

	}else{
		// Für Internet-Explorer Fehler erzeugen & abfangen - Drecksding!
		// onload fkt. bei dem Ding nicht bei img-Tags :(
		blankGIF.onerror = function(){
			blankGIF.src="/ljex/images/blank.gif";
			thisObj.renderHead(gridBody);						
			return true;
		}
	}

	return this.el; 
}


ljex.GridPanel.prototype.moveTo = function(from,to){
	//$alert("Verschiebe von Position: "+from+" nach Position: "+to);
	var pbox=new ljex.progressBox("Verschiebe Datensatz...");
	new ljex.Ajax({
		url: '/lib/TableSort.php5?c=moveTo&tbl='+this.table+'&fldid='+this.fldid+'&from='+from+'&to='+to,
		scope: this,
		callback: function(response){
			var  data=eval("("+response.responseText+")");
//			$alert("Moved Up!");
			var newitems=this.reorder(data.items);
			var items=(this.filtered)?this.filter.call(this,newitems):newitems;
			this.update(items);
			pbox.close();
		}
	}).request();
}

ljex.GridPanel.prototype.reorder = function(dataitems){
	var newitems=[];
	var olditems=(this.filtered)?this.itemsUnfiltered:this.items;

	for(var i=0;i<dataitems.length;i++){
		if(olditems[i][this.fldid]==dataitems[i][this.fldid]){
			olditems[i].prev=dataitems[i].prev;
			olditems[i].next=dataitems[i].next;
			olditems[i].position=dataitems[i].position;
			newitems.push(olditems[i]);
		}else{
			for(var j=0;j<olditems.length;j++){
				if(olditems[j][this.fldid]==dataitems[i][this.fldid]){
					olditems[j].prev=dataitems[i].prev;
					olditems[j].next=dataitems[i].next;
					olditems[j].position=dataitems[i].position;
					newitems.push(olditems[j]);
					break;
				}
			}
		}
	}

	return newitems;
}

ljex.GridPanel.prototype.moveUp = function(pos,idx){
	if(idx>0){
		var pbox=new ljex.progressBox("Verschiebe Datensatz...");
		new ljex.Ajax({
			url: '/lib/TableSort.php5?c=moveUp&tbl='+this.table+'&fldid='+this.fldid+'&pos='+pos,
			method: 'POST',
			param: {
				cols: JSON.stringify(this.cols)
			},
			scope: this,
			callback: function(response){
				var  data=eval("("+response.responseText+")");
				var newitems=this.reorder(data.items);

				var items=(this.filtered)?this.filter.call(this,newitems):newitems;
				this.update(items);
				if(this.gridBodyPtr.rows[idx-1].cells[0].value==pos-1){
					this.gridBodyPtr.rows[idx-1].onclick();
				}else{
					this.gridBodyPtr.rows[idx].onclick();
				}
				pbox.close();
			}
		}).request();
	}else{
		$error("Datensatz ist bereits an Position 1!");
	}
}

ljex.GridPanel.prototype.moveDown = function(pos,idx){
		var pbox=new ljex.progressBox("Verschiebe Datensatz...");
		new ljex.Ajax({
			url: '/lib/TableSort.php5?c=moveDown&tbl='+this.table+'&fldid='+this.fldid+'&pos='+pos,
			scope: this,
			callback: function(response){
				var  data=eval("("+response.responseText+")");
				pbox.close();
				if(data.items){
					var newitems=this.reorder(data.items);
					var items=(this.filtered)?this.filter.call(this,newitems):newitems;
					this.update(items);
					if(this.gridBodyPtr.rows[idx+1].cells[0].value==pos+1){
						this.gridBodyPtr.rows[idx+1].onclick();
					}else{
						this.gridBodyPtr.rows[idx].onclick();
					}

				}else{
					$error("Datensatz ist schon am Ende angelangt.");
				}
			}
		}).request();
}

ljex.GridPanel.prototype.renderHead = function(gridBody){
	var thisObj=this;

	var hb=document.createElement("tbody");

	var headRow = document.createElement("tr");
	headRow.width='100%';
	headRow.style.backgroundColor='#ccc';

	var firstRow=gridBody.rows[0];
	if(firstRow==null) return;

	for(var j=0;j<this.cols.length;j++){

		if( (this.cols[j].display==undefined || this.cols[j].display==true) && gridBody.rows[0].cells[j].clientWidth>0){
			var headCell= document.createElement("td");
			headCell.className="lx-grid-panel-th";
			if(j<this.cols.length-1){
				if(ljex.isIE()){
					if(gridBody.rows[0].cells[j].clientWidth>0)
					headCell.style.width=parseInt(gridBody.rows[0].cells[j].offsetWidth)-1; //-(offset*(j+1));
					else
					headCell.style.display='none';
				}else{
					headCell.style.width=parseInt(gridBody.rows[0].cells[j].offsetWidth)-2; //-(offset*(j+1));
				}
			}

			headRow.appendChild(headCell);
			if( this.cols[j].title!=undefined && this.cols[j].title!=null){
				var hTitle=$create(this.cols[j].id+'#hTitle');
				with(hTitle.style){
					cursor='pointer';
					color='#000';
					paddingLeft='3px';
					width=(parseInt(gridBody.rows[0].cells[j].clientWidth)-7 > 8)?parseInt(gridBody.rows[0].cells[j].clientWidth)-7:0;
					overflow='hidden';
				}
				
				hTitle.setAttribute("colid",this.cols[j].id);
				hTitle.setAttribute("idx",j);
				hTitle.innerHTML=(parseInt(gridBody.rows[0].cells[j].clientWidth)>10)?"<div>"+this.cols[j].title+"</div>":"";

				hTitle.onclick = function(){
					var id=this.id.split("#");
					var colid=id[0];
					var idx=$(this.id).getAttribute('idx');
					var sortdir=(thisObj.cols[idx].sort)?thisObj.cols[idx].sort:'none';
					
					var gt=(sortdir=="none" || sortdir=="desc")?1:-1;
					var regex=/^\d\d\d\d\-\d\d\-\d\d$/;
					var isDate=(regex.test(thisObj.items[0][colid]));

					function sortitems(i1, i2){
						if(isDate){
							var s1=i1[colid].substr(0,4)+i1[colid].substr(5,2)+i1[colid].substr(8,2);
							var s2=i2[colid].substr(0,4)+i2[colid].substr(5,2)+i2[colid].substr(8,2);
						}else{
							var s1=parseInt(i1[colid]);
							var s2=parseInt(i2[colid]);
						}

						if(isNaN(s1)){
							s1=i1[colid];
							s2=i2[colid];
							s1=s1.toLowerCase();
							s2=s2.toLowerCase();
						}

						if(s1 > s2) return gt;
						else return -1*gt;
					}

					thisObj.items.sort(sortitems);
					thisObj.render(true);

					if(gt==1) thisObj.cols[idx].sort="asc";
					else thisObj.cols[idx].sort="desc";

				}
					headCell.appendChild(hTitle);
			}else{
				var dummy=$create();
				dummy.style.width=0;
				headCell.appendChild(dummy);
			}

		}
	}


	hb.appendChild(headRow);
	this.headTable.appendChild(hb);

}

// }}}2
// }}}1

/*	class:	ljex.TreePanel
	Stellt eine Baumstruktur mit Ordnern, Unterordnern und Items dar. Da auch TreePanel
	von Panel abgeleitet ist, gelten auch hier wieder dessen Konfigurationsoptionen.
*/
// {{{1 Dokumentation
/*	properties: Konfigurationsoptionen
	title (string) - Titel des TreePanels
	id (string) - ID des TreePanels.
	innerWidth (int) - innere Breite des Panels.
	collapsed (bool) - true = stelle Baum zusammengefaltet dar, false = Baum augeklappt darstellen.
	items (hash) - Item Konfiguration
*/
// }}}1
// {{{1 Code
/*	constructor: ljex.TreePanel
	Initialisiert das TreePanel Objekt.

	parameters:
	args (hash) - <Konfigurationsoptionen>
*/
ljex.TreePanel = function(args){
	ljex.Panel.call(this, args);
	this.items = args.items;
	
	this.selectedId=null;
	this.selected=null;

	this.tree=null;
	this.treeEl=null;
}

ljex.TreePanel.prototype = new ljex.Panel({});
ljex.TreePanel.prototype.constructor = ljex.TreePanel;

/*	method: selectNode
	Programmatisch einen Baumknoten auswählen. Simmuliert quasi einen KLick.

	todo: label/item... ohje.... sollte man erstmal überarbeiten...
*/
ljex.TreePanel.prototype.selectNode = function(label, item){ // {{{ Code
	if(this.selectedId!=null){
		$(this.selectedId+'-label').className="lx-treepanel-item-label";
	}

	if(this.selectedId==item.id){
		this.selectedId=null;
		this.selected=null;
	}else{
		label.className="lx-treepanel-item-label lx-treepanel-item-label-hovered";
		this.selectedId=item.id;
		this.selected=item;
	}
}
// }}} Code

/*	method: move
	Einen Knoten entweder auf- oder abwärts bewegen. Dies funktioniert jedoch immer nur auf 
	der Ebene des Knotens. Es ist mit dieser Methode nicht möglich, Knoten auf eine andere Ebene
	zu bewegen.

	parameters:
	item (object) - Knoten, der bewegt werden soll.
	direction (string) - "up" = Eine Position nach oben bewegen, "down" = Eine Position nach unten bewegen.
	sNode (object) - Elternknoten. Wenn nicht angegeben, wird der Wurzelknoten angenommen.
*/
ljex.TreePanel.prototype.move = function(item,direction,sNode){// {{{ Code
	var newitems=[];
	if(sNode==undefined){
		sNode=this.items[0];
		newitems[0]={
			id:	'rootNode',
			label: 'Der Wurzelknoten',

			items: []
		};
	}
	
	if(direction=="up"){
		newitems[0].items=this.moveup(item,sNode);
	}else{
		newitems[0].items=this.movedown(item,sNode);
	}

	this.items=newitems;

	this.contentEl.removeChild(this.treeEl);
	this.renderTree();
		
	this.selectedId=null;
	this.selected=null;
	this.selectNode($(item.id+'-label'), item);
}
// }}}

/*	method:	movedown
	Verschiebt einen Knoten nach unten.
*/
ljex.TreePanel.prototype.movedown = function(item,sNode){ // {{{ Code	
	var nextitem = {};
	var newitems=[];

	for(var i=0;i<sNode.items.length;i++){
		if(sNode.items[i].items==undefined || item.id==sNode.items[i].id){
			if(item.id==sNode.items[i].id && (i+1)<sNode.items.length){
				nextitem=sNode.items[i+1];
				newitems.push(nextitem);
				newitems.push(item);
				i++;
			}else{
				newitems.push(sNode.items[i]);
			}
		}else{
			newitems.push(sNode.items[i]);
			newitems[newitems.length-1].items=this.movedown(item,sNode.items[i]);
		}
	}

	return newitems;
}
// }}}

/*	method: moveup
	Verschiebt einen Knoten nach oben.
*/
ljex.TreePanel.prototype.moveup = function(item,sNode){	// {{{ Code
	var previtem = {};
	var newitems=[];

	for(var i=0;i<sNode.items.length;i++){
		if(sNode.items[i].items==undefined || item.prev==sNode.items[i].id){
			if(item.prev==sNode.items[i].id){
				previtem=sNode.items[i];
				newitems.push(item);
				newitems.push(previtem);
				i++;
			}else{
				newitems.push(sNode.items[i]);
			}
		}else{
			newitems.push(sNode.items[i]);
			newitems[newitems.length-1].items=this.moveup(item,sNode.items[i]);
		}
	}

	return newitems;
}
// }}} Code


/*	method: remove
	Löscht einen Knoten aus dem Baum.

	parameters:
	id (string)- ID des Knotens.
	sNode (object) - Elternknoten. Wenn nicht angegeben wird von der Rootnode aus gesucht.
*/
ljex.TreePanel.prototype.remove = function(id, sNode){ // {{{ Code
	if(sNode==undefined) sNode=this.rootNode;

	for(var i=0;i<sNode.items.length;i++){
		if(sNode.items[i].id==id){
			sNode.items.splice(i,1);
			break;
		}
		if(sNode.items[i].items!=undefined){
			this.remove(id, sNode.items[i]);
		}
	}

	this.contentEl.removeChild(this.treeEl);
	this.renderTree();
		
	this.selectedId=null;
}
// }}} Code

/*	method: insert
	Fügt einen neuen Knoten in die Baumstruktur ein. *Weitere Doku folgt noch*
*/
ljex.TreePanel.prototype.insert = function(id, item, sNode){ // {{{ Code
	if(sNode==undefined){
		sNode=this.rootNode;
	}

	if(id==null){
		if(item instanceof Array){
			if(sNode.items==undefined) sNode.items=[];
			for(var j=0;j<item.length;j++){
				sNode.items.push(item[j]);
			}
		}else{
			sNode.items.push(item);
		}
	}else{
		for(var i=0;i<sNode.items.length;i++){
			if(sNode.items[i].id==id){
				if(sNode.items[i].items==undefined){
					sNode.items[i].items=[];
				}
				if(item.length>1){
					for(var j=0;j<item.length;j++){
						sNode.items[i].items.push(item[j]);
					}
				}else{
					sNode.items[i].items.push(item);
				}
				break;
			}
			if(sNode.items[i].items!=undefined && sNode.items[i].items.length!=0){
				this.insert(id, item, sNode.items[i]);
			}
		}
	}

	this.contentEl.removeChild(this.treeEl);
	this.renderTree();

	this.selectedId=null;
}
// }}} Code

ljex.TreePanel.prototype.repaint =function(item){
	var label = $(item.id+'-label');

	label.innerHTML=item.label;
}

/*	method: toggle
	Klappt die Baumstruktur auf, wenn sie geschlossen ist und umgekehrt. Das fkt.
	z.Z. nur bis zur 2ten Ebene.
*/
ljex.TreePanel.prototype.toggle = function(){ // {{{ Code
	for(var i=0;i<this.rootNode.items.length;i++){
		if(this.rootNode.items[i].items!=undefined && this.rootNode.items[i].items.length>0){
			if($(this.rootNode.items[i].id+'-itemct').style.display=='block'){
				$(this.rootNode.items[i].id+'-itemct').style.display='none';
				$(this.rootNode.items[i].id+'-plus').style.backgroundPosition="0px 0px";
			}else{
				$(this.rootNode.items[i].id+'-itemct').style.display='block';
				$(this.rootNode.items[i].id+'-plus').style.backgroundPosition="0px -9px";
			}
		}
	}
}
// }}} Code

ljex.TreePanel.prototype.reload = function(data){
	this.items = data;
	
	this.contentEl.removeChild(this.treeEl);
	this.renderTree();

	this.selected=null;
	this.selectedId=null;
}

ljex.TreePanel.prototype.render = function(){
	ljex.Panel.prototype.render.apply(this);
	this.renderTree();

	return this.el;
}

/*	method:	renderTree (internal)
	interne Methode, die den Baum rendert. Sollte man eher nicht explizit von aussen aufrufen.
*/
ljex.TreePanel.prototype.renderTree = function(){ // {{{ Code
	this.treeEl = document.createElement("div");
	this.treeEl.id=this.id+'-tree';
//	this.treeEl.style.overflow='hidden';
	if(this.args.innerWidth!=undefined)
		this.treeEl.style.width=this.args.innerWidth;

	this.rootNode = this.items[0];
	
	for(var i=0;i<this.rootNode.items.length;i++){
		var prespace=[];
		prespace[0]="<div class='lx-treepanel-item-space' style='width:0px;'></div>";

		this.items[0].items[i].prev=(i==0)?null:this.items[0].items[i-1].id;
		this.items[0].items[i].next=((i+1)<this.items[0].items.length)?this.items[0].items[i+1].id:null;
	//	if(this.rootNode.items[i].next!=null) alert(this.rootNode.items[i].next.id);

		this.treeEl.appendChild(this.renderItem(this.rootNode.items[i], prespace));
	}
	this.contentEl.appendChild(this.treeEl);

}
// }}} Code

/*	method: renderItem (internal)
	Rendert einzelnen Baumknoten. Auch diese Funktion sollte man eher nicht von aussen
	aufrufen.
*/
ljex.TreePanel.prototype.renderItem = function(item, prespace){ // {{{ Code
	var thisObj = this;

	// Äußerer Container des Items 
	var elCt=document.createElement("div");
	elCt.id=item.id+'-elct';
	elCt.style.padding='3px';
	elCt.style.clear="left";

	// Container für Kindknoten
	var itemCt=document.createElement("div");
	itemCt.id=item.id+'-itemct';

	// Innerer Container des Items ("+/-", Icon, Label)
	var itemEl=document.createElement("div");
	with(itemEl){
		id=item.id;
		style.cssFloat="left";
	}

	// Icon
	var iconImg=document.createElement("div");
	iconImg.id=item.id+'-icon';

	if(item.items!=undefined && item.items.length!=0){
		var isFolder=true;

		var plusminusImg = document.createElement("div");
		with(plusminusImg){		
			className='lx-treepanel-item-plusminus';
			id=item.id+'-plus';
			style.backgroundPosition="0px -9px";
		}
	
		if(this.args.collapsed){
			itemCt.style.display='none';
			plusminusImg.style.backgroundPosition="0px 0px";
		}else{
			itemCt.style.display='block';
		}


		iconImg.className='lx-treepanel-folder-icon';

		itemEl.innerHTML=prespace.join(" "); 
		itemEl.appendChild(plusminusImg);
	}else{
		var isFolder=false;
		iconImg.className='lx-treepanel-leaf-icon';
		var prespaceHtml=prespace.join(" ");
		itemEl.innerHTML=prespaceHtml;
	}

	if(item.icon!=undefined) iconImg.style.backgroundImage="url('"+item.icon+"')";
	
	var labelEl=document.createElement("div");
	with(labelEl){
		className='lx-treepanel-item-label';
		id=item.id+'-label';
		innerHTML=item.label;

		onmousedown = function(e){
			if(ljex.isIE()){
				var rightClick = (event.button==2)?true:false;
			}else{
				var rightClick = (e.which==3)?true:false;
			}
			if(rightClick && item.onrightclick!=undefined){
				thisObj.selectNode(this,item.id);

				if(typeof(item.onrightclick)=="string"){
					eval(item.onrightclick+".call(item, thisObj, e);");
				}else{
					item.onrightclick.call(item, thisObj, e);
				}
			}
			return false;
		}

		onclick = function(e){
			thisObj.selectNode(this, item);
			
			if(item.onclick!=undefined){
				if(typeof(item.onclick)=="string"){
					eval(item.onclick+".call(item, thisObj, e);");
				}else{
					item.onclick.call(item, thisObj, e);
				}
			}
			return false;
		}

		onmouseover = function(){
			this.className="lx-treepanel-item-label lx-treepanel-item-label-hovered";
		}

		onmouseout = function(){
			if(thisObj.selectedId!=item.id)
			this.className="lx-treepanel-item-label";
		}
	}

	itemEl.appendChild(iconImg);
	itemEl.appendChild(labelEl);

	elCt.appendChild(itemEl);
	
	if(isFolder){
		prespace[prespace.length]="<div class='lx-treepanel-item-space'></div>";
		for(var j=0;j<item.items.length;j++){
			
			item.items[j].prev=(j==0)?null:item.items[j-1].id;
			item.items[j].next=((j+1)<item.items.length)?item.items[j+1].id:null;

			itemCt.appendChild(this.renderItem(item.items[j], prespace));
		}
		prespace.pop();	
		plusminusImg.style.cursor='pointer';
		iconImg.style.cursor='pointer';
		plusminusImg.onclick = iconImg.onclick = function(){
			if(itemCt.style.display=='block'){
				itemCt.style.display='none';
				plusminusImg.style.backgroundPosition="0px 0px";
			}else{
				itemCt.style.display='block';
				plusminusImg.style.backgroundPosition="0px -9px";
			}
		}
	}


	elCt.appendChild(itemCt);
	
	return elCt;
}
// }}}
// }}}1

/*	class:	ljex.TabPanel
	Stellt ein sogenanntes "Tabbed Panel" dar, also ein Panel mit Reitern.
*/
// {{{1 Code
/*	constructor: ljex.TabPanel
	Initialisiert das TabPanel

	parameters:
	args (hash) - <Konfigurationsoptionen>
*/
ljex.TabPanel = function(args){
	ljex.Panel.call(this, args);
	this.items = args.items;

	this.aktContent=null;
	this.aktTitle=null;
	this.aktId=null;
}

ljex.TabPanel.prototype = new ljex.Panel({});
ljex.TabPanel.prototype.constructor = ljex.TabPanel;

/*	method: appendTab
	*Doku folgt noch*
*/
ljex.TabPanel.prototype.appendTab = function(item){ // {{{ Code
	if(!$(item.id)){
		var ntab = this.renderTab(item,1);
		this.activate(ntab[0],ntab[1]);
		if(item.onrender){
			if(item.scope) item.onrender.call(item.scope); else item.onrender();
		}
	}
}
// }}} Code

/*	method: render
	Rendert das TabPanel. Durchläuft dazu eine Schleife mit einzelnen
	<renderTab> - Aufrufen.
*/
ljex.TabPanel.prototype.render = function(){ // {{{ Code
	thisObj=this;
	ljex.Panel.prototype.render.apply(this);

	// contentEl ist in ljex.Panel deklariert
	this.contentEl.style.height=parseInt(this.contentEl.style.height)-26+'px';
	this.contentEl.style.backgroundColor='#ddd';
//	this.contentEl.style.top='25px';

	// Container für Tabs
	this.tabCt = $create(this.args.id+'-tabct');
	this.tabCt.className='lx-tabpanel-tabct';
	with(this.tabCt.style){
		width=(this.args.width)+'px';
	}


	for(var i=0;i<this.items.length;i++){
		this.renderTab(this.items[i],i);
	}

	this.el.insertBefore(this.tabCt, this.contentEl);

	return this.el;
}
// }}} Code

/*	method:	renderTab
	Rendert ein einzelnes Tab des Panels. *Mehr Doku folgt*
*/
ljex.TabPanel.prototype.renderTab = function(item,i){ // {{{ Code
		var thisObj=this;
		var titleCt = document.createElement("div");
		titleCt.id=item.id;
		titleCt.style.cssFloat='left';
		titleCt.style.cursor='pointer';

		var titleLeft = document.createElement("div");
		titleLeft.className='lx-panel-title-left';
		
		if(item.icon){
			if(item.iconDisplay!=undefined && item.iconDisplay){
				var icdisplay=true;
			}else{
				var icdisplay=false;
			}
			titleLeft.innerHTML="<img style='display:"+((icdisplay)?"block":"none")+"' id="+item.id+"-icon"+" class='lx-panel-title-icon' src='"+item.icon+"'>";
		}

		titleCt.appendChild(titleLeft);

		var titleCenterCt = document.createElement("div");
		titleCenterCt.className='lx-panel-title-center';
		titleCenterCt.innerHTML+="<div class='lx-panel-title-text'>"+item.title+"</div>";
		titleCt.appendChild(titleCenterCt);

		var titleRight = document.createElement("div");
		titleRight.className='lx-panel-title-right';

		var closeImg = document.createElement("div");
		closeImg.id=item.id+'-close';
		closeImg.className="lx-tabpanel-title-close";
		titleRight.appendChild(closeImg);

		titleCt.appendChild(titleRight);

		this.tabCt.appendChild(titleCt);
	

		var tabContentEl = document.createElement("div");
		tabContentEl.id=item.id+'-content';

		tabContentEl.innerHTML=item.html;
		if(i==0){
			this.activate(titleCt, tabContentEl);
		}else{
			 tabContentEl.style.display='none';
			 titleCt.style.opacity=0.7;
		}


		titleCt.onclick = function(){
			thisObj.activate(this, tabContentEl);
		}

		closeImg.onclick= function(){
			var id=this.id.substr(0,this.id.length-6);
			$(thisObj.tabCt.id).removeChild($(id));
			thisObj.contentEl.removeChild($(id+'-content'));
			if(thisObj.aktPanelId==id+'-content'){
				thisObj.aktPanelId=0;
			}
			
			if(thisObj.onclose){
				thisObj.onclose.call(thisObj, id);
			}
		}
		
		this.contentEl.appendChild(tabContentEl);

		return [titleCt, tabContentEl];
}
// }}} Code

/*	method: activate
	*Doku folgt noch*
*/
ljex.TabPanel.prototype.activate = function(selTitle, selContent) { // {{{ Code
	var thisObj=this;

	if(this.aktTitle!=null && selTitle!==this.aktTitle){
		this.aktTitle.firstChild.nextSibling.className = 'lx-panel-title-center';
		this.aktContent.style.display='none';
		this.aktTitle.style.opacity=0.7;
	}
	
	selTitle.firstChild.nextSibling.className = 'lx-panel-title-center lx-panel-title-center-active';
	selTitle.style.opacity=1.0;
	selContent.style.display='block';
	this.aktId=selTitle.id;
	
	this.aktTitle=selTitle;
	this.aktContent=selContent;
} // }}} Code
// }}}1 END CLASS
