/*!
 * jrCMS Main Classes and Utilities
 *
 * The main part contains all classes and functions needed for initial usage
 * of the content management system as well as an API. 
 * For proper usage of the history the JRCmsRsh plugin must be loaded and 
 * instantiated first. The real simple history functions require an empty 
 * blank.html file in the root directory.
 *
 * Conventions for JRCmsRsh history pool:
 * - each public object (class) gets a four digit ID 
 * - the last two digits are used to identify the methods
 *
 * @author Jens Raabe <jens@raabe-berlin.de>
 * @version $Id: jrcms.js 559 2011-07-08 08:57:53Z jensraabe $ 
 * 
 * @copyright Copyright (c) 2010 Jens Raabe
 * Permission is hereby granted, free of charge, to any person 
 * obtaining a copy of this software and associated documentation 
 * files (the "Software"), to deal in the Software without restriction, 
 * including without limitation the rights to use, copy, modify, merge, 
 * publish, distribute, sublicense, and/or sell copies of the Software, 
 * and to permit persons to whom the Software is furnished to do so, 
 * subject to the following conditions:
 *
 * Plugins of the software package may relay to this copy right notice only
 * whereas assets or customer enhancements will have own copyrights.
 * The above copyright notice and this permission notice shall be included 
 * in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 
 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR 
 * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

//pre-definition of classes containted in the script file 
//for references and to speed up loading and availability in DOM

/**
 * @class JRCmsCore
 * @package Client
 * @subpackage Config
 */ 
var JRCmsCore = new Class({
	
	_coreInfo: {
		name:	 		"JRCmsCore",
		instance:		"jrCMS",
		version:	 	"0.3.0",				//Release.Version.Minor
		revision:		"$Revision: 559 $",		//Revision set by svn		
		developer:		"Jens Raabe",
		developer_url:	"http://www.raabe-berlin.de",
		license: 		"MIT",
		classId:		1000
	}  
});

var JRCmsUtils = new Class({
	//no own _pluginInfo, will be not instantiated itself 
});

var JRCmsForm = new Class({
	//no own _pluginInfo, will be not instantiated itself 
    Extends: JRCmsUtils
});

var JRCmsApi = new Class({
	//no own _pluginInfo, will be not instantiated itself 
    Extends: JRCmsForm
});

var JRCmsPlugins = new Class({
	// no own _pluginInfo, will be not instantiated itself 
    Extends: JRCmsUtils
	/**
	 * Plugin Conventions:
	 * 	class name:			two leading upper case letters
	 * 	object name:		the two leading letters as lower case letters
	 * 	constructor:		initialize( options, instanceName )
	 * 	filename:			compressed: <class_name>.cmp.js as default or w/o 'cmp.'
	 * 
	 * Conventions for JRCmsRsh history pool:
	 * 	- each public object (class) gets a four digit class ID 
	 * 	- the last two digits are used to identify the methods
	 * 
	 * preserved classIDs:
	 *	1000	- JRCmsCore		imacs core itself
	 *	1100	- JRCmsRsh		ajax history
	 *	1200	- JRCmsLog		logging functionality
	 *	1300	- JRCmsSpeed	determine communication quality
	 *	1400	- JRCmsGrid		provides Grid functionality
	 *	1900	- JRCmsExample	coding example for an own plugin
	 *
	 *	2300	- JRCmsMenu		simple maintenance of menu items
	 *	2400	- JRCmsEditor	initialize the Xinha editor
	 *	2500	- JRCmsUser		user maintenance
	 *	2600	- JRCmsUserProf	user profile maintenance
	 *
	 *	3200	- JRImgShow		integrates the slideshow asset in the editor (former 2200) 
	 *	3300	- JRCmsPuw		provides a simple popup window for menu points
	 *	3400	- JRCmsEventPlanner	event planne integrated in the editor
	 *	3500	- JRCmsReports	reports integrated in the editor 
	 *
	 * >4900	- extensions of imacs (own plugins)
	 * 
	 */
});

/* ==================================================================== */
/* MOOTOOLS extensions                                                  */
/* ==================================================================== */
var _requestLoaded = false;			// for testing purposes only
/**
 * Refactor Request Class
 * @author Jens Raabe <jens@raabe-berlin.de>
 */
Request = Class.refactor(Request, {
	
	options: {
		jr_useSpinner: false		//own spinner flag
		,method: 'post'				// default for requests
		,link: 'ignore'				// default: 'ignore' or 'chain'
		,async: true				// async requests
		,evalScripts: false 		// don't ask mootools to process js
	}
	,initialize: function(options){
		//we use an own spinner flag to deactivate the spinner after complete
		//and processing the request loading
		if($defined(options.jr_useSpinner))
			options.useSpinner = options.jr_useSpinner;
		this.previous(options);
	}
	,send: function(options){
		_requestLoaded = false;			// for testing purposes only
		this.addEvent('onLoaded', this.onLoaded.bind(this));
		this.previous(options);
	}
	,onLoaded: function(){
		_requestLoaded = !this.running;	// for testing purposes only
	}
	,getSpinner: function(){
		if (!this.spinner) {
			var update = document.id(this.options.spinnerTarget) || document.id(this.options.update);
			if (this.options.jr_useSpinner && update) {
				this.spinner = update.get('spinner', this.options.spinnerOptions);
				//set the own onLoaded event
				['onLoaded', 'onException', 'onCancel'].each(function(event){
					this.addEvent(event, this.spinner.hide.bind(this.spinner));
				}, this);
			} else
			if (this.options.useSpinner && update) {
				this.spinner = update.get('spinner', this.options.spinnerOptions);
				['onComplete', 'onException', 'onCancel'].each(function(event){
					this.addEvent(event, this.spinner.hide.bind(this.spinner));
				}, this);
			}
		}
		return this.spinner;
	}
	,onSuccess: function(){
		//use the onLoaded event as last event after processing
		//the complete and success routines 
		this.fireEvent('complete', arguments).fireEvent('success', arguments).fireEvent('loaded', arguments).callChain();
	}	
	,onFailure: function(){
		if($defined(window.jrCmsLog))
			jrCmsLog.put("F#>> JRCmsApi.processRequest no content "+err);
		this.previous();
	}
});

/**
 * Class supporting a converter for XML to Object. Therefore the name was chosen as
 * XObjectLanguage = XOL ;-)
 * The basic idea of this was taken from author Ciul(?), downgraded to mootools V1.2
 * and adapted for the specific needs of jrcms xml container
 * 
 * @author Jens Raabe <jens@raabe-berlin.de>
 */
Xol = new Class({
	
	xml: null
	,xmlObj: {}

	,convertXml2Obj: function(node) {
		var obj = new Object();
		if(this.hasChildNodesXml(node)) {
			var childObj = (this.getFirstChildNameXmlNode(node)!='_array'?new Object():new Array());
			Array.each(this.getChildElementsXmlNode(node), function(child, index) {
				var childNode = this.convertXml2Obj(child);
				if($type(childObj)!='array'){
					$extend(childObj, childNode);
				} else {
					if(this.hasAttributesXmlNode(child))  
						//per convention the first and only attribute is the index
						childObj[parseInt(this.getValueXmlNode(this.getFirstAttributeXmlNode(child)))] = childNode; 					
					 else
						childObj.push(childNode);
				}
			}, this);
			if(this.getNameXmlNode(node) == '_array' || this.getNameXmlNode(node) == 'root')
				//ignore this elements
				return childObj;
			obj[this.getNameXmlNode(node)] = childObj;
		} else {
			obj[this.getNameXmlNode(node)] = this.getDataXmlNode(node);
		}
		return obj;
	}

	,getRootNodeXml: function(xmlDoc) {
		//taken like as initialize
		this.xml = xmlDoc;
		this.xmlObj = new Object();
		return xmlDoc.documentElement;
	}

	,getNameXmlNode: function(node) {
		//consider special prefix, in case of leading 
		//char not in accordance with XML roles, see cJrcms.php
		return ((node.nodeName.length > 1 && 
				 node.nodeName.search(/___/) == 0)
				? node.nodeName.substr(3)
				: node.nodeName);
	}

	,getValueXmlNode: function(node) {
		return node.nodeValue;
	}

	,getDataXmlNode: function(node) {
		//per convention the first and only attribute is the itemType
		//strings do not have an attribute, but number and boolean
		//TODO: what do do node.firstChild is null
		//-----------------------------------------------------------
		// workaround for firefox which splits nodeValue in packets of 4096 bytes
		// see https://bugzilla.mozilla.org/show_bug.cgi?id=194231 
		// getXmlNodeValueWithout4KBLimit: function(xmlTag) {
		// 	if(xmlTag.firstChild.textContent && xmlTag.normalize) {
		// 	 xmlTag.normalize(xmlTag.firstChild);
		// 	 content=xmlTag.firstChild.textContent;
		//  } else if(xmlTag.firstChild.nodeValue) {
		// 	 content=xmlTag.firstChild.nodeValue;
		//  } else {
		// 	 content=null;
		//  }
		//  return content;
		// }
		// alternative, usage of get wholeText (to be tested for IE, ...)
		if(!this.hasAttributesXmlNode(node))
//			return ($defined(node.firstChild)?node.firstChild.data:'');
			return ($defined(node.firstChild)
					? (node.firstChild.textContent?node.firstChild.wholeText:node.firstChild.data)
					: '');
		else
			return (this.getValueXmlNode(this.getFirstAttributeXmlNode(node)))=='number'
					? parseFloat(node.firstChild.data)
					: node.firstChild.data==0?false:true;
	}

	,hasChildNodesXml: function(node) {
		return (!!node.childNodes && node.childNodes.length != 0 && !$defined(node.firstChild.data));
	}

	,getFirstChildNameXmlNode: function(node) {
		if(this.hasChildNodesXml(node)) {
			return this.getNameXmlNode(node.firstChild);
		} else return null;
	}

	,getChildrenXmlNode: function(node) {
		if(this.hasChildNodesXml(node)) {
			return node.childNodes;
		} else return null;
	}

	,getChildElementsXmlNode: function(node) {
		return this.filterByTypeXml(this.getChildrenXmlNode(node));
	}

	,hasAttributesXmlNode: function(node) {
		return (!!node.attributes && node.attributes.length != 0);
	}

	,getAttributesXmlNode: function(node) {
		if(this.hasAttributesXmlNode(node)) {
			return node.attributes;
		} else return null;
	}
	
	,getFirstAttributeXmlNode: function(node) {
		if(this.hasAttributesXmlNode(node)) {
			return node.attributes[0];
		} else return null;
	}

	,filterByTypeXml: function(nodes) {
		var filteredNodes = this.xml.createElement('filteredNodes');
		for(i=0;i<nodes.length;i++) {
			var newNode = nodes[i].cloneNode(true);
			filteredNodes.appendChild(newNode);
		}
		return filteredNodes.childNodes;
	}
	
	,xml2Obj: function(xmlDoc) {
		return $defined(xmlDoc)?this.convertXml2Obj(this.getRootNodeXml(xmlDoc)):null;
	}
	
});

/**
 * Provide a new request class which extends the basic Request Class
 * with additional methods for sending and receiving XML data  
 * converted to an object as well.
 *  
 * @author Jens Raabe <jens@raabe-berlin.de>
 */
Request.XOL = new Class({

	Extends: Request
	,Implements: Xol

	,success: function(text, xml){
	
		this.onSuccess(this.processScripts(text), xml, this.xml2Obj(xml));
	}
});

/* ==================================================================== */
/* ==================================================================== */
/**
 * JRCmsApi Class
 *
 * @author Jens Raabe <jens@raabe-berlin.de>
 */
(function(){

	/*
	 * Protected variables EDIT AT YOUR OWN RISK
	 */
    var _getContentForNodeId = 1021;
    
    var _globalOptionsSet = {
   		jr_lang:				'en'			// language used for texts, supplied by cConfig.php
		,jr_userLevel:			'000'			// user level init, supplied by cConfig.php
		,jr_uploadUrl:			'content/uploads'		// upload directory, supplied by cConfig.php
		,jr_editorLevel:		'220'			// minimum userlevel for usage of editor (see cConfig.php)
		,jr_webmasterLevel:		'999'			// will be supplied by cConfig.php  
		//,jr_xinhaContentCss:	'src/css/xinha.css' // special styles of xinha	
			
		,jr_langTxt:			{}				// deprecated, not used
    											// replaced by central hash table (see API)
    											// = objects which holds the help texts are loaded =
		,jr_langLoaded: 		false			// used to identify the successfully loading
		,jr_srcUrl:				'src/'			// script directory as relative dir will be converted to url
		,jr_pluginsUrl:			'plugins/'		// plugins directory as relative dir will be converted to url
		,jr_assetsUrl:			'assets/'		// directory of 3rd party software
		,jr_divMain:			'divMain'		// Main frame = content
		,jr_divLogin:			'divLogin'		// frame of Login/Logout dialog
		,jr_divHMenu:			'divHMenu'		// frame of Horizontal Menu
		,jr_divVMenu:			'divVMenu'		// frame of Vertical Menu
		,jr_divRMenu:			'divRMenu'		// frame of Right Menu
		,jr_showRMenu:			'.hideswitch'	// used to control visibility in case of different style frames
		,jr_divPupMenu:			'divPupMenu'	// frame of PopUp Menu
		,jr_divButtons:			'divButtons'	// frame of task buttons/icons
		,jr_divButtonsWrap:		'divRTMenu'		// wrapping frame of buttons
		,jr_showButtonsWrap:	'.hideswitch'  	// used to control visibility of wrapping frame
		,jr_divRContent:		'divRMenu'		// frame of Right Content
		,jr_divRContentWrap:	'.hideswitch'	// wrapping frame of right content 
		,jr_divWindowSize:		'divWindowSize'	// special div for frame sizing
		,jr_divVersion:			'divVersion'	// special div for version information
		,jr_divGrid:			'divGrid'		// area of omnigrid
		,jr_divHelp:			'divHelp'		// help frame
		,jr_thumbSubDir:		'.thumbs'		// thumb directory, when uploading
		,jr_divRightDisplay:	'block'			// default setting of right element
			
		,jr_firebugConsole:		true			// logs into console of FireFox
		,jr_histDebug:			false			// ajax history debugging
		,jr_histEnabled:		true			// ajax enable ajax history (jrCmsRsh)
		,jr_histBackId:			0				// ajax history back unique id (0 / <id>)
												// if unequal to 0 a back event try to call this method (id)

		,jr_types: 				['ajax'			// as information only, not yet used
		           				 ,'alink'
		           				 ,'apage'
		           				 ,'aeditor'
		           				 , 'js']
		           				 
		,jr_buttonType:			undefined		// undefined = 'icon', 'button', 'iconText'
												// up to now a hidden feature, set via pre_load_images at
												// at the server
		           				 
		,jr_dbischanged:		false			// TODO: flag to identify sitemap relevant changes
		,jr_base64:				false			// Base64 coding true/false of parameter
												// will be set to true during init sequence w/o debugging mode
		           								// but not for IE <7

		,jr_user_pw:			false			// true userid = pw while creating user

		,jr_initParam:			new Object()	// variable for initial parameter
		,jr_maintLevel:			'444'			// admin userlevel used while reloading
		,jr_maintParam:			new Object()	// variable for maint. parameter
		,jr_projURL:			'localhost'		// supplied by CONFIG.PHP
		,jr_ie_version:			0				// IE version determined during startup
		,jr_ie_bug:				false			// special processing for IE required
		,jr_lowspeed:			false			// indicating a low speed line, used e.g. in history
		,jr_loadPage:			true			// setting control loading of first content
		,jr_spinnerOptions:{					// see mootools doc for other options
	          	containerPosition:{
					 position:'upperRight'
	        	 	,offset: {x:-34,y:10}
		 }}
		,jr_spinnerTarget:		undefined		// for project specific settings (default divMain)
    };
	
	JRCmsApi.implement({

		/* ==================================================================== */
		/* CMS API: LOGGING API                                                 */
		/* ==================================================================== */

        /**
		 * calls jrCmsRsh.addHP if exist
		 * 
		 * @param string logtxt, integer level 
		 * @access public
		 */
		jrLog: function(logtxt, level){
			if(((isNaN(this.options.jr_debug))?((this.options.jr_debug)?(1):(0)):this.options.jr_debug) <= 0) 
				return;
			if($defined(window.jrCmsLog)) 
				jrCmsLog.put(logtxt, level);
		}
		
		/* ==================================================================== */
		/* CMS API: Request and Content Processing                              */
		/* ==================================================================== */
		
		/**
		 * generic routine for requests which shall be used to control default settings of the
		 * mootools Request class
		 * 
		 * Additional parameter are:
		 * p.requestType		- control request type {'xml', 'html', 'json', 'form'}, default: 'xml'
		 * p._div				- div element for HTML requests 
		 * p._hp._hpParam		- History point: parameter (new parameter see jrCmsRsh, this.addRequestHP)
		 * p._hp._hpUniqueId	- History point: unique ID of function (new parameter see jrCmsRsh, this.addRequestHP)
		 * p._hp._hpDesc		- History point: description  (new parameter see jrCmsRsh, this.addRequestHP)
		 * 
		 * @param object p 
		 * @access public
		 */

		,processRequest: function(p) {
			
			try{
				if(!$defined(p.data)) throw new Error('processRequest without data called!');
				// delay request for IE
				if(this.options.jr_ie_bug && this._delayProcessRequest) {
					//DEBUG: this.jrLog('T:2#>> processRequest delayed for: '+($defined(p.data)?p.data.a:'undefined')+' ('+p.requestType+')' , 2);
					this.processRequest.delay(200, this, p);
				} else if(this.options.jr_ie_bug) {
					this._delayProcessRequest = true;
					(function(){this._delayProcessRequest = false;}).delay(200, this);
				}
				if(!$defined(p.requestType)) p.requestType = 'xml';
				// merge the default settings with the provided parameter
				// due to dynamic values the the spinner couldn't 
				// be defined in the default settings
				// the spinner will be not used during startup to prevent 
				// a clash with the startup spinner
				var reqP = $merge( {jr_useSpinner: (!$defined(this._showFrameLoadingSpinner)?true:false)
									,spinnerOptions: this.options.jr_spinnerOptions
									,spinnerTarget: ($defined(this.options.jr_spinnerTarget)
													 ? this.options.jr_spinnerTarget
													 : this.options.jr_divMain)
									}, p);
				reqP.spinnerOptions.message = this.getLangItem('reqspinner_msg');
				
				// define the request specific parameter
				switch( reqP.requestType.toLowerCase()) {
				case 'form':
				case 'html':
					reqP = $merge(
								reqP,	
								{evalResponse: false, // we will processed itself
								onSuccess: 
									(!$defined(reqP.onSuccess)
										? function(responseTree, responseElements, responseHTML, responseJavaScript) {
											var osp = $merge(reqP.data);	//take a copy
											this.writeContentHTML(
												//combine splitted scripts and content
												$defined(responseJavaScript)
													? '<script type="text/javascript">'+responseJavaScript+'</script>'+responseHTML 
													: responseHTML,
												//set parameter
												{'divCont' : osp._div
												 ,'postMainFunc' : ($defined(osp.successHandler)?(osp.successHandler):null)
												 ,'noEditor' : true});
										  }.bind(this)
										: reqP.onSuccess)
								});
					break;
				case 'json':
					reqP = $merge(
								reqP,
								{onSuccess:
									(!$defined(reqP.onSuccess)
										? function(parmObject){
											this.getContent(parmObject);
										  }.bind(this)
										: reqP.onSuccess)
								});
					break;
				case 'xol':
					reqP = $merge(
							reqP,
							{onSuccess: 
								(!$defined(reqP.onSuccess)
									? function(txt, xmldoc, xol){
										var osp = $merge(reqP.data);	//take a copy
										this.processXolContainer(xol
												,$merge(osp
														,{'postMainFunc' : ($defined(osp.successHandler)?(osp.successHandler):null)}));
									  }.bind(this)
									: reqP.onSuccess)
							});
					break;
				default:	//xml
					reqP = $merge(
							reqP,
							{onSuccess: 
								(!$defined(reqP.onSuccess)
									? function(txt, xmldoc){
										var osp = $merge( reqP.data 	//take a copy
														 ,{'postMainFunc' : ($defined(reqP.data.successHandler)
																 			 ? (reqP.data.successHandler)
																 			 : null)});
										// update content only, other requests should use XOL
										if (xmldoc.getElementsByTagName("conthtml").length > 0)  
											if($type(p.contMainFunc)=='function') 
												osp.contMainFunc(xmldoc.getElementsByTagName("conthtml")[0].firstChild.data);
											else 
												this.writeContentHTML(xmldoc.getElementsByTagName("conthtml")[0].firstChild.data, osp);
										else
											this._contentLoadedOnce = true;
									  }.bind(this)
									: reqP.onSuccess)
							});
					break;
				}
				
				// send request
				if (p.requestType.toLowerCase()!= 'form') {
					((p.requestType.toLowerCase()=='xml')
						? (new Request(reqP))
						: ((p.requestType.toLowerCase()=='html')
						    ? (new Request.HTML(reqP))
							    : ((p.requestType.toLowerCase()=='xol')
								    ? (new Request.XOL(reqP))
							    	: (new Request.JSON(reqP))))).send();
				
				} else {
					reqP.data.set('send', $merge(reqP,{data:undefined}));
					reqP.data.send();
				}
				
			} catch(err) {
				this.jrLog('F#>> processRequest fail: '+err);
			}
		}

		/**
		 * central routine for reloading/refreshing the page
		 *
		 * @param string $sel
		 * @access public
		 */

		,reloadPage: function( sel ) {

			if( !$defined(sel)) sel = "home";
			switch (sel) {
			case 'page': 
						this.jrLog(">>>> jrCMS page refresh <<<<");
						self.location.reload();
						break;
			case 'home':
						if(!$defined(this._reloadPageCalled) && window.location.hash.search(/\?/) > 0){
							this._reloadPageCalled = true;
							var newLoc = (window.location.hash.search(/\#/) == 0)
											 ? (_getContentForNodeId+window.location.hash.substring(window.location.hash.search(/\?/)))
											 : (window.location.hash);
							this.jrLog(">>>> jrCMS loading with hash: "+newLoc+" <<<<");
	 						this.change(newLoc);
						} else {
							this.jrLog(">>>> jrCMS load/reload home page<<<<");
							//call the first content routine
							if (!jrCMS.accessRights(jrCmsInit.getUserLevel(), jrCmsInit.options.jr_maintLevel)){
								if(this.options.jr_histEnabled)
									this.execHP({uniqueId:_getContentForNodeId, 
												parameter:JSON.encode(jrCmsInit.options.jr_initParam)});
								else
									//try to execute standard content
									jrCMS.getContentForNode(jrCmsInit.options.jr_initParam);
							} else {
								if(this.options.jr_histEnabled)
									//to ensure loading of horizontal menu, the getContentForNode must be called in every case								
									this.execHP({uniqueId:_getContentForNodeId,
												parameter:JSON.encode(jrCmsInit.options.jr_maintParam)});
								else
									//try to execute standard content
									jrCMS.getContentForNode(jrCmsInit.options.jr_maintParam);
							}
						}
						break;
			default:
						// reload location from scratch
						this.jrLog(">>>> jrCMS page reload <<<<");
						this.historyStorageReset();
						self.location.href = jrCmsInit.options.jr_projURL;
						this.change.delay(50,this);
			}			
		}
		
		/**
		 * general routine which processes a XML container converted to an object in a standard
		 * or enhanced manner
		 * 
		 * Standard: container is processed by using default settings
		 * Enhanced: container processing could be controlled by 
		 * p.contMainFunc			- function to be called for processing of main content <default = writeContentHTML>
		 * p.contRightFunc			- function to be called for processing of main content <default = undefined>
		 * p.postMainFunc			- function to be called after setting main content <default = undefined>
		 * p.postMenuFunc			- function to be called after setting menu content <default = undefined>
		 * p.divMenu				- div element of (menu) area to be updated <default = options.jr_divMenu> 
		 * p.divCont				- div element of (main) area to be updated <default = options.jr_divMain> 
		 * p.divContClear			- div element of (main) area will be cleared first <default = false>
		 * p.divCtrl				- div element of button area to be updated <default = options.jr_divButtons>
		 * p.divCtrlWrap			- wrapping div element of button area <default = options.jr_showButtonsWrap>
		 * p.showCtrl				- used in case of different styles <default = jr_showButtonsWrap> 
		 * p.divRightCont			- div element of right area to be updated <default = options.jr_divRContent>
		 * p.divRightContWrap		- wrapping div element of right area <default = jr_divRContentWrap>
		 * p.divRightDisplay	- display property of right area {block,none} <default = display:block>
		 * 
		 * @param object xol, object p 
		 * @access public
		 */
		,processXolContainer: function(xol, p){
			
			var rightFrame = false;
			if(!$defined(p)) var p = new Object();
			
			// 1) update the style
			if($defined(xol.cssdata))
				this.writeCssData(xol.cssdata);
			
			// 2) update menue
			if($defined(xol.menus))
				xol.menus.each(function(menu, index){
					switch (menu.menudiv) {
					case this.options.jr_divHMenu:
						//TODO: ???
						if($defined($(this.options.jr_divHMenu)))
							//update horizontal menu
							rightFrame = this.writeMenuHTML( menu.menuhtml,
															{divMenu:this.options.jr_divHMenu});
						else {
							this.jrLog('F#>> processXolContainer element: '+this.options.jr_divHMenu+' not available !!!');
							//try to restart (to prevent deadlock only 'page' is used)
							window.jrCMS.reloadPage('page');
						}
						break;
					case this.options.jr_divVMenu:
						//TODO: there seems to be a problem while using reloadPage
						//it could happen that the reload is faster that the DOM is
						//ready again, therefore I check for presence of element and
						//perform a site refresh in case of problems.
						//Sure, we need a better solution.
						//Second part of intermediate solution is a delay in reloadPage(ALL)
						if($defined($(this.options.jr_divVMenu)) && ($(this.options.jr_divVMenu).get('html') == "" || this.options.jr_refreshVMenu)) 
							//update vertical menu
							this.writeMenuHTML( menu.menuhtml,
												{divMenu:this.options.jr_divVMenu, 
												 divRightDisplay: ($defined(p.divRightDisplay)
														 ? p.divRightDisplay 
														 : this.options.jr_divRightDisplay)
												 });
						else {
							this.jrLog('F#>> processXolContainer element: '+this.options.jr_divVMenu+' not available !!!');
							//try to restart (to prevent deadlock only 'page' is used)
							window.jrCMS.reloadPage('page');
						}
						break;
					case this.options.jr_divRMenu:
						//TODO: same as above
						if($defined($(this.options.jr_divRMenu)))
							//update right menu
							rightFrame = this.writeMenuHTML( menu.menuhtml,
															{divMenu:this.options.jr_divRMenu});
						else {
							this.jrLog('F#>> processXolContainer element: '+this.options.jr_divRMenu+' not available !!!');
							//try to restart (to prevent deadlock only 'page' is used)
							window.jrCMS.reloadPage('page');
						}
						break;
					}
				}.bind(this));
			
			// 3) update task buttons
			if($defined(xol.ctrlhtml)) {
				//write&show task buttons
				this.writeButtonsHTML(xol.ctrlhtml);
				rightFrame = true;
			} else
				//hide the task button frame
				this.hideFrame((($defined(p) && $defined(p.divCtrl))?(p.divCtrl):(this.options.jr_divButtons)));

			// 4) update content
			if($defined(xol.conthtml)) 
				if($type(p.contMainFunc)=='function') 
					p.contMainFunc(xol.conthtml);
				else 
					this.writeContentHTML(xol.conthtml, p);
			else
				this._contentLoadedOnce = true;

			// 5) update right content (only alternatively to right menu
			if($defined(xol.rightconthtml)) {
				if($type(p.contRightFunc)=='function') 
					p.contRightFunc(xol.rightconthtml);
				else 
					this.writeRightContentHTML(xol.rightconthtml, p);
			} else if(!rightFrame)
				if(($defined(p.divRightDisplay) && p.divRightDisplay == 'none') || this.options.jr_divRightDisplay == 'none')
					this.hideFrame(($defined(p.divRightContWrap)?(p.divRightContWrap):(this.options.jr_divRContentWrap)));
			
			// 6) if a dialog is supplied process content data
			if($defined(xol.contdata) && $defined(xol.contdata.dlgoptions)) {
				this.writeDialog(
						xol.contdata
						,$merge(xol.contdata.dlgoptions,{'dlgText': this.getLangItemSet()}));
			}

			this.jrLog('T:2>> processXolContainer finished', 2);
		}
		
		/**
		 * routine to post the content of a sitemap in the main frame
		 * 
		 * p.postMainFunc	- function to be called after setting the content <default = undefined>
		 * p.divCont		- div element of area to be updated <default = options.jr_divMain>
		 * p.anchor			- anchor element within the text to be focused on
		 * p.noEditor 		- do not call the editor <default = false>
		 * 
		 * @param string $strHtml, object $p
		 * @access public
		 */
		,writeContentHTML: function(strHtml, p){
			try {
				
				//for debugging only 
				//this.jrLog('T:3>> writeContentHTML.strHtml: '+strHtml.replace(/<\/?[^>]+(>|$)/g, "").substr(0, 120), 3);
				//check parameters
				if(!$defined(p.divCont) || !$defined($(p.divCont)))
					p.divCont = this.options.jr_divMain;
				if(!$defined(p.noEditor)) 
					p.noEditor = false;
				//combine strHtml and p
				p.strHtml = strHtml;
				
			    p.imgArray = p.strHtml.match(/<img[^>]*>/g);
			    if($defined(p.imgArray) && p.imgArray.length > 0) {
		 			//to ensure re-entrance a copy of parameter object has to be used
			    	this.loadImagesAndWriteContent.delay(5,this,$merge(p));
			    } else {
			    	this.writeContent(p);
			    }
			} catch (err) {
				var e = ' writeContentHTML: '+err;
				if(this.options.jr_debug)	throw new Error(e); 
			}
		}

		/**
		 * routine to post the right content of a sitemap in the right frame
		 * 
		 * @param string $strHtml, object $p
		 * @access public
		 */
		,writeRightContentHTML: function(strHtml, p){
			try {
				//for special traces
				//this.jrLog('T:3>> writeRightContentHTML.strHtml: '+strHtml.replace(/<\/?[^>]+(>|$)/g, "").substr(0, 120), 3);

				//prevent double processing of post routine
				p.postMainFunc = undefined;
				//prohibit call of editor for the right frame
				p.noEditor = true;
				p.divCont = ($defined(p.divRightCont))?(p.divRightCont):(this.options.jr_divRContent);
				//ensure visibility of wrapping frame
				this.showFrame((($defined(p.divRightContWrap))?(p.divRightContWrap):(this.options.jr_divRContentWrap)));
				//as well as visibility of right content frame
				this.showFrame(p.divCont);
				//write the content
				this.writeContentHTML(strHtml,p);

			} catch (err) {
				var e = ' writeRightContentHTML: '+err;
				if(this.options.jr_debug)	throw new Error(e); 
			}
		}

		/**
		 * retrieve a HTML content to be displayed in Main frame, 
		 * the content could contain javascript and styles sequences.
		 * 
		 * The parameter has to be provided as object like {div:divMain}
		 * 
		 * @param object $p, function $ftype
		 * @access public
		 * @deprecated
		 */
		,getHTML: function (p, func, a_sync){
			
			try{
				
				if($type(p)=='object' && $defined(p._src) && $defined(p._div)) {
					
					this.processRequest({
						//build up request parameters
						async: ($defined(a_sync) ? a_sync : true),
						successHandler: (($type(func)=='function')?func:undefined),
						requestType: 'html',
						link: 'chain',
						//due to compatibility reasons
						url: p._src,
						data: p
					});

				} else {
					var e = ' getHTML with wrong parameter called';
					if(this.options.jr_debug)	throw new Error(e); 
				}

			} catch (err) {
				var e = ' getHTML: '+err;
				if(this.options.jr_debug)	throw new Error(e); 
			}
		}
		
		/* ==================================================================== */
		/* CMS API: AJAX HISTORY API                                            */
		/* ==================================================================== */

		/**
		 * fills the source pool of the ajax history, and ensures proper processing
		 * in case of parallel requests
		 * 
		 * parameter is an object of following structure:
		 *
		 * 	   {instance: <instanceName>,
		 *		classId: <classId>,
		 *		functions: [{functionName: <functionName>, methodId: <methodId>, functionType: <functionType>}]}
		 *		
		 * @param object 
		 * @access public
		 */
		,registerFunctions: function(p) {
			
			if(!$defined(p) || $type(p) != 'object') throw new Error('registerFunctions with wrong parameter called!');
			
			if(this.options.jr_histEnabled) {
			
				//prevent collisions due to parallel requests and ensure proper state of DOM
				if(!$defined(window.jrCmsRshSource) || window.jrCmsRshSource.addSourcePoolEntered) {
		 			//to ensure re-entrance a copy of parameter object has to be used
					this.registerFunctions.delay(50,this,$merge(p));
					//DEBUG: this.jrLog('T:4#>> registerFunctions (jrCmsRshSource.add) wait for  '+ p.instance +'!',4);
					return false;
				}
				//DEBUG: this.jrLog('T:4#>> registerFunctions (jrCmsRshSource.add) for '+ p.instance +' starting now!',4);
				
				jrCmsRshSource.add(p);
				
				this.jrLog('T:4#>> registerFunctions (jrCmsRshSource.add) for '+ p.instance +' finished!',4);
			}
			if($defined(p.successHandler) && $type(p.successHandler)=='function') 
				p.successHandler.run();
			
		}
		
		/**
		 * returns an object containing the history informations,
		 * which could be used by an additional Request parameter
		 * of jrCmsRsh
		 * 
		 * @param string uniqueId, object param, string desc 
		 * @access public
		 */
		,addRequestHP: function(uniqueId, param, desc){
			
			if(this.options.jr_histEnabled && $defined(window.jrCmsRsh))
				return jrCmsRsh.addRequestHP(uniqueId, param, desc);
			else
				return null;
		}

		/**
		 * @deprecated
		 * calls jrCmsRsh.addHP if exist
		 * --
		 * shouldn't be used anymore, because the history will be called 
		 * inside request object of mootools
		 * --
		 * 
		 * @param string uniqueId, object param, string desc, function func 
		 * @access private
		 */
		,addHP: function(uniqueId, param, desc, func){
			
			if(this.options.jr_histEnabled && $defined(window.jrCmsRsh))
				return jrCmsRsh.addHP(uniqueId, param, desc, func);
			else
				return false;
		}
		
		/**
		 * calls jrCmsRsh.execHP if exist
		 * 
		 * @param object p
		 * @access public
		 */
		,execHP: function(p){
			
			if(this.options.jr_histEnabled && $defined(window.jrCmsRsh))
				return jrCmsRsh.execHP(p);
			else
				return false;
		}

		/**
		 * calls jrCmsRsh.change if exist
		 * 
		 * @param string newLoc, string histData
		 * @access public
		 */
		,change: function(newLoc, histData){
			
			if(this.options.jr_histEnabled && $defined(window.jrCmsRsh))
				return jrCmsRsh.change(newLoc, histData);
			else
				return false;
		}

		/**
		 * calls historyStorage.reset if exist
		 * 
		 * @param none
		 * @access public
		 */
		,historyStorageReset: function(){
			
			if(this.options.jr_histEnabled && $defined(window.historyStorage))
				return historyStorage.reset();
			else
				return false;
		}
		
		/* ==================================================================== */
		/* CMS API: Files Access                                                */
		/* ==================================================================== */
		
		/**
		 * routine which loads a javascript files and ensure that the files are loaded only once.
		 * The file names could be defined by camel case identifier which will be internally
		 * converted to lower cases.
		 * 
		 * jsfiles		- array of files
		 * 				  default = [{'jsfile':'example.js','path': '..', 'loadfunc': $lambda()}]
		 * 			or	- single object, e.g.
		 * 							{'jsfile':'exampple.js','path': '..', 'loadfunc': $lambda()}
		 */
		,loadScriptFiles: function(srcfiles){
			try{
				var jf = new Array();
				if($type(srcfiles) == 'object') {
					jf.push(srcfiles);
				} else {
					jf = $A(srcfiles);
				}
				jf.each(function(itemjf, index){
					var sf = this.getUniqueScriptId(itemjf.jsfile.substring(0, itemjf.jsfile.lastIndexOf('.')));
					if($chk($$('script.'+sf)[0]))
						$$('script.'+sf)[0].dispose();
					//load the javascript file
					var asset = new Asset.javascript((itemjf.path+itemjf.jsfile), {
													'class': sf
													,onload: ($defined(itemjf.loadfunc)
															 ? itemjf.loadfunc
															 : function(){return true;})
						});
				}.bind(this));
			} catch (err) {
				var e = ' loadScriptFiles: '+err;
				if(this.options.jr_debug)	throw new Error(e); 
			}
		}

		/**
		 * routine which loads a list of style files and ensure that the file is only
		 * loaded once.
		 * Per convention special IE6 style files must be placed at the bottom of a list and
		 * shall contain an 'IE'. Furthermore style files of plugins should get as file name
		 * the class name (camel case) which will internally converted to lower case.
		 * 
		 * cssfiles		- array of style files
		 * 				  default = [{'cssfile':'layout.css','path': this.options.jr_projURL+'css/'}
		 * 							,{'cssfile':'navigation.css','path': this.options.jr_projURL+'css/'}
		 * 							,{'cssfile':'content.css','path': this.options.jr_projURL+'css/'}
		 * 							,{'cssfile':'patchIE6.css','path': this.options.jr_projURL+'css/'}]
		 * 			or	- single object, e.g.
		 * 							{'cssfile':'patchIE6.css','path': this.options.jr_projURL+'css/'}
		 */
		,loadStyleFiles: function(cssfiles){
			try{
				var cf = new Array();
				if(!$defined(cssfiles)) {
					//default style files.
					//as explained in the internet the usage of @import url(layout.css); in a global styles file  
					//is much more slower than loading of single styles therefore the general style files is loaded here
					cf = [{'cssfile':'layout.css','path': this.options.jr_srcUrl+'css/'}
					     ,{'cssfile':'navigation.css','path': this.options.jr_srcUrl+'css/'}
					     ,{'cssfile':'content.css','path': this.options.jr_srcUrl+'css/'}
					     ,{'cssfile':'patchIE6.css','path': this.options.jr_srcUrl+'css/'}];
				} else if($type(cssfiles) == 'object') {
					cf.push(cssfiles);
				} else {
					cf = $A(cssfiles);
				}
				cf.each(function(itemcf, index){
					if((itemcf.cssfile.search(/IE/) != -1 && this.options.jr_ie_bug) ||
							itemcf.cssfile.search(/IE/) == -1	) {
						var sf = this.getUniqueStylesFileId(itemcf.cssfile.substring(0, itemcf.cssfile.lastIndexOf('.')));
						if($chk($$('link.'+sf)[0]))
							$$('link.'+sf)[0].dispose();
						//load the style file
						var asset = new Asset.css((itemcf.path+itemcf.cssfile.toLowerCase()), {
													'class': sf
						});
					}
				}.bind(this));
				
			} catch (err) {
				var e = ' loadStyleFiles: '+err;
				if(this.options.jr_debug)	throw new Error(e); 
			}
		}
		
		/**
		 * pre-load images with prefix to show first page complete or
		 * callable with an image list and post processing function
		 *
		 * Optional parameter
		 * p.imgArray		- array of images (correct path)
		 * p.onComplete		- post processing function
		 * 
		 * @param object p 
		 * @access public
		 */
		,preLoadImages: function(p) {
			try{
				if(!$defined(p)) {
					var p = new Object();
					p.a = 'pldimg';
					p.ipp = $defined(this.options.jr_imgPreloadPrefix)?this.options.jr_imgPreloadPrefix:'prl';
					if($defined(this.options.jr_buttonType))
						p.taskType = this.options.jr_buttonType;
	
					this.processRequest({
						requestType: 'xol',
						url: this.options.jr_srcUrl+'jrcms.php',
						data: p,
//						async: false, //that must be an sync request
						onSuccess: function(resp, xml, xol){
							p.imgArray = new Array();
							//convert the object in an array
							xol.img.each(function(item, index){
								p.imgArray.push(item.src);
							}.bind(this));
					    	this._preloadedImages = new Asset.images(p.imgArray,{
				    			onComplete: (!$defined(p.onComplete)
												? function(parmObject){
													this.jrLog('T:2#>> preLoadImages finished!',2);
												  }.bind(this)
												: p.onComplete),
								onError: function(){
				    						this.jrLog('F#>> preLoadImages.AssetImages Failure !!!');
		    							}.bind(this)});
							
						}.bind(this)
					});
				} else {
			    	this._preloadedImages = new Asset.images(p.imgArray,{
			    			onComplete: (!$defined(p.onComplete)
											? function(parmObject){
												this.jrLog('T:2#>> preLoadImages finished!',2);
											  }.bind(this)
											: p.onComplete),
							onError: function(){
			    						this.jrLog('F#>> preLoadImages.AssetImages Failure !!!');
	    							}.bind(this)});
				}
			} catch(err) {
				this.jrLog('F#>> preLoadImages fail: '+err);
			}
		}

		/* ==================================================================== */
   		/* CMS API: Internationalization / Language Support                     */
   		/* ==================================================================== */

		/**
		 * Retrieve the whole set of available language items
		 * 
		 * @access public
		 */
		,getLangItemSet: function(){
			return window.document.retrieve('jr_langTxt')||(new Object());
		}

		/**
		 * Provide the language specific text of an item
		 * 
		 * @access public
		 */
		,getLangItem: function(itendifier){
			var jr_langTxt = this.getLangItemSet();
			return $defined(jr_langTxt[itendifier])?jr_langTxt[itendifier]:'';
		}
		
		/**
		 * internationalization by loading i18n constants
		 * the file shall contain an object {'id':'description'}
		 * calling by
		 * 	filePath:	relative/absolute path, e.g. 'lang', 
		 *  fileName:   filen name, e.g. this.options.jr_lang+'.i18n'
		 *  successHandler
		 * 
		 * @param string filePath, string fileName, function successHandler 
		 * @access public
		 */
		,retrieveLangFile: function(filePath, fileName, successHandler) {
			try{
				var p = new Object();
				p.a = 'getLangFile';
				p.fn = filePath + fileName;
				
				this.processRequest({
					requestType: 'xol',
					url: 'src/jrcms.php',
					method: 'get',
//					async: false, //that must be an sync request
					data: p,
					onSuccess: function(resp, xml, i18n){
						if($type(i18n)=='object') {
							window.document.store('jr_langTxt', $merge(i18n, this.getLangItemSet()));
						} else {
							this.jrLog('F#>> retrieveLangFile failed for: '+($defined(this._pluginInfo)?(this._pluginInfo.name+': '+fileName):(fileName))+' !');
						}
						if($type(successHandler)=='function') successHandler.run();
					}.bind(this)
				});
				
			} catch(err) {
				this.jrLog('F#>> retrieveLangFile fail: '+err);
			}
		}

   		/* ==================================================================== */
   		/* CMS API: access control                                              */
   		/* ==================================================================== */
     	
   		/**
   		 * The userlevel of the request will be compared with the level
   		 * required for the task (accessTyp)
   		 *  
   		 * Attention: a similar function 'writeAccess' exist in PHP
   		 *
   		 * @access public
   		 */
   		,accessRights: function( ulOfRequest, ulRequired, accessType){
   		 	//check for optional access type
   		 	if(!$defined(accessType)) accessType = 'default';
   		 	switch (accessType) {
   		 	case "read":
   				return this.readRights(ulOfRequest, ulRequired);
   				break;
   			case "write":
   				return this.writeRights(ulOfRequest, ulRequired);
   				break;
   			case "create":
   				return this.createRights(ulOfRequest, ulRequired);
   				break;
   			default:
   				//each given level must fit
   				return (this.readRights(ulOfRequest, ulRequired) && 
   						this.writeRights(ulOfRequest, ulRequired) &&
   						this.createRights(ulOfRequest, ulRequired));
   			}
   			return false;
   		}
     	
   		/**
   		 * check for write access
   		 */
   		,writeRights: function( ulOfRequest, ulRequired){
   		 	ulOfRequest.trim();ulRequired.trim();
   		 	if(ulOfRequest.length < 3 || ulRequired.length < 3) 
   		 		throw new Error('writeRights with wrong parameter called!');	 		
   			return ((ulOfRequest.substr(1,1).toInt() >= ulRequired.substr(1,1).toInt()) && ulOfRequest.substr(1,1).toInt() > 0);
   		}

   		/**
   		 * check for read access
   		 */
   		,readRights: function( ulOfRequest, ulRequired){
   		 	ulOfRequest.trim();ulRequired.trim();
   		 	if(ulOfRequest.length < 3 || ulRequired.length < 3) 
   		 		throw new Error('readRights with wrong parameter called!');	 		
   			return (ulOfRequest.substr(0,1).toInt() >= ulRequired.substr(0,1).toInt());
   		}
     		
   		/**
   		 * check for create access
   		 */
   		,createRights: function( ulOfRequest, ulRequired){
   		 	ulOfRequest.trim();ulRequired.trim();
   		 	if(ulOfRequest.length < 3 || ulRequired.length < 3) 
   		 		throw new Error('createRights with wrong parameter called!');	 		
   			return ((ulOfRequest.substr(2,1).toInt() >= ulRequired.substr(2,1).toInt()) && ulOfRequest.substr(2,1).toInt() > 0);
   		}
   		
   		/* ==================================================================== */
   		/* CMS API: Menu and Buttons processing                                 */
   		/* ==================================================================== */
     		
		/**
		 * routine to post the Menu in the menu frame
		 * 
		 * @param string $menuHtml, object $p
		 * @access public
		 */
		,writeMenuHTML: function(menuHtml, p){
			try {
				//for special traces
				this.jrLog('T:3>> writeMenuHTML.menuHtml: '+menuHtml.replace(/<\/?[^>]+(>|$)/g, "").substr(0, 120), 3);
	
				if(!$defined(p)) var p = new Object();
//				if(!$defined(p.divMenu)) p.divMenu = this.options.jr_divVMenu;
//				if(!$defined(p.divRightDisplay)) p.divRightDisplay = 'block';
				//default settings
				p = $merge({ 'divMenu':this.options.jr_divVMenu
							,'divRightDisplay':'block'}, p);
				//first execute included scripts
				menuHtml.stripScripts(true);

				//consider special processing in case of right menu
				if ((p.divMenu != this.options.jr_divRMenu) ||
					(p.divMenu == this.options.jr_divRMenu &&  $defined($(this.options.jr_divRMenu)) && 
				     $(this.options.jr_divRMenu).get('html').indexOf('<ul>') > -1 && menuHtml == ""   ) ||
				    (p.divMenu == this.options.jr_divRMenu && menuHtml != "")){
				
					$(p.divMenu).empty().set('html', menuHtml);
					$(p.divMenu).scrollTop = $(p.divMenu).scrollHeight;
					
					//determine visibility of style elements
					if (((p.divMenu == this.options.jr_divVMenu || p.divMenu == this.options.jr_divHMenu) && p.divRightDisplay == 'none') ||
						(p.divMenu == this.options.jr_divRMenu && menuHtml == '' && p.divRightDisplay == 'none')) 
							this.hideFrame((($type(this.options.jr_showRMenu))?(this.options.jr_showRMenu):(this.options.jr_divRMenu)));
						else this.showFrame((($type(this.options.jr_showRMenu))?(this.options.jr_showRMenu):(this.options.jr_divRMenu)));
	
					//if provided call a function
					if($type(p.postMenuFunc)=='function') p.postMenuFunc.run();
					
					//menu updated
					return true;
	
				}
				//no updates done
				return false;
				
			} catch (err) {
				var e = ' writeMenuHTML: '+err;
				if(this.options.jr_debug)	throw new Error(e); 
			}
		}
	
		/**
		 * routine to post the Buttons in a frame
		 * 
		 * @param string $ctrlHtml, object $p
		 * @access public
		 */
		,writeButtonsHTML: function(ctrlHtml, p){
			try {
				//for special traces
				this.jrLog('T:3>> writeButtonsHTML.ctrlHtml: '+ctrlHtml.replace(/<\/?[^>]+(>|$)/g, "").substr(0, 120), 3);
	
				if(!$defined(p)) var p = new Object();
				//ensure visisbiliy of wrapping frame
				this.showFrame((($defined(p.showCtrl))?(p.showCtrl):(this.options.jr_showButtonsWrap)));
				//control default setting
				if(!$defined(p.divCtrl)) p.divCtrl=this.options.jr_divButtons;   
				
				if($defined(ctrlHtml)) {
					//check for existing button frame
					if (!$(p.divCtrl)){
						// set up the button frame
						var buttonDiv = new Element('div', { id: p.divCtrl });
						$(($defined(p.divCtrlWrap)?(p.divCtrlWrap):(this.options.jr_divButtonsWrap))).grab(buttonDiv);
					}
					//show the button frame
					this.showFrame(p.divCtrl);
					//write the content of button frame		
					$(p.divCtrl).set('html', ctrlHtml);
				}
			} catch (err) {
				var e = ' writeButtonsHTML: '+err;
				if(this.options.jr_debug)	throw new Error(e); 
			}
		}

   		/* ==================================================================== */
   		/* CMS API: Styles processing                                           */
   		/* ==================================================================== */
     		
		/**
		 * 
		 */
		,writeCssData: function(cssData){
			
			try {
				//for special traces
				this.jrLog('T:3>> writeCssData.cssData: '+cssData.mnu_css.substr(0, 10), 3);
		
				// process the styles
				if( $defined(cssData.mnu_css) && cssData.mnu_css != "none") {
						this.writeCSS(cssData.mnu_css);
				}
				// ### new meta description ###
				if( $defined(cssData.mdesc) && cssData.mdesc != "none") {
					var meta = $$('meta[name=description]');
					meta[0].set('content',cssData.mdesc);
				}
				// ### new meta keywords ###
				if( $defined(cssData.mkey) && cssData.mkey != "none") {
					var meta = $$('meta[name=keywords]');
					meta[0].set('content',meta[0].get('content')+' '+cssData.mkey);
				}
				
			} catch (err) {
				var e = ' writeCssData: '+err;
				if(this.options.jr_debug)	throw new Error(e); 
			}
		}
	
		/**
		 * apply the properties of a selector
		 * Remark: no space characters are allowed
		 *
		 * @param string sel, string pstr
		 * @access private
		 */
		,cssProperty: function (sel, pstr) {
			try{

				sel = sel.replace(/\#|\./g,'');
				if(sel == "") return false;
				var prop_ext = pstr.replace(/;/g,'').toLowerCase().split(':');
				if($defined($(sel))) {
					$(sel).setStyle(prop_ext[0],prop_ext[1]);
				} else if($defined($$('.'+sel))) {
					$$('.'+sel)[0].setStyle(prop_ext[0],prop_ext[1]);
				} else if($defined($$(sel))) {
					$$(sel)[0].setStyle(prop_ext[0],prop_ext[1]);
				}
				
			} catch (err) {
				var e = ' cssProperty failure: '+err;
				if(this.options.jr_debug)	throw new Error(e); 
	 		}
		}
	
		/**
		 * Public method: writeCSS
		 * write give CSS styles
		 *
		 * @param string cstr
		 * @access private
		 */
		,writeCSS: function (cstr) {
			
			cstr = cstr.replace('/ |\n|\r/g', '');
			var csnip = new Array();
			var carr = cstr.split('}');
			carr.each(function(item, index){
				csnip = item.split('\{');
				this.cssProperty(csnip[0], csnip[1]);
			}.bind(this));
		}

   		/* ==================================================================== */
   		/* CMS API: Help                                                        */
   		/* ==================================================================== */
		
		/**
		 * 
		 * @param none
		 * @access public
		 */
		,getHelpDoc: function(p){
	
			try{
				//defined the parameter object
				if(!$defined(p)) var p = new Object();
				//determine the help caller
				if(!$defined(p.plugin)) p.plugin = this._pluginInfo.name;
				//create the slideing frame for users only
				if(!this.writeRights(this.getUserLevel(), this.options.jr_webmasterLevel)){
					p.helpIFrame = 'ifrHelpContent';
					p.divCont = p.helpIFrame;
					if (!$defined($(this.options.jr_divHelp))){
						//create the help window
						$$('body').grab(
								 (new Element('div', {'id': this.options.jr_divHelp})).grab(
								 (new Element('div', {'class': 'helpTasks'})).grab(
								 (new Element('a', {'id':'helpToggle', 'href':'#'})).grab(
								  new Element('img', {'src':'src/images/help_enabled.gif'}))).grab(
								  new Element('br')).grab(
								 (new Element('a', {'id':'helpClose', 'href':'#'})).grab(
								  new Element('img', {'src':'src/images/close_enabled.gif'})))).grab(
								  new Element('div', {'id': p.helpIFrame})).grab(
								  new Element('div', {'class': 'nf'})));
						var myHelpSlide = new Fx.Slide(p.helpIFrame, {mode: 'horizontal'});
						$('helpToggle').addEvent('click', function(e){
							e.stop();
							myHelpSlide.toggle();
						});
						$('helpClose').addEvent('click', function(e){
							e.stop();
							this.hideFrame(this.options.jr_divHelp);
						}.bind(this));
						this.showFrame(this.options.jr_divHelp);
						myHelpSlide.slideIn();
					} else {
						//existing help window assumed
						this.showFrame(this.options.jr_divHelp);
					}
				}
				p.a = 'getHelpDoc';
				this.processRequest({
					requestType: 'xol',
					url: jrCMS.options.jr_srcUrl + jrCMS.options.jr_phpSRC,
					data: p,
					onSuccess : ((!this.writeRights(this.getUserLevel(), this.options.jr_webmasterLevel))
								? (function(txt, xmldoc, xol){
									this.writeContentHTML(xol.conthtml, p);
									}.bind(this))
								: undefined)	
				});
			} catch(err) {
				this.jrLog("F#>> jrCMS.getHelpDoc failure: "+err);
			}
		}
	
		/**
		 * 
		 * @param none
		 * @access public
		 */
		,saveHelpDoc: function(p){
			
			try{
				if(!$defined(p)) return false;
				//retrieve Editor Content
				p.cont = jrCmsEditor.getXinhaTextArea();
				
				this.processRequest({
					requestType: 'html',
					url: jrCMS.options.jr_srcUrl + jrCMS.options.jr_phpSRC,
					data: p,
					onSuccess: function(responseTree, responseElements, responseHTML, responseJavaScript) {
						if ($defined(responseJavaScript)){
							$exec(responseJavaScript);
						}
					}.bind(this)
				});
			} catch(err) {
				this.jrLog("F#>> jrCMS.saveHelpDoc failure: "+err);
			}
		}

   		/* ==================================================================== */
   		/* CMS API: UserLevel                                                   */
   		/* ==================================================================== */
     		
		/**
		 * set user level, method will be called via <script> tag, 
		 * assigned in cJrcms.php
		 * 
		 * @param ulevel string
		 * @access public
		 */
		,setUserLevel: function(ulevel) {
			//to ensure unique processing we try to set the config/init value
			if($defined(window.jrCmsInit))
				jrCmsInit.setOptions({jr_userLevel:ulevel});
			else
				this.setOptions({jr_userLevel:ulevel});
		}
		
		/**
		 * provides the actual user level
		 */
		,getUserLevel: function() {
			//to ensure unique processing we try to retrieve the config/init value
			if($defined(window.jrCmsInit))
				return jrCmsInit.options.jr_userLevel;
			else
				return this.options.jr_userLevel;
		}
		
   		/* ==================================================================== */
   		/* CMS API: FORMULAR                                                    */
   		/* ==================================================================== */
		
		/* see JRCmsForm */
		
		/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
		
		/**
		 * protected global options
		 */
        ,_globalOptions: _globalOptionsSet
        
		/**
		 * Flag used to control intial loading
		 * @access private
		 */
		,_contentLoadedOnce: false
		
		/**
		 * delayed processing, e.g. for IE6
		 * @access private
		 */
		,_delayProcessRequest: false
		
		/* @access private */
		,_preloadedImages: null
		
		/* @access private */
		,_reloadPageCalled: null
		
		/* @access private */
		,_slideLogin: null
		
		/* @access private */
		,_showFrameLoadingSpinner: null
		
		/**
		 * internal routine
		 * 
		 * @param object $p
		 * @access private
		 */
		,writeContent: function (p) {
			//first execute included scripts
			p.strHtml.stripScripts(true);
			//write content
			$(p.divCont).set('html', p.strHtml);
			if($defined(p.anchor) && $defined($$('a[name="'+p.anchor+'"]')[0]))
				$(p.divCont).scrollTo(0,($$('a[name="'+p.anchor+'"]')[0].offsetTop-4));
			else	
				$(p.divCont).scrollTo(0,0);
			//set loaded flag, will be overwriten each time
			this._contentLoadedOnce = true;
			//if provided call a post processing function
			if($type(p.postMainFunc)=='function') p.postMainFunc.run();
		    // activate the editor
			if(!p.noEditor && $type(window.jrCmsEditor)=='object') jrCmsEditor.activateEditor(p.strHtml);
		}
		
		/**
		 * internal routine
		 * 
		 * @param object $p
		 * @access private
		 */
		,loadImagesAndWriteContent: function (p) {
			p.imgArray = p.imgArray.map(function(itm, index){
				if(itm.search(/src="/)>=0)
					return ((itm.match(/src="[^"]*"/g)[0]).replace(/src="/g,'')).replace(/"/g,'');
				else
					return ((itm.match(/src=[^\s]*/g)[0]).replace(/src=/g,''));
	    	});
			
	    	p.onComplete = function(){
							this.jrLog('T:2#>> loadImagesAndWriteContent finished!',2);
	    					this.writeContent(p);
	    					}.bind(this);
	    	this.preLoadImages(p);	
		
		}

		/**
		 * function to show a menu entry (see cMenu.php), e.g. used by
		 * IE compatibility mode (jr_ie_bug)
		 *
		 * @param string id, array idlst
		 * @access private
		 */
		,showMenuId: function (id,idlst) {
			if($defined(idlst)){
				//deactivate all other first
				idlst.each(function(item, index){
					this.hideMenuId(item);
				}.bind(this));
			}
			//show the Menu Id only
			if($defined($(id))) $(id).show();
		}
		
		/**
		 * function to hide a menu entry
		 *
		 * @param string id
		 * @access private
		 */
		,hideMenuId: function (id) {
			if($defined($(id))) $(id).hide();
		}
		
	}); //implements end
})();

/* ==================================================================== */
/* ==================================================================== */
/**
 * JRCmsForm Class
 * 
 * Class provides methods for unique processing of formulars/dialogs
 * as well as dialog frames (windows).
 * 
 * DialogFrames
 * ============
 * Inspired by the tornlog (http://torntech.com) the functionality provides
 * a dialog frame as standard variant with a menu bar at 'top' or 'left/right'
 * side. The 'top' variant supports the re-sizing and dragging only. The scroller
 * bar could be enabled for 'left/right' via css.
 * Instead of a separate class or extension of mootools the functionality uses 
 * a hash attached to the wrapping element. 
 * For a proper function the styles (see jrcmsform sytsles) must be available 
 * and following conventions apply:
 * 
 * Options set:
 * 
 * 	{ 'dlgText': 	 	- Language Text of values (at least for the buttons
 * 						  'dlgKill', 'dlgHide', 'dlgShow', 'dlgLock, 'dlgUnlock'
 * 						  and for each dialog element name
 *	 ,'dlgFrameStyle': 	- 'width:nn0px;<height:nn0px>'
 *	 ,'dlgButtons':	    - (optional) buttons object each consisting of 
 *						     {<identifier>: function(){<function>}.bind(this)}}
 *                           The <identifier> should correspond to a text element
 *                           defined above 
 *   ,'dlgType': 		- (optional) 'top','left','right' (default: 'top')
 *	 ,'dlgContent':		- (optional) the element Id where the content <data> refer to.
 *						  The element must be a <div> element (default: 'dlg')
 *                        Using this option require an own definition of styles as
 *                        defined for 'dlg'.
 *   ,'dlgParent':		- (optional) anchor element of the frame (default: document.body)
 *   ,'dlgDragable': 	- (optional) true/false enable/disable dragging (default: true)
 *   ,'dlgSizable':		- (optional) true/false enable/disable re-sizing (default: true)
 *   ,'dlgScroller':	- (optional) true/false enable/disable scroller (default: true)
 *   ,'dlgMenu':		- (optional) true/false enable/disable menu bar (default: true)
 *   
 * for writeDialog only:
 *   ,'dlgUseFieldset'	- (optional) true/false enable/disable a wrapping fieldset around 
 *   					  of a dialog formular
 *   ,'dlgUrl'			- specify the path and
 *   ,'dlgSrc'			- the server file for the formular action
 *  }
 *
 * With this options two features are available
 * 
 *  Dialog Frame	Function createDialog write a dialog consisting of menu bar
 *                  and an empty content element. The content element could be 
 *                  accessed via 'dlgContent' as defined above.
 *                  Alternatively a data set as needed for the writeDialog (see 
 *                  below) could be provided and will be written inside
 *                  
 *  Write Dialog	A standardized dialog table is written by the function
 *  				writeDialog in the 'dlgContent' element consisting of two 
 *  				columns.
 *   
 * Write Dialog:
 * =============
 * Assumed is an Json string retrieved and converted to an data object
 * of following structure:
 * 
 * 	header:					as object
 *  	refName				- database reference ID name
 *  	value				- value of the reference
 *  	action				- action string
 *  data:					array of objects, consisting of:
 *  	valueName				- database representation name/id
 *  	value					- value itself
 *  	valueGroup				- dialog group and optional an object
 *  							  if needed for special data
 *  							  e.g. '<title>:<instance>'
 *  							  using an instance require this information
 *  							  for each element
 *  	valueDialogMethod		- dialog type and optional an object 
 *  							  if needed for input and select
 *  							  elements
 *  							  e.g. '<type>:<instance>'
 *  	valueValidator			- define the <validator> of an element
 *  							  e.g. {'none', 'disabled', 'required'}
 *  
 * <title>				- specify the dialog formular, several formulars
 *                        are possible 
 * <types> are:
 *   text				- special type which writes a text over the 
 *                        two columns (row)
 *   input				- html input element (hidden, normal, radio, checkbox
 *   					  password)
 *   select				- html select element
 *   textarea           - html text area
 *   accordion          - accordion function with textareas, only one 
 *                        accordion per formular is supported
 *   textareaEditor		- html text area with integrated Editor
 *   accordionEditor	- accordion as above but with integrated Editor                     
 *  
 * <validator>s are:
 * 	 none				= default, no further processing/validation
 *   disabled			= value could not be changed (read only)
 *   required			= input is required
 *   validate-email		= check the mail format
 *   validate-date		= check the date
 *   validate-integer	= only numeric values allowed
 *   validate-digits	= only numeric values and dots, spaces and underline
 *   validate-alpha		= only letters (a-z)
 *   validate-alphanum	= only letters and numeric without spaces
 *   
 *   Except 'disabled' and 'none' all validators could be combined.
 *   They have to be separated by spaces. 
 * 
 * The data object described above has to be processed by using the 
 * method: writeDialog with the options:
 * 
 *	writeDialog( <data object>,
 *				{'dlgContent': 		- Target Element Id
 *				 ,'dlgText': 		- Language Text of values
 *				 ,'dlgUrl': 		- Url prefix of dialog object
 *				 ,'dlgSrc':         - (opt) server script file
 *				 ,'dlgLeftWidth': 	- (opt) default '100px'
 *				 ,'dlgRightWidth':  - (opt) default '250px'
 *				 })
 *  
 * To complete special types (e.g. select by options)a generic function
 * is provided. This function have to be available in the instance
 * as specified by the valueDialogMethod.
 * 
 *  processDialogValue( el			- will contain the element
 *  								  to be processed
 *  				   ,valueName	- value name for selection of
 *  								  special processing
 *                     ,value )		- value
 *                      
 * The special processing will be supported by predefined functions
 * 
 *  elCheckbox( el, valueName, value )
 *  elCheckboxes( el, valueName, value, chkArray )
 *  elRadiobox( el, valueName, value, chkArray )
 *  elPassword( el, valueName, value )
 *  elOptions( el, valueName, value, optArray )
 *  
 *  The input array shall contain the data each constiong of 'idx' and
 *  'value'.
 * 
 * The formular(s) data are saved by saveDialog, which could call a
 * pre/post processing routine inside. Such routines my be usefull for
 * transaction control. The post processing routine will get a
 * success flag as parameter
 * 
 *  saveDialog({ 'a':				- overwrites an existing 'a' element
 *   								  in the formulars
 *              ,'formOnly':		- (opt)	array of formular names to 
 *              					  be processed
 *              ,'formExclude':		- (opt) array of formalar names to
 *              					  be excluded
 *
 * 
 * For special processing of validated elements a generic function
 * could be redefined by the using plugin
 *  
 *  saveDialogValue( valueName )  value name for selection of
 *  							  special processing
 * 
 * ATTENTION this requires the usage of <validators> != 'none|disabled',
 * e.g. by using the Xinha Editor this function must be used to submit
 * changes in the text area of the editor frame.
 * 
 *
 * For further explanations see below.             
 * -----------------------------------------------------------------
 * functions overview:
 * 
 *   changeDialogElementValue( dialogArray, valueName, value )
 *   createDialog( opt, data)
 *   dialogElement( valueName, value, valueGroup, valueDialogMethod, valueValidator )
 *   dialogHeader( refName, value, action )
 *   elCheckbox( el, valueName, value) 
 *   elCheckboxes( el, valueName, value, chkArray) 
 *   elOptions( el, valueName, value, optArray) 
 *   elPassword( el, valueName, value) 
 *   elRadiobox( el, valueName, value, chkArray) 
 *   processDialogValue( el, valueName, value)
 *   saveDialogValue( el )
 *   saveDialog( opt, preProc, postProc) 
 *   writeDialog( data , opt )
 *   actEditorForElement( el )
 *   syncTextAreas() 
 * -----------------------------------------------------------------
 *  
 * @author Jens Raabe <jens@raabe-berlin.de>
 */
(function(){
	
	var _dlgObj = new Object;				// instance (object) where the methods refere to
											// for easy reference (e.g. in events)

    var _dlgOpt = { 						// dialog Options
            dlgEnabled: 		true		// true: draws a dialog in the browser, false: disables the UI from being drawn
			,dlgUrl:			undefined	// url completed by dialogObject or 
			,dlgSrc:			undefined	// by provided dlgSrc
			,dlgText: 						// placeholder for text elements
				{'_kill':  		'Kill Dialog'
				,'_hide': 		'Hide Dialog'
				,'_show': 		'Show Dialog'
            	,'_lock': 		'Lock Dialog'	
               	,'_unlock': 	'Unlock Dialog'	
				}
    		,dlgFrameStyle: 'top:1px;right:1px;' // Custom wrapper style to load that may not work in css such as right/top/bottom
            ,dlgContent: 		'dlg'		// content anchor, will cause an exception if not correct 	
            ,dlgParent: 		null		// document.body by default	
            ,dlgKillable:		true		// Enable killing
            ,dlgDragable: 		true		// Enable dragging
            ,dlgSizable: 		true		// Enable resizing,
            ,dlgScroller: 		true		// Enable scroller,
            ,dlgMenu:	 		true		// Enable menu,
            ,dlgType:			'top'		// dialog type 'top'(default), 'left', 'right'
            								// special type 'login', simliar to 'top'
            ,dlgTitle:			undefined	// Dialog Title (string)	
            ,dlgOpacity: 		1			// opacity of the dialog with 1: fully visible, 0.x: partially visible, 0: not visible
    		,dlgButtons: 		null		// additional dialog buttons as object element of
    										// 'title': new Element('div', {events: {'click': function(){$empty;}.bind(this)}})
			,dlgUseFieldset:	true		// a frameset is used as wrapper for dialog elemens
			,dlgCssClass:		undefined	// special user style class (wrapper and form)	
			//internal parameter	
            ,dlgWrapper: 		'div'		// Acceptable block elements EG: p, div, pre, code
            ,dlgPlacement: 		'top'		// Order in which the dialog ('top', 'bottom', 'before', 'after') is injected
            ,dlgMovable: 		false		// state of dragging icon, don't change
			,dlgLeftWidth:		undefined	// width of left column of dialog table
			,dlgRightWidth:		undefined	// width of right column of dialog table
            ,dlgMinSize: 					// Minimal Size the Dialog can be resized to
            	{x: 100
            	,y: 100
            	}
            ,dlgLockOriginalSize: true		// Forces the minimal size to be the original size
            ,dlgKeepInContainer: true		// Forces the dialog to remain inside of the container. (Disabled in IE)
			,dlgTabIndex:		1			// start index	
			,dlgWithEditor:		false		// Flag indicating usage of elements with integrated Editor
			,dlgFadeTime:		100			// Time to fade in/out the dialog
			,dlgDebug: 			false		// debugging flag
			,dlgDebugOutput:	'divSaveResult'
			,dlgWrapperOpt:		new Object()// empty object for additional element options like as events
	};
    
    JRCmsForm.implement({
    	
		Implements: [Events, Options, Chain]

		
		/* ==================================================================== */
		/* DIALOG FRAME API                                                     */
		/* ==================================================================== */

    	/**
    	 * This function creates a dialog frame
    	 * with standard buttons for control of the
    	 * frame and supplied buttons for the dialog
    	 * The frame could be established as a normal, so 
    	 * called 'top' menue frame or as 'left/right'
    	 * menu frame. 
    	 * Re-size and dragging is supported for 'top'
    	 * frames only.
    	 * Data could be provided optionally and will
    	 * be inserted like as using writeDialog.
    	 * 
   	 	 * @param object
   	 	 * @access global
    	 */
        ,createDialog: function( opt, data){
        
        	//use an instance copy
    		_dlgObj = this;
    		//define a parent by default
    		if(!$defined(opt.dlgParent)) opt.dlgParent = $$('body')[0];
    		//consider special format or dependencies
    		if(($defined(opt.dlgType) && (opt.dlgType != 'top' && opt.dlgType != 'login')) ||
    		   ($defined(opt.dlgDragable) && !opt.dlgDragable)  ) {
    			//not supported options for now
    			opt.dlgDragable = false;
    			opt.dlgSizable = false;
    			opt.dlgScroller = false;
    		}	
    		//initialize the options
    		opt = _dlgObj.setDialogOptions(opt);
    		//ensure that a same element doesn't exist
    		_dlgObj.killDialog(opt);
    		//set state flags
    		_dlgObj.dlgCreated = true;
    		_dlgObj.dlgOriginalSize = false;
    		//create the wrapping element
    		var dlgElWr = new Element(opt.dlgWrapper, $merge({
										'id': 'dlgWrapper'+opt.dlgType
										,'class': 'dlgwrapper'+		//don't change, use for save
												  ($defined(opt.dlgCssClass)
												   ? ' '+opt.dlgCssClass
												   : '')
										,'style': opt.dlgFrameStyle
    									}, opt.dlgWrapperOpt
    		));
    		dlgElWr.store('options', opt);
    		//create the scroller element
    		dlgElWr.store('dlgElScr', new Element('div', {
                						'class' : (opt.dlgScroller?'_scroller':'_nscroller')
    		}));
    		//create the placeholder for content
    		dlgElWr.store('dlgElCont', new Element('div', {    		
										'id': opt.dlgContent
    		}));
    		//create the menu element
    		dlgElWr.store('dlgElMenu', new Element('div', {
										'id': 'dlgMenu'+opt.dlgType
										,'class': 'dlgmenu'
    		}));
    		if(opt.dlgMenu) 
    			_dlgObj.addDialogButtons(dlgElWr);
    		if(opt.dlgType != 'top' && opt.dlgType != 'login')
    			dlgElWr.retrieve('dlgElMenu').setStyle('height', dlgElWr.retrieve('dlgElCont').getSize().y);
    		//create the size element
    		if(opt.dlgSizable)
    			dlgElWr.store('dlgElSz', new Element('div', {
                						'id': 'dlgSize'
                						,events: {
                        					'mousedown': function(e){
                                				e.stopPropagation();
                                				dlgElWr.addEvent('selectstart', _dlgObj.stopEvent);
                                			}
                                			,'mouseup': function(e){
                                				dlgElWr.removeEvent('selectstart', _dlgObj.stopEvent);
                                			}
                                			,'contextmenu': _dlgObj.stopEvent
                                		}
    		}));
    		//build the dialog elemens
    		_dlgObj.insertDialog(dlgElWr, data);
    		_dlgObj.toggleLockDialog(opt);
    	}
    
		
		/* ==================================================================== */
		/* FORMULAR API                                                         */
		/* ==================================================================== */
		/**
		 * A dialog for an object of items will be created
		 * which uses the content element established
		 * by createDialog or the supplied element
		 * To complete specific inputs and selections each 
		 * application classe should re-define the method
		 * processDialogValue defined below
		 * 
	 	 * @param object
	 	 * @param object
	 	 * @access global
		 */
		,writeDialog: function( data , opt ) {
			
			try{
	        	//use an instance copy
	    		_dlgObj = this;
				// we use the options set for the header data as well 
				var opt = $merge($merge(_dlgOpt, opt), data.header);
				// we create an own wrapping element (createDialog)
	    		var dlgElWr = $(opt.dlgContent);
	    		// clean the hash storage of the element
	    		dlgElWr.eliminate('options');
	    		dlgElWr.eliminate('dlgElCont');
	    		dlgElWr.eliminate('dlgElAccWrapper');
	    		// build up the hash storage
	    		dlgElWr.addClass('dlgwrapper'); 	//don't change, use for save
	    		dlgElWr.store('options', opt);
	    		dlgElWr.store('dlgElCont', $(opt.dlgContent));

	    		_dlgObj.writeDialogContent(dlgElWr, data);
				
			} catch (err) {
				var e = ' writeDialog: '+err;
				if(opt.dlgDebug) throw new Error(e); 
			}
		}	
	
		/**
		 * Due to the usage of own buttons instead of a submit 
		 * element within the formular the submit will be simulated
		 * and multiple formulars could be submitted one after
		 * another.
		 * By using the mootools validator the parameter are proved
		 * first and pre/post-processing routines could be provided 
		 * e.g. for transaction control or other tasks.
		 * 
		 * The processing could be controlled by the first paramter
		 * which is an object of:
		 * 
		 * 	 a:				action - overwrites an existing 'a' element
		 *   formOnly:		array of formular names to be processed only
		 *   formExclude	array of formalar names to be excluded
		 *   
		 * The formular names are the valueGroup names without further 
		 * extensions BUT all with lower case.
		 *  
	 	 * @param object
	 	 * @param function
	 	 * @param function
	 	 * @access global
		 */
		,saveDialog: function(opt, preProc, postProc) {
	
			//ensure correct setting
			var elFail = false;
			//pre-processing routine
			if($defined(preProc)) preProc.run();
			//overwrite/set task/action if provided
			if($defined(opt.a)) $$('input[name="a"]').set('value',opt.a);
			//retrieve all groups to be processed
			var dlgElForms = $$('form');
			//search for wrapping element by using the class as
			//defined above (attention: dont change the class)
			var dlgElWr = $$('.dlgwrapper')[0];
			//clean up the list for easier processing
			//bad run time, but better for usage of last index
			dlgElForms.each(function(item, index){
				if(($defined(opt.formOnly) && !opt.formOnly.contains(item.name.substr(0,item.name.indexOf('_')))) ||
				   ($defined(opt.formExclude) && opt.formExclude.contains(item.name.substr(0,item.name.indexOf('_')))))
					dlgElForms[index] = null;
			});
			dlgElForms = dlgElForms.clean();
			if (dlgElWr.retrieve('options').dlgDebug >= 4)
				$(dlgElWr.retrieve('options').dlgDebugOutput).empty();
			// if an integrated Editor is used synchronize the textareas
			if (dlgElWr.retrieve('options').dlgWithEditor)
				this.syncTextAreas();
			dlgElForms.each(function(item, index){
				if($defined(item)) {
					var itemValidator = new Form.Validator(item,{
						// disable default options usefull in case of submit event
						evaluateOnSubmit: false	
						,evaluateFieldsOnBlur: false
						,evaluateFieldsOnChange: false
						// changing defaults
						,errorPrefix: 'imacs: '
						// our processing of request
					    ,onFormValidate: function(passed, form, event) {
							//the loop require a further state
							if (passed) {
								this.processRequest({
									requestType:'form'
									,data: form
									,evalScripts: (dlgElForms.length-1==index)?true:false 
									,async: false
									,onSuccess: (dlgElWr.retrieve('options').dlgDebug >= 4)
												?(function(response){ 
													// for traces only
													$(dlgElWr.retrieve('options').dlgDebugOutput).set('html', 
														$(dlgElWr.retrieve('options').dlgDebugOutput).get('html')+'<br />'+ response);
												  }.bind(this))
												:(function() {
													if(dlgElWr.retrieve('options').dlgType != 'login')
														this.killDialog(dlgElWr.retrieve('options'));
													else
														this.toggleHideDialog(dlgElWr.retrieve('options'));
												  }.bind(this))});
							}
							// else do nothing
				         }.bind(this)
				         // for traces only
				         // ,onElementValidate: function(state, element, validator, warning){
				         //	 ;
				         // }
				         ,onElementFail: function(element, validators) {
				        	 elFail = true;
				        	 element.focus();
				        	 alert(dlgElWr.retrieve('options').dlgText[validators[0]]);
				         }.bind(this)
				         ,onElementPass: function(element) {
				        	 this.saveDialogValue(element);
				         }.bind(this)
					});
					// we don't use the global submit event, 
					// to prevent clashes between several forms at same page
					itemValidator.validate();
					//post-processing routine
					if(dlgElForms.length-1==index && $defined(postProc))
						postProc.run(!elFail, this);
				}
			}.bind(this));
		}
	
		/**
		 * Method to be called by application e.g. within
		 * processDialogValue to provide a single check box
		 * 
	 	 * @param element
	 	 * @param string
	 	 * @param string
	 	 * @access global
		 */
		,elCheckbox: function( el, valueName, value) {
			el.set({ 'type': 'checkbox'
				   ,'class': 'checkbox'
				   ,'value': (value?1:0)
				   ,'checked': value});
			el.addEvent('click', function(event){
				event.target.value = (event.target.checked?1:0);
			}.bind(this));
			return this.elInput( el );
		}
		
		/**
		 * Method to be called by application e.g. within
		 * processDialogValue to provide check boxes
		 * Expected is an option array consisting of:
		 *  [{idx:'<db representation>', value:'<visible value>'}]
		 * 
	 	 * @param element
	 	 * @param string
	 	 * @param string
	 	 * @param array
	 	 * @access global
		 */
		,elCheckboxes: function( el, valueName, value, chkArray) {
			// ensure proper processing of multiple selection
			el.set({'type': 'checkbox', 'name': el.get('name')+'[]'});
			return this.elInput( el, valueName, value, chkArray);
		}

		/**
		 * Method to be called by application e.g. within
		 * processDialogValue to provide radio boxes
		 * Expected is an option array consisting of:
		 *  [{idx:'<db representation>', value:'<visible value>'}]
		 * 
	 	 * @param element
	 	 * @param string
	 	 * @param string
	 	 * @param array
	 	 * @access global
		 */
		,elRadiobox: function( el, valueName, value, chkArray) {
			// ensure proper processing of multiple selection
			el.set('type', 'radio');
			return this.elInput( el, valueName, value, chkArray);
		}
	
		/**
		 * Method to be called by application e.g. within
		 * processDialogValue to provide a password box
		 * 
	 	 * @param element
	 	 * @param string
	 	 * @param string
	 	 * @access global
		 */
		,elPassword: function( el, valueName, value) {
			return el.set('type', 'password');
			
		}
	
		/**
		 * Method to be called by application e.g. within
		 * processDialogValue to complete a Select section
		 * Expected is an option array consisting of:
		 *  [{idx:'<db representation>', value:'<visible value>'}]
		 * 
	 	 * @param element
	 	 * @param string
	 	 * @param string
	 	 * @param array
	 	 * @access global
		 */
		,elOptions: function( el, valueName, value, optArray) {
			optArray.each(function(item, index){
				var opt = new Element( 'option', {'value': item['idx']
				 				                 ,'html': item['value']});
				if (value == item['idx']) opt.set('selected', true);
				el.grab(opt);
			});
			return el;
		}
		
		/**
		 * Dummy method to be overwritten by applications
		 * This method is called in case of a specified
		 * valueDialogMethod object.
		 * 
		 * Based on the valueName additional values for
		 * Select and Input Elements could be provided
		 * by calling local routines providing the data.
		 * Such data could be integrated in a dialog by using
		 * the above defined methods for element to be returned:
		 * 
		 *  elCheckbox		- for single choice using input checkbox
		 *  elCheckboxes	- for choices using input checkbox
		 *  elRadiobox		- for alternate choices using input radio
		 *  elPassword		- for password protected fields
		 *  elOptions		- for options of a select
		 * 
	 	 * @param element
	 	 * @param string
	 	 * @param string
	 	 * @access global
		 */
		,processDialogValue: function(el, valueName, value){
			return el;
		}
		
		/**
		 * Dummy method to be overwritten by applications.
		 * This method is called for successfully validated
		 * elements
		 * 
	 	 * @param element
	 	 * @access global
		 */
		,saveDialogValue: function(el){
			return true;
		}
		
		/**
		 * Provides a dialog element for definition
		 * of a dialog structure
		 * 
	 	 * @param string
	 	 * @param mixed
	 	 * @param string
	 	 * @param string
	 	 * @param string
	 	 * @access global
		 */
		,dialogElement: function(valueName, value, valueGroup, valueDialogMethod, valueValidator) {
			return ({
				 'valueName': valueName
				,'value': value
				,'valueGroup': valueGroup
				,'valueDialogMethod': ($defined(valueDialogMethod)?valueDialogMethod:'input')
				,'valueValidator': ($defined(valueValidator)?valueValidator:'none')
			});
		}

		/**
		 * Provides a dialog header for definition
		 * of a dialog structure
		 * 
		 * @param string
		 * @param mixed
		 * @param string
		 * @access global
		 */
		,dialogHeader: function(refName, value, action) {
			return ({
				 'refName': refName
				,'value': value
				,'a': ($defined(action)?action:'todo')
			});
		}
		
		/**
		 * function provides the possibility to manipultate
		 * values of dialog Elements in the structure
		 * 
		 * @param array
		 * @param string
		 * @param mixed
		 * @access global
		 */
		,changeDialogElementValue: function( dialogArray, valueName, value) {
			$A(dialogArray).each(function(dlgel, index){
				if(dlgel.valueName == valueName) 
					dialogArray[index].value = value;
			}, this);
			return dialogArray;
		}
		
		/**
		 * Activates the Editor for the given element.
		 * function as interface to an integrated Editor. May be overwritten in
		 * case of an other Editor as Xinha
		 */
		,actEditorForElement: function(el) {
			if($defined(window['jrCmsEditor']))
				jrCmsEditor.activateEditorForElement(el);
		}
		
		/**
		 * Syncronize the Editor elements with the text areas.
		 * function as interface to an integrated Editor. may be overwritten in 
		 * case of an other Editor as Xinha
		 */
		,syncTextAreas: function() {
			if($defined(window['jrCmsEditor']))
				jrCmsEditor.syncXinhaTextAreas();
		}
		
		/* ==================================================================== */
		/* Internal Methods                                                     */
		/* ==================================================================== */
		
		/**
		 * set the dialog options (use in the frame) which will be
		 * stored in the wrapper hash table
		 * Furthermore the buttons defined for the header will be created
		 */
    	,setDialogOptions: function(opt){
    		//convert letters
    		if($defined(opt.dlgType))
    			opt.dlgType = opt.dlgType.toLowerCase();
    		//merge the provided options with predefinitions
    		opt = $merge(_dlgOpt, opt);
    		//build up the buttons list
            var btns = function(o){
            	var result = new Array();
            	var stdbuttons = new Object();
            	var mnuTitle = new Object();
            	//no kill button
            	if(o.dlgKillable)
            		stdbuttons['_kill'] = new Element('div', {'id': '_kill'+o.dlgContent
                								,'class': '_kill _stdbutton'
                								,events: {'click': function(){_dlgObj.killDialog(o);}}});
            	//hide button
            	stdbuttons['_hide'] = new Element('div', {'id': '_hide'+o.dlgContent
                								,'class': '_hide _stdbutton'
            									,events: {'click': function(){_dlgObj.toggleHideDialog(o);}}});
            	//lock button
            	if(o.dlgDragable)
            		stdbuttons['_lock'] = new Element('div', {'id': '_lock'+o.dlgContent
            									,'class': '_lock _stdbutton'
            									,events: {'click': function(){_dlgObj.toggleLockDialog(o);}}});
            	//title element
            	if($defined(o.dlgTitle))
            		mnuTitle['_title'] = new Element('div', {'id': '_title'+o.dlgContent
            									,'class': '_dlgtitle'
            									,'html': o.dlgTitle	});
            	//build button element for user buttons
            	if($defined(o.dlgButtons))
            		$each(o.dlgButtons, function(val, key){
            			o.dlgButtons[key] = new Element('div', {'id': key+o.dlgContent
            									,'class': key+' _button'
            									,events: {'click': val}});
            		});
            	//sequence of buttons depends on type
           		o.dlgButtons = (o.dlgType == 'top' || o.dlgType == 'login') 
           						? ($merge(o.dlgButtons, mnuTitle, stdbuttons)) 
           						: ($merge(stdbuttons, o.dlgButtons));
           		//update settings
            	$each(o.dlgButtons, function(val, key){
	        		val.set('title', o.dlgText[key]);
	        	//	val.set('dlganchor', 'JR');
	        		result.push(val);
            	});
            	return result;
            };
            opt.dlgButtons = btns(opt);
            return opt;
    	}

    	/**
    	 * Central routine which creates the element with all childs
    	 * and content if provided.
    	 * For testing purposes the write Content could be called 
    	 * separatly
    	 */
        ,insertDialog: function(dlgElWr, data ){
        	//recall the options
        	var opt = dlgElWr.retrieve('options');
        	//data provided
        	if( $defined(data) ) {
        		dlgElWr.store('options', $merge(dlgElWr.retrieve('options'), data.header));
        		this.writeDialogContent(dlgElWr, data);
        	}	
            //insert elements
        	dlgElWr.inject(opt.dlgParent, opt.dlgPlacement).adopt(
        			dlgElWr.retrieve('dlgElMenu'),
        				dlgElWr.retrieve('dlgElScr').grab(
        				dlgElWr.retrieve('dlgElCont')
            			),
            		dlgElWr.retrieve('dlgElSz')
            	);
        	
        	if(opt.dlgDragable)
	        	//make it dragable
	        	dlgElWr.store('dlgDragger', dlgElWr.makeDraggable({
	        		container: _dlgObj.getDialogContainer(opt)
	        		,handle: $(opt.dlgContent+'Menu'+opt.dlgType)
	        		,onDrag: _dlgObj.addDialogDragger.bind(this,dlgElWr)
	        		,onComplete: _dlgObj.addDialogComplete.bind(this,dlgElWr)
	        	}));
        	if(opt.dlgSizable)
	        	//make it resizeable
        		dlgElWr.store('dlgResizer', dlgElWr.makeResizable({
	        		handle: dlgElWr.retrieve('dlgElSz')
	        		,onDrag: _dlgObj.addDialogSizer.bind(this,dlgElWr)
	        		,onComplete: _dlgObj.addDialogComplete.bind(this,dlgElWr)
	        	}));
        	//set opacity
        	dlgElWr.set('opacity', opt.dlgOpacity);
			this.updateDialogSize( dlgElWr );				
        }

        /**
         * Function which defines the Lock/Unlock functionality
         */
        ,toggleLockDialog: function(opt){
        	var dlgElWr = $('dlgWrapper'+opt.dlgType);
           	var dlgElButton = $$('#dlgMenu'+opt.dlgType+' ._lock')[0] || 
            				  $$('#dlgMenu'+opt.dlgType+' ._unlock')[0];
            if (opt.dlgMovable){
            	if($chk(dlgElButton)){
            		dlgElButton.removeClass('_unlock');
                    dlgElButton.addClass('_lock');
                    dlgElButton.setAttribute('title', opt.dlgText['_lock']);
                    dlgElWr.retrieve('dlgElMenu').setStyle('cursor', 'move');
                    if($chk(dlgElWr.retrieve('dlgElSz'))) 
                    	dlgElWr.retrieve('dlgElSz').setStyle('cursor', 'se-resize');
            	}
            	if($defined(dlgElWr.retrieve('dlgDragger'))) dlgElWr.retrieve('dlgDragger').attach();
            	if($defined(dlgElWr.retrieve('dlgResizer'))) dlgElWr.retrieve('dlgResizer').attach();
            } else {
            	if($chk(dlgElButton)){
            		dlgElButton.removeClass('_lock');
            		dlgElButton.addClass('_unlock');
            		dlgElButton.setAttribute('title', opt.dlgText['_unlock']);
            		dlgElWr.retrieve('dlgElMenu').setStyle('cursor', 'default');
            		if($chk(dlgElWr.retrieve('dlgElSz'))) 
            			dlgElWr.retrieve('dlgElSz').setStyle('cursor', 'default');
            	}
            	if($defined(dlgElWr.retrieve('dlgDragger'))) dlgElWr.retrieve('dlgDragger').detach();
            	if($defined(dlgElWr.retrieve('dlgResizer'))) dlgElWr.retrieve('dlgResizer').detach();
            }
            return opt.dlgMovable = !opt.dlgMovable;
        }
        
        /**
         * Function which defines the Hide/Show functionality
         */
        ,toggleHideDialog: function(opt){
           	var dlgElButton = $$('#dlgMenu'+opt.dlgType+' ._hide')[0] || 
               				  $$('#dlgMenu'+opt.dlgType+' ._show')[0];
        	if(!_dlgObj.uiHidden){
        		if($chk(dlgElButton)){
        			dlgElButton.removeClass('_hide');
        			dlgElButton.addClass('_show');
        			dlgElButton.setAttribute('title', opt.dlgText['_show']);
        		}
        		_dlgObj.hideDialog(opt);
            } else {
            	if($chk(dlgElButton)){
            		dlgElButton.removeClass('_show');
            		dlgElButton.addClass('_hide');
            		dlgElButton.setAttribute('title', opt.dlgText['_hide']);
            	}
            	_dlgObj.showDialog(opt);
            }
            return _dlgObj.uiHidden = !_dlgObj.uiHidden;
        }
        
        /**
         * Close the complete element
         */
        ,killDialog: function(opt){
	    	//remove the element
	    	if($chk($('dlgWrapper'+opt.dlgType)))
	    		$('dlgWrapper'+opt.dlgType).dispose();
	    	_dlgObj.dlgOriginalSize = false;
	    	_dlgObj.dlgCreated = false;
	    }

        ,getDialogContainer: function(opt){
            return opt.dlgKeepInContainer
            		? Browser.Engine.trident 
            			? false
            			: opt.dlgParent
            		: false;
    	}
    	
        ,getDialogOriginalSize: function(dlgElWr){
            return _dlgObj.dlgOriginalSize = !_dlgObj.dlgOriginalSize
            				? dlgElWr.getSize()
            				: _dlgObj.dlgOriginalSize;
    	}
        
        ,updateDialogSize: function(dlgElWr) {
    		if(dlgElWr.retrieve('options').dlgType != 'top' && dlgElWr.retrieve('options').dlgType != 'login') 
    			dlgElWr.retrieve('dlgElMenu').setStyle('height',
    					((dlgElWr.retrieve('dlgElCont').getSize().y < dlgElWr.getSize().y )
    					? dlgElWr.getSize().y
    					: dlgElWr.retrieve('dlgElCont').getSize().y));
        }
        
        ,lockDialogSize: function(dlgElWr){
            var minSize = dlgElWr.retrieve('options').dlgLockOriginalSize
            				? _dlgObj.getDialogOriginalSize(dlgElWr)
            				: dlgElWr.retrieve('options').dlgMinSize;
            if (dlgElWr.getSize().y < minSize.y)
                    dlgElWr.setStyle('height', minSize.y);
            if (dlgElWr.getSize().x < minSize.x)
                    dlgElWr.setStyle('width', minSize.x);
        }

        ,addDialogButtons: function(dlgElWr){
            var btns = function(dlgElWr){
            	var result = [];
            	$each(dlgElWr.retrieve('options').dlgButtons, function(val){
            		result.push(val);
            	});
            	return result;
            };
            dlgElWr.store('dlgElMenu', dlgElWr.retrieve('dlgElMenu').adopt(btns(dlgElWr)));
	    }

        ,addDialogSizer: function(dlgElWr){
       	 	_dlgObj.addDialogDragger(dlgElWr);
       	 	_dlgObj.lockDialogSize(dlgElWr);
       }

        ,addDialogDragger: function(dlgElWr){
        	dlgElWr.retrieve('dlgElScr').addEvent('selectstart', _dlgObj.stopDialogEvent);
        	dlgElWr.retrieve('dlgElScr').setStyle('MozUserSelect', 'none');
    	}

        ,addDialogComplete: function(dlgElWr){
        	dlgElWr.retrieve('dlgElScr').removeEvent('selectstart', _dlgObj.stopDialogEvent);
        	dlgElWr.retrieve('dlgElScr').setStyle('MozUserSelect', 'text');
    	}

        ,stopDialogEvent: function(e){
            return e.stop();
        }

        ,showDialog: function(opt){
            if (!$chk($('dlgWrapper'+opt.dlgType))) return false;
            var dlgElWr = $('dlgWrapper'+opt.dlgType);
            if(Fx.Tween){
            	dlgElWr.retrieve('dlgElScr').set('tween', {duration: opt.dlgFadeTime}).fade('in');
            	if($chk(dlgElWr.retrieve('dlgElSz'))) 
            		dlgElWr.retrieve('dlgElSz').setStyle('visibility', 'visible');
            } else
            	dlgElWr.retrieve('dlgElScr').setStyle('display', '');
//            return _dlgObj.fireEvent('show');
            return $('dlgWrapper'+opt.dlgType).fireEvent('show');
        }
        
        ,hideDialog: function(opt){
            if (!$chk($('dlgWrapper'+opt.dlgType))) return false;
            var dlgElWr = $('dlgWrapper'+opt.dlgType);
            if(Fx.Tween){
            	dlgElWr.retrieve('dlgElScr').set('tween', {duration: opt.dlgFadeTime}).fade('out');
            	if($chk(dlgElWr.retrieve('dlgElSz')))
            		dlgElWr.retrieve('dlgElSz').setStyle('visibility', 'hidden');
            } else
            	dlgElWr.retrieve('dlgElScr').setStyle('display', 'none');
//            return _dlgObj.fireEvent('hide');
            return $('dlgWrapper'+opt.dlgType).fireEvent('hide');
        }

        /**
         * function which writes the content in a formular
         * by using the options and wrapping element as defined
         * in createDialog or writeDialog
         */
		,writeDialogContent: function( dlgElWr, p) {
			var formName = '';
			p.data.each(function(item, index){
				if(formName != item.valueGroup.split(':')[0]) {
					formName = item.valueGroup.split(':')[0];
					// determin the server script file
					if(!$defined(dlgElWr.retrieve('options').dlgSrc))
						if($defined(item.valueGroup.split(':')[1]))
							dlgElWr.store('options', 
									$merge(dlgElWr.retrieve('options'),
											{'dlgSrc' :
												(item.valueGroup.split(':')[1]).toLowerCase() + '/' +
												(item.valueGroup.split(':')[1]).toLowerCase() + '.php'
											}
							));
						else
							throw new Error('no dlgSrc specified');
					// create the formular element
					dlgElWr.retrieve('dlgElCont').grab(this.dlgForm(
														dlgElWr, 
														formName));
				}
				// shorten the valueGroup, skip the object
				item.valueGroup = formName;
				// write new dialog row
				this.dlgRow( dlgElWr, item);

			}.bind(this));
		}
		
		/**
		 * Create the formular element either as pur formular or 
		 * with an wrapping fieldset element as requested by the 
		 * options. The table containing the dialog data will be
		 * created as well. Like as all other elements the wrapping
		 * hash table is used to store the table which gives the 
		 * oppertunity for easy using of the HtmlTable features
		 */
		,dlgForm: function( dlgElWr, valueGroup ) {
			//create the formular element
			dlgElWr.store('dlgElForm', new Element('form', {
						    			'name': valueGroup+'_form'
						    			,'class': 'dlgForm'+
						    					 ($defined(dlgElWr.retrieve('options').dlgCssClass)
												   ? ' '+dlgElWr.retrieve('options').dlgCssClass
												   : '')
						    			,'action': dlgElWr.retrieve('options').dlgUrl+
						    					   dlgElWr.retrieve('options').dlgSrc
						    			,'method': "post"
						    			,events: {
    										'submit': function(e){
    											this.stopDialogEvent(e);
    											}.bind(this)
    									}	    			
			}));
			//create the table element
			dlgElWr.store('dlgElTable', new HtmlTable({
										properties:{
											'id': valueGroup+'_tbl'
											,'class': dlgElWr.retrieve('options').dlgContent+'Table'+
													  ($defined(dlgElWr.retrieve('options').dlgCssClass)
													   ? ' '+dlgElWr.retrieve('options').dlgCssClass
													   : '')
			}}));
    		//combine the elements
			dlgElWr.retrieve('dlgElForm').adopt(
    				this.dlgHiddenInput({valueName:	dlgElWr.retrieve('options').refName
    									,value:		dlgElWr.retrieve('options').value})
    				,this.dlgHiddenInput({valueName:'a'
    									,value:		dlgElWr.retrieve('options').a})
    				,dlgElWr.retrieve('dlgElTable'));
			
    		if(dlgElWr.retrieve('options').dlgUseFieldset) {
    			//return the formular with a wrapping fieldset
    			return new Element('fieldset', { 
    									'class' : valueGroup+' dlgFieldset'+
    											 ($defined(dlgElWr.retrieve('options').dlgCssClass)
												   ? ' '+dlgElWr.retrieve('options').dlgCssClass
												   : '')
    								}).grab( new Element('legend', {
    									'html': dlgElWr.retrieve('options').dlgText[valueGroup]
    								}), 'top').grab(dlgElWr.retrieve('dlgElForm'), 'bottom');
			} else {
				//return the pur formular
				return dlgElWr.retrieve('dlgElForm');
			}
		}
		
		/**
		 * depending on the dialog method a table row will
		 * be generated by pushing the given data in the table
		 */
		,dlgRow: function( dlgElWr, p ) {
			switch (p.valueDialogMethod.split(':')[0].toLowerCase()) {
			case 'text': // text (HTML string), left column is used
				// create a row with combined column (left only)
				dlgElWr.retrieve('dlgElTable').push([this.dlgColL(dlgElWr, p, 2)]);
				break;
			case 'accordion': // accordion, right column for input is used
			case 'accordioneditor': // accordion, right column for input is used
				if(!$chk(dlgElWr.retrieve('dlgElAccWrapper')))
					// create a row with combined column (right only)
					// to create an ancore element for the accordion
					dlgElWr.retrieve('dlgElTable').push([this.dlgColR(dlgElWr, p, 2)]);
				// afterwards only this sequence is used
				// special processing enlarge an existing row
				this.dlgAccordion(dlgElWr, p);
				break;
			case 'hidden':
				// that's not a row within the table but above ;-)
				dlgElWr.retrieve('dlgElForm').grab(this.dlgHiddenInput(p),'top');
				break;
			default: // left col for description, right col for input 
				// create a row with two columns (left, right)
				dlgElWr.retrieve('dlgElTable').push([this.dlgColL(dlgElWr, p, 1),this.dlgColR(dlgElWr, p, 1)]);
			}
		}
		
		,elInput: function( el, valueName, value, chkArray) {
			// define a wrapping element for easier processing
			var wrapper = new Element('span',{'class':'checkboxes'});
			if($defined(chkArray))
				chkArray.each(function(item, index){
					var cpyEl = el.clone();
					if (item['idx'] == value) cpyEl.set('checked', true);
					cpyEl.set({'value':item['idx']
							  ,'title':item['value']});
					wrapper.grab(cpyEl).grab(new Element('span',{'html':item['value']})); 
				});
			else
				wrapper.grab(el);
			return wrapper;
		}
		
		,dlgHiddenInput: function( p ) {
			return new Element( 'input', {'id': p.valueName
											 ,'name': p.valueName
											 ,'value': p.value
											 ,'type': 'hidden'});
		}

		,dlgInput: function( dlgElWr, p ) {
			var inp = new Element( 'input', {'id': p.valueName
											 ,'name': p.valueName
											 ,'title': dlgElWr.retrieve('options').dlgText[p.valueName]
											 ,'class': (p.valueValidator!="none"?p.valueValidator:'')
											 ,'value': p.value
											 ,'tabindex': dlgElWr.retrieve('options').dlgTabIndex++
											 ,disabled:(p.valueValidator=="disabled")?true:false
											 });
			return (!$defined(p.valueDialogMethod.split(':')[1]))
					? inp
					// per convention the method processDialogValue of the given class is called 
					: window[p.valueDialogMethod.split(':')[1]].processDialogValue(inp, p.valueName, p.value);
			
		}
		
		,dlgTextarea: function( dlgElWr, p ) {
			var txtarea = new Element( 'textarea', {'id': p.valueName
											   ,'name': p.valueName
											   ,'title': dlgElWr.retrieve('options').dlgText[p.valueName]
											   ,'class': (p.valueValidator!="none"?p.valueValidator:'')
											   ,'html': p.value
											   ,'tabindex': dlgElWr.retrieve('options').dlgTabIndex++
											   ,readonly: (p.valueValidator=="disabled")?true:false
											   });

			txtarea = (!$defined(p.valueDialogMethod.split(':')[1]))
						? txtarea
						// per convention the method processDialogValue of the given class is called 
						: window[p.valueDialogMethod.split(':')[1]].processDialogValue(txtarea, p.valueName, p.value);
			
			if( p.valueValidator!="disabled" && 
				p.valueDialogMethod.split(':')[0].toLowerCase().search(/editor/) != -1 ) {
					dlgElWr.store('options', $merge(dlgElWr.retrieve('options'), {'dlgWithEditor':true}));
					this.actEditorForElement(txtarea);
			}
			return txtarea;
		}

		,dlgSelect: function( dlgElWr, p ) {
			var dlgElSel = new Element( 'select', {'id': p.valueName
											 ,'name': p.valueName
											 ,'title': dlgElWr.retrieve('options').dlgText[p.valueName]
											 ,'class': (p.valueValidator!="none"?p.valueValidator:'')
											 ,'tabindex': dlgElWr.retrieve('options').dlgTabIndex++
											 ,disabled:(p.valueValidator=="disabled")?true:false
											 }).grab(
						   new Element( 'option', {'value': undefined 
							   				 ,'html': dlgElWr.retrieve('options').dlgText['option_select']
							   				 ,'selected': true							   				                                              
						   					 }));
			return ($defined(p.valueDialogMethod.split(':')[1]))
					// per convention the method processDialogValue of the given class is called 
					? window[p.valueDialogMethod.split(':')[1]].processDialogValue(dlgElSel, p.valueName, p.value)
					// otherwise only the given value is shown
					: dlgElSel.grab(new Element( 'option', {'value': 0
															,'html': p.value}));
		}
		
		,dlgAccordion: function( dlgElWr, p ) {
			// 1) first time called via dlgElement
			// create wrapping according element
			if(!$chk(dlgElWr.retrieve('dlgElAccWrapper'))) {
				dlgElWr.store('dlgElAccWrapper', new Element( 'div', {'id': p.valueGroup+'_accordion'
										   				,'class': 'accordion'
				}));
				//to ensure correct processing clean the hash pool
	    		dlgElWr.eliminate(p.valueGroup+'_accordion');
	    		//return the new wrapping element
				return dlgElWr.retrieve('dlgElAccWrapper');
			}
			// 2) second time called directly
			// if not exist create the accordion itself
			if(!$chk(dlgElWr.retrieve(p.valueGroup+'_accordion'))) {
				dlgElWr.store(p.valueGroup+'_accordion', new Accordion(
							dlgElWr.retrieve('dlgElAccWrapper')
							,'div.accordion_toggler'
							,'textarea.accordion_element', {
							 opacity: false
							,onActive: function(toggler, element){
								toggler.setStyle('color', '#41464D');
							 }
							,onBackground: function(toggler, element){
								toggler.setStyle('color', '#528CE0');
				}}));
			}
			// create toggler
			var toggler = new Element('h3', {
				'class': 'accordion_toggler'
				,'html': dlgElWr.retrieve('options').dlgText[p.valueName]
			});
			// create content as textarea wrapped by a div
			var content = new Element( 'div', {'class':'accordion_element'}).grab(this.dlgTextarea(dlgElWr, p));
			// position for the new section
			var position = 0;
			// add the section
			dlgElWr.retrieve(p.valueGroup+'_accordion').addSection(toggler, content, position);
		}
	
		,dlgElement: function( dlgElWr, p ) {
			
			return ((p.valueDialogMethod.split(':')[0].toLowerCase() == 'input')
					? (this.dlgInput(dlgElWr, p))
					: (p.valueDialogMethod.split(':')[0].toLowerCase() == 'select')
					  ? (this.dlgSelect(dlgElWr, p))
					  : (p.valueDialogMethod.split(':')[0].toLowerCase().search(/textarea/) != -1)
						? (this.dlgTextarea(dlgElWr, p))
						: (p.valueDialogMethod.split(':')[0].toLowerCase().search(/accordion/) != -1)		
						  ? (this.dlgAccordion(dlgElWr, p))
						  :	null);
		}
		
		,dlgColL: function( dlgElWr, p, colsp ) {
			var cnt = (colsp<=1
						? (dlgElWr.retrieve('options').dlgText[p.valueName]+
						  (p.valueValidator.search(/\brequired\b/) != -1?'<sup>*</sup>: ':': '))
						: p.value); 
			return {
				content: cnt
		        ,properties: {
		            colspan: colsp
					,'class': p.valueGroup+'_left'+
							  (colsp>1?'_c2 ':' ')+
 	    					  ($defined(dlgElWr.retrieve('options').dlgCssClass)
								  ? dlgElWr.retrieve('options').dlgCssClass+' '
								  : '')+p.valueName
		            ,'styles':{'padding': 0
								,'width':($defined(dlgElWr.retrieve('options').dlgLeftWidth)
										  ? (colsp <= 1
											? dlgElWr.retrieve('options').dlgLeftWidth.toInt()
											: dlgElWr.retrieve('options').dlgLeftWidth.toInt()+
											  dlgElWr.retrieve('options').dlgRightWidth.toInt())
										  : undefined)}
	        	}
			};	
		}
		
		,dlgColR: function( dlgElWr, p, colsp ) {
			return {
				content: this.dlgElement(dlgElWr, p)
				,properties: {
					colspan: colsp
					,'class': p.valueGroup+'_right'+
							  (colsp>1?'_c2 ':' ')+
							  ($defined(dlgElWr.retrieve('options').dlgCssClass)
								  ? dlgElWr.retrieve('options').dlgCssClass+' '
								  : '')+p.valueName
					,'styles':{'padding': 0
								,'width':($defined(dlgElWr.retrieve('options').dlgRightWidth)
										  ? (colsp <= 1
											? dlgElWr.retrieve('options').dlgRightWidth.toInt()
											: dlgElWr.retrieve('options').dlgLeftWidth.toInt()+
											  dlgElWr.retrieve('options').dlgRightWidth.toInt())
										  : undefined)}
				}
			};
		}
		
	}); //implements end
})();

/* ==================================================================== */
/* ==================================================================== */
/**
 * JRCmsUtils Class
 * 
 * Generic CMS/Utilities Class
 * 
 * @author Jens Raabe <jens@raabe-berlin.de>
 */
(function(){
	JRCmsUtils.implement({
		
		/**
		 * special character converter
		 * the usage of this function requires in PHP the call of 
		 *  forward(SQL-DB): str_replace('%#', '&#', <string>)
		 *  backward(SQL-DB): html_entity_decode(<string>)
		 * 
		 * @param string $strin, string $ctrl
		 * @access public
		 */
		chars2entities: function(strin, ctrl) {
			
			var strout = "";
			//remark: the escape()/unescape functions isn't used because of some rstrictions
			//special replacements for Xinha
			strin.replace(/\&amp;/,'\&');
			strin.replace(/\&nbsp;/,' ');
			for (var i=0; i<strin.length; i++) {

				switch (strin.charCodeAt(i)) {
				case 39: // '
					// if (ctrl != undefined && ctrl == 'proc') break;
				case 43: // +	
					if ($defined(ctrl) && ctrl == 'proc' && (strin.charCodeAt(i)==45)) 
						strout += strin.charAt(i);
					else
						// convert special char
		 				// prevent wrong processing & excanged by %
			 			strout += "%#"+strin.charCodeAt(i)+";";
					break;
				default: 
					if (strin.charCodeAt(i) > 127) {
		 				// prevent wrong processing - & excanged by %
	 					strout += "%#"+strin.charCodeAt(i)+";";
					} else {
		 				strout += strin.charAt(i);
		 			}
				}
	 		}
			return strout;
		}
	
		/**
		 * @param integer dec
		 * @access public
		 */
		,dec2bin: function(dec) {
			var potencies = new Array(); // Creates an empty array that is used to fill in with potencies of 2
			var binary = ''; // The empty string that is written in the binary text input
			for (var i = 0; i > -1; i++) // In theory an endless loop, that is only interrupted by "break"
				{
					var potency = Math.pow(2, i); // Calculates the potency 2^i
					if (potency > dec) { break; } // Maximal length is done, do not add to array but leave loop
					potencies[i] = potency; // Writes actual potency in the array
				}
			
			potencies.reverse(); // Turn array around, so that the biggest number is first and the lowest last
			
			for (var j = 0; j < potencies.length; j++) // This loop increases the variable (which is the divisor)
				{
					var position = potencies[j]; // Select actual potency desc. (32, 16, 8...)
					var zeroOne = parseInt(dec / position); // Integer value that is the result of dividing the number over
															// actual potency (only "1" or "0" can be the result)
					binary += zeroOne + ''; // Just avoid making a number of the string (instead of "0001", "1" may be created)
					dec -= potencies[j] * zeroOne; // Substracts actual value * 0 [or 1]
				}
			
			return binary;
		}
		
		/**
		 * @param string bin
		 * @access public
		 */
		,bin2dec: function(bin) {
			var bin = bin + '';
			var digits = bin.split('');
			digits.reverse();
			var dec = 0;
			for (var i = 0; i < digits.length; i++) {
				var result = digits[i] * Math.pow(2, i);
				dec += result;
			}
			return dec;
		}
		
		/**
		 * resolves a url as complete url
		 *
		 * @param string base, string url
		 * @access public
		 */
		,resolveRelativeUrl: function( base, url ){ 
		   if(url.match(/^([^:]+\:)?\/\//)) { 
			   return url; 
		   } else { 
			   var b = base.split("/"); 
			   if(b[b.length - 1] === "") b.pop(); 
			   var p = url.split("/"); 
			   if(p[0] == ".") p.shift(); 
			   while(p[0] == ".."){ 
				   b.pop(); 
				   p.shift(); 
			   } 
			   return b.join("/") + "/" + p.join("/"); 
		   } 
		} 
		  
		/**
		 * converts a relative directory to an absolute url
		 *
		 * @param string
		 * @access public
		 */
		,convertDirToUrl: function( dir ) {
			if($type(dir) == "string") {
				// skip leading backslash 
				dir = dir.replace(/^\//, ''); 
				// Leave exactly one backslash at the end of dir 
				dir = dir.replace(/\x2f*$/, '/'); 
				// convert dir to absolute url 
				if(!dir.match(/^([^:]+\:)?\//)) { 
					var tmpPath = window.location.toString().replace(/\?.*$/,'').split("/"); 
					tmpPath.pop(); 
					dir = this.resolveRelativeUrl(tmpPath.join("/"), dir); 
				} 
			} else {
				//throw new Error('directory is not set');
				dir = window.location.toString().replace(/\?.*$/,'').split("/");
				dir.pop();
				dir = this.resolveRelativeUrl(dir.join("/"), "");
			}
			return dir;
		}
		
		/**
		 * Build a unique script name
		 * 
		 * @return string
		 * @param string script name
		 * @param string prefix (optional)
		 * @access public
		 */
	 	,getUniqueScriptId: function(scriptName, prefix){
	 		return (!$defined(prefix)
	 				? 'jrsrc'
	 				: prefix).toLowerCase()+'-'+
	 				scriptName.replace(/([a-z])([A-Z])([a-z])/g, function (str, l1, l2, l3) { 
	 																return l1 + "-" + l2.toLowerCase() + l3; 
	 															 }).toLowerCase();
	 	}
	 	
		/**
		 * Build a unique styles file name
		 * 
		 * @return string
		 * @param string styles file name
		 * @param string prefix (optional)
		 * @access public
		 */
	 	,getUniqueStylesFileId: function(stylesFileName, prefix){
	 		return this.getUniqueScriptId(stylesFileName, (!$defined(prefix)?'jrcss':prefix));
	 	}

	 	/**
		 * retrieves html element(s) by class name 
		 *
		 * @return array elements
		 * @param string class name
		 * @access public
		 */
		,getElementsByClassName: function(classname, node) {
			if(!node)
				node = document.getElementsByTagName("body")[0];
		    var a = [];
		    var re = new RegExp('\\b' + classname + '\\b');
		    var els = node.getElementsByTagName("*");
		    for(var i=0,j=els.length; i<j; i++)
		    	if(re.test(els[i].className))a.push(els[i]);
		    return a;
		}
	      
		/* ==================================================================== */
		/* CMS UTIL: Page Select                                                */
		/* ==================================================================== */

		/**
	  	 * p.lpp	- lines per page
	  	 * p.page	- page
	  	 * p.maxp	- max number of pages
	  	 * 
	  	 * @param 
	  	 * @access public
	  	 */
	  	,pageSelect: function(p) {
	  		
	  		if(!$defined(p)) 
	  			var p = new Object();
	  		this.setOptions({jr_maxPage: Math.ceil(($defined(p.total)?(p.total/p.perpage):1))});
	  		var pSDiv = new Element('div');
	  		pSDiv.addClass('pSDiv');
	  		pSDiv.setStyle('width', 'auto'); 
	  		pSDiv.setStyle('height', this.options.jr_repCtrlHeight);
	  		pSDiv.inject(this.options.jr_divMain);
	  		
	  		var pSDiv2 = new Element('div');
	  		pSDiv2.addClass('pSDiv2');
	  		pSDiv.appendChild(pSDiv2);
		
	  		var h = '<div class="pSGroup"><select class="rp" name="rp">';
	  		this.options.jr_perPageOptions.each(function(item, index){
	  			h += '<option value="' + item + '" '+(((!$defined(p.perpage) && index==0)||($defined(p.perpage) && p.perpage == item))?'selected="selected">':'>')+item+'</option>';
	   		}.bind(this));
	  		h += '</select></div>';
	  		
	  		h += '<div class="btnseparator"></div><div class="pSGroup"><div class="pFirst pButton"></div><div class="pPrev pButton"></div></div>';
	  		h += '<div class="btnseparator"></div><div class="pSGroup"><span class="pcontrol"><input type="text" value="'+p.page+'" size="2" style="text-align:center"/> / '+this.options.jr_maxPage+'<span></span></span></div>';
	  		h += '<div class="btnseparator"></div><div class="pSGroup"><div class="pNext pButton"></div><div class="pLast pButton"></div></div>';

	  		pSDiv2.innerHTML = h;

	  		pSDiv2.getElement('.pFirst').addEvent('click', this.jrFirstPage.bind(this,p) );
	  		pSDiv2.getElement('.pPrev').addEvent('click', this.jrPrevPage.bind(this,p) );
	  		pSDiv2.getElement('.pNext').addEvent('click', this.jrNextPage.bind(this,p) );
	  		pSDiv2.getElement('.pLast').addEvent('click', this.jrLastPage.bind(this,p) );
	  		pSDiv2.getElement('.rp').addEvent('change', this.jrPerPageChange.bind(this,p));
	  		pSDiv2.getElement('input').addEvent('keyup', this.jrPageChange.bind(this,p) );
	  	}

	  	/**
	  	 * 
	  	 */
	  	,jrFirstPage: function(p){
	  		p.page = 1;
	  		this[p.a].run(p, this);
	  	}
	  	
	  	/**
	  	 * 
	  	 */
	  	,jrPrevPage: function(p){
	  		if (parseInt(p.page)>1){
	  			p.page--;		
	  	  		this[p.a].run(p, this);
	  		}
	  	}
	  	
	  	/**
	  	 * 
	  	 */
	  	,jrNextPage: function(p){
	  		if( (parseInt(p.page)+1) > this.options.jr_maxPage) return;
	  		p.page++;		
	  		this[p.a].run(p, this);
	  	}
	  		
	  	/**
	  	 * 
	  	 */
	  	,jrLastPage: function(p){
	  		p.page = this.options.jr_maxPage;		
	  		this[p.a].run(p, this);
	  	}

	  	/**
	  	 * 
	  	 */
	  	,jrPerPageChange: function(p){
	  		p.page = 1;
	  		p.perpage = $(this.options.jr_divMain).getElement('.rp').value;		
	  		this[p.a].run(p, this);
	  	}
	  		
	  	/**
	  	 * 
	  	 */
	  	,jrPageChange: function(p){
	  		var np = $(this.options.jr_divMain).getElement('div.pSDiv2 input').value;
	  		if (np>0 && np<=this.options.jr_maxPage) {
	  			if (this.refreshDelayID)
	  				$clear(this.refreshDelayID);
	  			p.page = np;
	  			this.refreshDelayID = this[p.a].run(p, this).delay(1000, this, $merge(p));
	  		}
	  	}
	  	
		/* ==================================================================== */
		/* CMS UTIL: Button Handling                                            */
		/* ==================================================================== */

		/**
		 * routine to set/delete a Button/Task event of a previously loaded Button list
		 * this function works closely together with the PHP routine cJrcms.convTaskHtml
		 * Prerequisite is the taskList jrCmsInit.jr_taskList loaded by cConfig.js.
		 * 
		 * Example: 
		 * 		1) a task list was esatblishe by convertTaskList
		 * 		2) set/change event of first button/icon
		 * 			setButtonEvent(jrCmsInit.jr_taskList.<selector>[0].id, function(){alert('Test!');});
		 * 		3) delete event
		 * 			setButtonEvent(jrCmsInit.jr_taskList.<selector>[0].id, null);
		 * 
		 * Remark: convert the used task list, e.g. var myTaskList = $A(jrCmsInit.jr_taskList.std);
		 * 
		 * @param string $taskId, function $func
		 * @access public
		 */
		,setButtonEvent: function(taskId, func){
			try {
			//prove existence of DOM element
				if($defined(taskId))
					if($type(func) == 'function'){
						//activate the task
						$(taskId).addEvent('click', func);
						//preven double events and set new event
						$(taskId).erase('onclick');
						$(taskId).set('class','taskenabled');
						//change the icon
						$(taskId).set('html', $(taskId).get('html').replace(/disabled/,"enabled"));
					} else {
						//deactivate the task, all 'click' events are removed
						$(taskId).removeEvents('click');
						$(taskId).erase('onclick');
						//set css class
						$(taskId).set('class','taskdisabled');
						//change the icon
						$(taskId).set('html', $(taskId).get('html').replace(/enabled/,"disabled"));
					}
				else
					throw new Error('wrong taskId');
			} catch (err) {
				var e = ' setButtonEvent: '+err;
				if(this.options.jr_debug)	throw new Error(e); 
			}
		}
		
		/**
		 * 
		 */
		,isSet: function (mask, index) {
			if (mask.substr(index, 1) == 1)
				return true;
			else
				return false;
		}
		
		/**
		 * handles the buttons. The parameter could be binary => "1101001000" or decimal => 840
		 * 
		 * @param mixed bitMask indicates the buttons to be set or not.
		 */
		,buttonHandler: function (taskList, funcList, bitMask) {
			try {
				if ($type(bitMask) == "number") 
					bitMask = this.dec2bin(bitMask);
		
				for (var i = 0; i < bitMask.length; i++) {
					if (taskList[i].id != null)
						if (this.isSet(bitMask, i))
							this.setButtonEvent(taskList[i].id, funcList[i]);
						else
							this.setButtonEvent(taskList[i].id, 0);
				}
		
				return true;
			} catch (err) {
				var e = ' buttonHandler: ' + err;
				if(this.options.jr_debug)	throw new Error(e); 
			}
		}
	  	
		/* ==================================================================== */
		/* CMS UTIL: Elements                                                   */
		/* ==================================================================== */

		/**
		 * hide frame
		 * 
		 * @param string $menuDiv
		 * @access public
		 */
		,hideFrame: function(menuDiv){
			
			(($defined($(menuDiv)))
					?($(menuDiv))
					:(((menuDiv.test('.') && $defined($$(menuDiv))))
							?($$(menuDiv))
							:($$('.'+menuDiv))
									)).hide();
		}
		
		/**
		 * show frame
		 * 
		 * @param string $menuDiv
		 * @access public
		 */
		,showFrame: function(menuDiv){
			
			(($defined($(menuDiv)))
					?($(menuDiv))
					:(((menuDiv.test('.') && $defined($$(menuDiv))))
							?($$(menuDiv))
							:($$('.'+menuDiv))
									)).show();
		}
		
		/**
		 * delete frame
		 * 
		 * @param string $menuDiv
		 * @access public
		 */
		,deleteFrame: function(menuDiv){
		
			(($defined($(menuDiv)))
					?($(menuDiv))
					:(((menuDiv.test('.') && $defined($$(menuDiv))))
							?($$(menuDiv))
							:($$('.'+menuDiv))
									)).dispose();
		}
		
		/**
		 * clear frame
		 * 
		 * @param string $menuDiv
		 * @access public
		 */
		,clearFrame: function(menuDiv){
			(($defined($(menuDiv)))
					?($(menuDiv))
					:(((menuDiv.test('.') && $defined($$(menuDiv))))
							?($$(menuDiv))
							:($$('.'+menuDiv))
									)).empty().set('html','');
		}
	
	
	
	}); //implements end
})();

/* ==================================================================== */
/* ==================================================================== */
/**
 * JRCmsPlugin Class
 * 
 * Functions needed for loading and instantiation of plugins.
 * -- The raw idea for this was taken from Xinha Editor -- 
 * 
 * Required options:
 * 	jr_pluginsUrl		provided by cConfig
 *  jr_pluginList		provided by cConfig / array of {plugin, cmp, userlevel}
 * 
 * Plugin Conventions:
 * 	class name:			two leading upper case letters
 * 	object name:		the two leading letters as lower case letters
 * 	constructor:		initialize( options, instanceName )
 * 	filename:			compressed: <class_name>.cmp.js as default or w/o 'cmp.'
 * 
 * For instantiation of the plugin the initialize method is called in case of
 * second call a refresh is attempted by calling a refresh method of the plugin
 * with a similar interface as the initialize method (except instance name)
 * 
 * 	Plugin information to be place in every plugin
 *		_pluginInfo = {
 *         name          : "<plugin name>",
 *         version       : "<n.n>",
 *         developer     : "<name>",
 *         developer_url : "<http://>",
 *         license       : "<MIT>",
 *         classId		 : "nnnn" }  
 * 
 * @author Jens Raabe <jens@raabe-berlin.de>
 */
(function(){
	JRCmsPlugins.implement({

		/**
		 * Stores a status for each loading plugin that may be one of "loading", "loaded", "ready" or "failed"
		 */
		_pluginLoadStatus: {}
		
		/** 
		 * Plugins reside in the global scope only   
		 * This function check implicit the loading status and retrieve the plugin's constructor
		 *  
		 * Remember: The first two letter of a class are upper cases
		 */ 
		,getPluginConstructor: function(pluginName){ 
			pluginName = pluginName.substr(0,2).toUpperCase() + pluginName.substr(2);
		 	return $type(window[pluginName])=='class'?window[pluginName]:undefined; 
	 	}
	 	
	 	/** 
	 	 * provides a unique script ID assigned while loading and used
	 	 * for removing the script
	 	 */ 
	 	,getPluginScriptId: function(pluginName){
	 		return this.getUniqueScriptId(pluginName);
	 	}
	 	
	 	/**
	 	 * Returns the directory from which the plugins are loaded
	 	 * per convention all plugins reside on one subdirectory where
	 	 * the url is provided during init of config
	 	 */ 
	 	,getPluginDir: function(plugin){
	 		return this.options.jr_pluginsUrl + plugin.toLowerCase(); 
	 	} 
	 	
	 	/**
	 	 * File Ping
	 	 * Parameter is an object of url, pluginName, successHandler, failHandler
	 	 */
	 	,pluginPing: function(p){
	 		
			var req = new Request({
				url: p.src,
				method: 'head',						// _method, shall retrieve the header only
				emulation: true,					// set by default, but set again to remember on state
				onSuccess: function(){
					if($type(p.successHandler)=='function') p.successHandler.run(p,this);
				}.bind(this),
				onFailure: function(err){
					if($type(p.failHandler)=='function') p.failHandler.run(p,this);
				}.bind(this)
			});
			req.send(null);
	 	}
	 	
	 	/** 
	 	 * set the plugin state in the global field
	 	 */
	 	,setPluginState: function(pluginName, state){
	 		// assoziative array
	 		this._pluginLoadStatus[pluginName] = state;
	 	}
	 	
	 	/**
	 	 * get the plugin state
	 	 */
	 	,getPluginState: function(pluginName){
	 		// assoziative array
	 		return this._pluginLoadStatus[pluginName];
	 	}
	  
	 	/** 
	 	 * Create the specified plugin and register it in the global DOM
	 	 *  
	 	 * As parameter an object is expected
	 	 * 	p {
	 	 *  	pluginName: <class name>,		mandatory class name  
	 	 *  	successHandler: <function>		optional function to be called while instantiated
	 	 *  } 
	 	 */ 
	 	,registerPlugin: function(p){
	 		
	 		//ensure proper processing, check parameter
	 		if($type(p.pluginName) != 'string') throw new Error('JRCmsPlugins.registerPlugin with wrong parameter called!');
	 		//We can only register plugins that have been succesfully loaded
	 		//and which are available in DOM
	 		if(this.getPluginState(p.pluginName) == 'failed') {
	 			//skip for further processing
				//DEBUG: if($defined(window.jrCmsLog)) this.jrLog('T:3#>> Register Plugin: '+p.pluginName+' skipped',3);
	 			return false;
	 		} else if(this.getPluginState(p.pluginName) != 'loaded' && this.getPluginConstructor(p.pluginName) == undefined) {
	 			//DEBUG: if($defined(window.jrCmsLog)) this.jrLog('T:3#>> Register Plugin: '+p.pluginName+' wait for domReady!',3);
	 			//to ensure re-entrance a copy of parameter object has to be used
				this.registerPlugin.delay(50,this,$merge(p));
				return false;
			}
	 		this.jrLog('T:3#>> Register Plugin: '+p.pluginName+' domReady! ',3);
	
			//retrieve the plugin constructor
			var plugin = this.getPluginConstructor(p.pluginName); 
			//check again
			if($type(plugin)!='class') {
				throw new Error('JRCmsPlugins.registerPlugin: This should never happen. But why does it do? ('+p.pluginName+')');
				return false;
			}
			//set an instance name if not provided 
			if (!$defined(plugin._pluginInfo)) { 
				plugin._pluginInfo = { name: p.pluginName.substr(0,2).toLowerCase() + p.pluginName.substr(2) }; 
	 	   	}
			
			try{
				//now create the instance
				window[plugin._pluginInfo.name] = new plugin($merge(this.options,{cmp: p.cmp}), plugin._pluginInfo.name);
				this.setPluginState(p.pluginName, 'ready');
				//debug info
				this.jrLog(('P:I>> Plugin: '+p.pluginName+' with Version: '+window[plugin._pluginInfo.name].getVersion()+' registered!'));
	 	   		//process a successHandler
	 	   		//delay is set to ensure proper state of DOM
	 			if($type(p.successHandler)=='function') p.successHandler.delay(20, this);
	
			} catch(e){
				this.setPluginState(p.pluginName, 'failed');
				$(this.getPluginScriptId(p.pluginName)).dispose();
	 	   		//debug info
				this.jrLog('F#>> Can not register Plugin: '+p.pluginName+'.  '+e); 
			}
			
	 	} 
	 
	 	/** 
	 	 * Refresh an allready loaded plugin by calling a refresh method
	 	 * instead of the initialize method
	 	 *  
	 	 * As parameter an object is expected
	 	 * 	p {
	 	 *  	pluginName: <class name>,		mandatory class name  
	 	 *  	successHandler: <function>		optional function to be called while instantiated
	 	 *  } 
	 	 */ 
	 	,refreshPlugin: function(p){
	 		
	 		//ensure proper processing, check parameter
	 		if($type(p.pluginName) != 'string') throw new Error('JRCmsPlugins.registerPlugin with wrong parameter called!');
	
			//retrieve the plugin constructor
			var plugin = this.getPluginConstructor(p.pluginName); 
			//check again
			if($type(plugin)!='class') {
				throw new Error('JRCmsPlugins.refreshPlugin: This should never happen. But why does it do? ('+p.pluginName+')');
				return false;
			}
			//set an instance name if not provided 
			if (!$defined(plugin._pluginInfo)) { 
				plugin._pluginInfo = { name: p.pluginName.substr(0,2).toLowerCase() + p.pluginName.substr(2) }; 
	 	   	}
			
			try{
				//now try to refresh the instance
				if($defined(window[plugin._pluginInfo.name]) && $defined(window[plugin._pluginInfo.name].refresh)) {
					//call the refresh method instead of initialize
					window[plugin._pluginInfo.name].refresh($merge(this.options,{cmp: p.cmp}));
					this.setPluginState(p.pluginName, 'refreshed');
					//debug info
					this.jrLog(('P:I>> Plugin: '+p.pluginName+' with Version: '+window[plugin._pluginInfo.name].getVersion()+' refreshed!'));
		 	   		//process a successHandler
		 	   		//delay is set to ensure proper state of DOM
		 			if($type(p.successHandler)=='function') p.successHandler.delay(20, this);
					
				} else if($defined(window[plugin._pluginInfo.name])) {
					//try again to register the plugin
					this.registerPlugin(p);
				}
	
			} catch(e){
				this.setPluginState(p.pluginName, 'failed');
				$(this.getPluginScriptId(p.pluginName)).dispose();
	 	   		//debug info
				this.jrLog('F#>> Can not refresh Plugin: '+p.pluginName+'.  '+e); 
			}
	 	} 

	 	/** 
	 	 * function that loads the given plugin, which could be called for a single
	 	 * compressed plugin or with options provided by the parameter object
	 	 * 
	 	 * As parameter an object or the pluginName is expected
	 	 * 	p {
	 	 *  	pluginName: <class name>,		mandatory class name  
	 	 *  	cmp: <true/false>,				optional compressed (default: true)
	 	 *  	successHandler: <function>		optional function to be called while instantiated
	 	 *  } 
	 	 */ 
	 	,loadPlugin: function(p) { 
	 		//ensure correct processing in case of simple call
	 		if($type(p)=='string') var p = new Object({pluginName:p});
	 		//debug info
	 		//DEBUG: this.jrLog('T:4#>> Plugin: '+p.pluginName+' loading', 4); 
	 		//Might already been loaded
	 		if ($defined(this.getPluginConstructor(p.pluginName))){ 
	 	 		//Attention: the check for still loaded plugin will fail in case of 
	 	 		//subsequent calling for same pluginName 
	 			//DEBUG: this.jrLog('T:4#>> Plugin: '+p.pluginName+' already loaded', 4);
	 	 		//try to refresh the plugin
	 	 		this.refreshPlugin(p);
	 			return true; 
	 		}
	 		//set initial plugin state
	 		this.setPluginState(p.pluginName, 'loading');
	 		//determine plugin url, for traces with separate variable
	 		var url = this.getPluginDir(p.pluginName) + "/" + p.pluginName.toLowerCase() +
	 					(($defined(p.cmp) && !p.cmp)?(".js"):(".cmp.js"));
	 		//Now load the script, by using of the asset functionality
	 		var asset = new Asset.javascript(url, {
	 						'class': this.getPluginScriptId(p.pluginName),
							onload: function(){
						 		this.setPluginState(p.pluginName, 'loaded');
						 		//DEBUG: this.jrLog('T:4#>> Plugin: '+p.pluginName+' loaded', 4);
					 			//to ensure re-entrance a copy of parameter object has to be used
						 		this.registerPlugin($merge(p));					 		
							}.bind(this)
	 					});
	
	 		//To speed things up, we start loading the script file before pinging it.
			if(this.options.jr_debug >= 6)
				this.pluginPing({
					src: url, 
					pluginName: p.pluginName,
					successHandler:	function(p){
						//DEBUG: this.jrLog('T:4#>> Plugin: '+p.pluginName+' exists', 4);
						;},
					failHandler: function(p){
						this._pluginLoadStatus[p.pluginName] = 'failed';	
						this.jrLog('F#>> Plugin: '+p.pluginName+' with url: '+p.src+' missing');}});
	
	 		return true; //not evaluated due to the asynch Asset request. 
	 	}
	 	
	 	/** 
	 	 * function that loads a list of plugins defined in an array of 
	 	 * objects(plugin options), e.g.:
	 	 * 
	 	 * 		[{pluginName:<class_name>,cmp:<true/false>,userLevel:<nnnn>}]
	 	 *  
		 * @access public
	 	 */ 
	 	,loadPlugins: function(pluginList, successHandler) {
	
	 		// load all plugins and create instances
	 		pluginList.each(function(item1, index1){
				if(this.readRights(this.getUserLevel(), item1.userLevel)) {
	
					if((index1+1)>=pluginList.length) item1['successHandler'] = successHandler;
					this.loadPlugin(item1);
	
				} else if ( index1 == pluginList.length-1 ) {
	 				 if($defined(successHandler)) successHandler.delay(20, this);
	 			}
					
	 		}.bind(this));
	
	 	}
	 	
	 	/** 
	 	 * function that register (update) a list of still loaded plugins defined 
	 	 * in an array of objects(plugin options), e.g.:
	 	 * 
	 	 * 		[{pluginName:<class_name>,cmp:<true/false>,userLevel:<nnnn>}]
	 	 *  
		 * @access public
	 	 */ 
	 	,updateRegisteredPlugins: function(pluginList, successHandler) {
	
	 		pluginList.each(function(item1, index1){
	 			
				if(this.readRights(this.getUserLevel(), item1.userLevel)) {
	
					if((index1+1)>=pluginList.length) item1['successHandler'] = successHandler;
					this.registerPlugin(item1);
						
				} else if ( index1 == pluginList.length-1 ) {
					
		 			 if($defined(successHandler)) successHandler.delay(20, this);
	 			}
						
	 		}.bind(this));
	 	}
 	
	}); //implements end
})();	

/* ==================================================================== */
/* ======================= C O R E ==================================== */
/* ==================================================================== */
/**
 * JRCMS Core Class
 *
 * @author Jens Raabe <jens@raabe-berlin.de>
 */
(function(){

	JRCmsCore.implement({

		Implements: [Options, JRCmsPlugins, JRCmsApi]
	
		,options: {
			jr_lang: 				'de'
			,jr_debug: 				false
			,jr_webmasterLevel: 	'999'			//user level of webmaster
			,jr_refreshVMenu: 		false
			,jr_loginHidden:		false			// login hidden, same CONST in cConfig.php
			,jr_loginload: 			'home'
			,jr_loginDialogHidden:	true			// hide/show the dialog while loaded 	
			,jr_loginDispUserRole:	undefined		// switch between disp of userlevel/userlevel description
			,jr_heightOfLogin:		105				// height of Login/Logout dialog in px, e.g. when styles change
			,jr_heightOfLoginH: 	24				// height of header of Login/Logout dialog, when styles change
			,jr_dbischanged:		false
			,jr_divFrame:			'divFrame'		// used to hide web page 
				
			,jr_loginFailure:		false			// internal used only
		}
		
		/*Public*/
		,getClassId: function() {
			return this._coreInfo.classId;
		}
	
		/*Public*/
		,getVersion: function() {
			return (this._coreInfo.version+'_'+
					this._coreInfo.revision.slice(this._coreInfo.revision.search(/:.+/)+1)).replace(/\$/g,'').replace(/ /,'');
		}
	
		/* ==================================================================== */
		/* CMS Core: Init				                                        */
		/* ==================================================================== */
		/* Parameter:
		 * - options:			combinition of jrCmsInit and JRCmsApi 
		 * - instanceName:		have to be jrCMS
		 * 
		 * Sequence:
		 * 
		 * 	- setOptions
		 * 	- hideMainFrameLoading
		 * 	- loadPlugins
		 * 		- loadPlugin/registerPlugin							instance with options of jrCMS 
		 * 		- loadPostProcessing.loadStyleFiles					global/project styles
		 * 		- loadPostProcessing.registerFunctions				functions of jrCMS for hist. pool
		 * 		- loadPostProcessing._coreStatus					"ready"
		 * 		- loadPostProcessing.updateXtpTable					internally controlled by userlevel
		 * 		- loadPostProcessing.reloadPage('home')				depending on options.jr_loadPage
		 * 		- loadPostProcessing.showMainFrameLoaded
		 *		- loadPostProcessing.getLoginSection				provides the login dialog
		 */

		/**
		 * Constructor: initialize
		 * Creates an instance of the JRCmsCore class.
		 *
		 * @param object options, string instanceName
		 * @access public
		 */
		,initialize: function(options, instanceName){
		
			this.setOptions(options);
			this.setOptions({jr_phpSRC: 'jrcms.php'});
			this.hideMainFrameLoading();
			
			//language support
			this.retrieveLangFile(this.options.jr_srcUrl+'lang/', 'lang.' + this.options.jr_lang,
					function(){this.setOptions({jr_langLoaded: true});
						//alert(this.getLangItem('data_length'));
					}.bind(this));
			
			//load plugins, instantiated them and as postprocessing
			// - core functions will be registered
			// - the initial location will be loaded
			this.loadPlugins(this.options.jr_pluginList, this.loadPostProcessing);
	
		}

		/**
		 * initial post processing routine
		 * 
		 * Tooks very complicated but the idea is to use a central register function which
		 * consider concurrent tasks due to parallel plugin loading
		 * The supplied successHandler performs the final steps
		 *  - update of database (functions)
		 *  - init first content
		 *    
		 * @access private
		 */
		,loadPostProcessing: function(){
			
			//load general styles which should overwrite plugin settings if needed
			this.loadStyleFiles();
			
			//assuming loading of history pool is finished, core functions will be registered
			//we do not wait for complete initialization of all plugins
			//BUT to ensure the proper loading the initial task is supplied as successHandler
			this.registerFunctions(
				{instance: this._coreInfo.instance,
				classId:this.getClassId(),
				functions:[{functionName:'getContent', methodId: 1, functionType: 'ajax' }
							,{functionName:'getContent', methodId: 2, functionType: 'aeditor' }
							,{functionName:'getLogin', methodId: 4, functionType: 'ajax' }
							,{functionName:'setLang', methodId: 10, functionType: 'js' }
							,{functionName:'reloadPage', methodId: 11, functionType: 'js' }
							,{functionName:'chgWindowSize', methodId: 13, functionType: 'ajax' }
							,{functionName:'notImplemented', methodId: 16, functionType: 'js' }
							,{functionName:'showAbout', methodId: 17, functionType: 'ajax' }
							,{functionName:'getContentForNode', methodId: 21, functionType: 'js' }
				],
				successHandler: 
				function(){
					//the initial loading and instantiation is finished
					this.jrLog("C:I>> imacs Version: "+this.getVersion()+" ready!");
					this.jrLog("C:I>> ========== jrCMS Init Sequence is finished ============");
					//set core status
					this._coreStatus = "ready";
					//try to update the procedure table filled by plugins
					//only executed for webmaster
					this.updateXtpTable();
					//call the first content by using the reload function
					if (this.options.jr_loadPage) this.reloadPage('home');
					//ensure visibility of completely loaded body
					this.showMainFrameLoaded();
					//initialize login
					this.getLoginSection(this.getUserLevel());
				}.bind(this)} //319
			);
		}
		
		/* ==================================================================== */
		/* CMS Core: Content (general)                                          */
		/* ==================================================================== */

		/**
		 * general get routine which retrieves and display a standard html content
		 * as well as updated vertical menu together with styles update
		 * 
		 * p.id		- node ID
		 * p.root	- root node ID
		 * p.cssid	- styles ID
		 * 
		 * @param object p, element el
		 * @access public
		 */
		,getContent: function(p, el){
	
			try{
				var methodId = 1; //unique id of method within class
	
				//prepare Ajax history
				if(!$defined(p.a) || p.a != 'getcntNode') 
					var hpParam = this.addRequestHP(this.getClassId()+methodId, p, 'getContent');
				
				//set additional parameter
				if(!$defined(p.a)) p.a = 'getcnt';
				p.mt = this.options.jr_menuType;
			
				this.processRequest({
					requestType: 'xol',
					url: this.options.jr_srcUrl + this.options.jr_phpSRC,
					data: p,
					_hp: hpParam
				});			
				
			} catch(err) {
				this.jrLog("F#>> jrCMS.getContent failure: "+err);
			}
		}
		
		/**
		 * general get routine which retrieves and display a standard html content
		 * together with the horizontal menu if a vertical menu item was defined as 'id'.
		 * Like as 'getContent' the menu structures are retrieved, styles as defined by the 
		 * 'cssid' and the content of the given 'id'
		 * 
		 * p.id		- node ID
		 * p.root	- root node ID
		 * p.cssid	- styles ID
		 * p.l		- label string of the node (shall be unique, otherwise first occurence in DB)
		 * 
		 * @param object p, element el
		 * @access public
		 */
		,getContentForNode: function(p, el){
		
			try{
				var methodId = 21; //unique id of method within class
			
				p.a = 'getcntNode';
				p.mt = this.options.jr_menuType;
			
				this.getContent(p);
				
			} catch(err) {
				this.jrLog("F#>> jrCMS.getContentForNode failure: "+err);
			}
		}
	
		/* ==================================================================== */
		/* CMS Core: Login / Logout                                             */
		/* ==================================================================== */

		/**
		 * event routine retrieves the login mask 
		 * 
		 * @param string (act)
		 * @access public
		 */
		,getLogin: function(p){
	
			try{
				var methodId = 4; //unique id of method within class
				
				if(!$defined(p)) 
					var p = new Object();
				if(!$defined(p.a)) 
					p.a = 'gin';			//initial mask or 'chgpw' for password change
				if(!$defined(p._div))
					p._div = this.options.jr_divMain;
				if($defined(this.options.jr_loginDispUserRole))
					p.dsp_ur = true;
				
				$(p._div).empty();
				this.processRequest({
					requestType: 'xol',
					url: this.options.jr_srcUrl + this.options.jr_phpSRC,
					_hp: undefined,
					data: p,
					onSuccess: (function(resp, xml, xol){
								//3) write the dialog
								this.writeDialog( xol,
									{ 'dlgContent': p._div
									 ,'dlgText': this.getLangItemSet()
									 ,'dlgUrl': this.options.jr_srcUrl
									 ,'dlgSrc':this.options.jr_phpSRC
									 //,'dlgDebug': this.options.jr_debug
									 ,'dlgUseFieldset' : false
									 });
							}.bind(this))
				});
				
			}catch(err){
				this.jrLog("F#>> jrCMS.getLogin failure: "+err);
			}
		}
	
		/**
		 * event routine performs the LOGIN 
		 * 
		 * @param string $act
		 * @access public
		 */
		,login: function(p){
			
			try{
				var methodId = 6; //unique id of method within class
				
				//we have to ensure that the frames behind have the correct format
//				if(!this.options.jr_loginHidden)
//					$('dlgWrapperlogin').fireEvent('hide');
				this.saveDialog({'a':(!$defined(p)?'in':p.a),'formOnly':['loginDialog']},
						$lambda,		//no pre-processing 
						(function(passed){	//but post-processing
							if(passed && !this.options.jr_loginFailure)
								this.loadPlugins(this.options.jr_pluginList,
										function(){
											// at least needed for installation but the 
											// the webmaster could wait ;-)
											this.updateXtpTable();
											// overwrite loaded styles
											this.loadStyleFiles();
											// update the login section
											this.getLoginSection(this.getUserLevel());
											// simulate page refresh
											this._reloadPageCalled = null;
											this.reloadPage('home');
										}.bind(this));
							else {
								return false;
							}
						 }.bind(this)));
				
			} catch(err){
				this.jrLog("F#>> login failure: "+err);
			}
		}
	
		/**
		 * event routine performs the LOGOUT 
		 * 
		 * @param string $act
		 * @access public
		 */
		,logout: function(p){
			
			try{
				var methodId = 7; //unique id of method within class

				//close the logindialog
				this.fireEvent('hide');

				if(!this.options.jr_loginHidden) {
					$('dlgWrapperlogin').fireEvent('hide');
					this.saveDialog({'a':(!$defined(p)?'out':p.a),'formOnly':['loginDialog']},
							$lambda,		//no pre-processing 
							(function(passed){	//but post-processing
								if(passed)
									this.reloadPage('ALL');
								else
									return false;
							 }.bind(this))
					);
				} else {
					this.processRequest({
							url: this.options.jr_srcUrl + this.options.jr_phpSRC,
							data: {'a':(!$defined(p)?'out':p.a)},
							evalScripts: true, 
							onSuccess: function(txt){
									this.reloadPage('\'ALL\'');
							}.bind(this)
					});			
				}
			} catch(err){
				this.jrLog("F#>> logout failure: "+err);
			}
		}
	
		/* ==================================================================== */
		/* CMS Core: BackUp DB		                                            */
		/* ==================================================================== */

		//TODO: do not delete	
		//	/**
		//	 * TODO: Ajax history ???
		//	 * 
		//	 * @param none
		//	 * @access public
		//	 */
		//	,backup: function (){
		//		
		//		var methodId = 9; //unique id of method within class
		//
		//		if (this.options.jr_backupDB) {
		//			var p = new Object();
		//			p.a = 'backup';
		//			
		//			var req = new Request({
		//				url: 'src/jrCMSMain.php',
		//				method: 'post',
		//				data: p,
		//				async: true,
		//				link: 'chain',	// requests will be chained to prevent wrong init sequence
		//				onSuccess: function(txt){
		//					// do nothing
		//				}.bind(this),
		//				onFailure: function(err){
		//					this.jrLog("F#>> jrCMS backup "+err);
		//				}.bind(this)
		//			});
		//			req.send();
		//		}
		//	}
		
		/* ==================================================================== */
		/* CMS Core: Language Support                                           */
		/* ==================================================================== */

		/**
		 * event routine set the language
		 * 
		 * @param string $lang
		 * @access public
		 */
		,setLang: function(p, el){
	
			var methodId = 10; //unique id of method within class
	
			if(!$defined(p)) var p = new Object();
			if(!$defined(p.lang)) p.lang = this.options.jr_lang;
			p.a = 'setLang';
			p._div = this.options.jr_divMain;
			
			if (this.options.jr_lang != "") {

				this.processRequest({
					requestType: 'html',
					url: this.options.jr_srcUrl + this.options.jr_phpSRC,
					successHandler: function(){
										window.jrCMS.reloadPage('ALL');
									}.bind(this),
					data: p
				});
			}
		}
	
		/* ==================================================================== */
		/* CMS Core: Reload Page                                                */
		/* ==================================================================== */

		/**
		 * reload
		 *	var methodId = 11; 
		 */
		 
		/* ==================================================================== */
		/* CMS Core: Functions Table (DB)                                       */
		/* ==================================================================== */

		/**
		 * updates the xTP table in database
		 * 
		 * @param array pluginlst
		 * @access private
		 */
		,updateXtpTable: function() {
			
			if($defined(window.jrCmsRshSource))
				if(this.accessRights(this.getUserLevel(), this.options.jr_webmasterLevel)){
					// build a request to
					var p = new Object();
					p.a = 'updateXtpTable';
					
					p.procs = new Array();
					$A(jrCmsRshSource.histSrcPool).each(function(item, index){
						var hsp = JSON.decode(item);
						if($defined(hsp) && $defined(hsp.functionType) && hsp.functionType != ""){
							p.procs[index] = JSON.decode(item);
						}
			 		});
					p.procs = JSON.encode(p.procs);
	
					//retrieve and process the content
					this.processRequest({
						url: this.options.jr_srcUrl + this.options.jr_phpSRC,
						data: p,
						onSuccess: function(txt, xmltxt){
							if(txt == '1' ) this.jrLog("C:I>> jrCMS xTP table updated ");
							;
						}.bind(this)
					});			
				}
			else
				if(this.options.jr_histDebug) throw new Error('jrCMS.updateXtpTable jrCmsRshSource no available');
		}
		
		/* ==================================================================== */
		/* CMS Core: Window Size                                                */
		/* ==================================================================== */

		/**
		 * Plugin loader, to be used once while webspace is loading
		 * 
		 * @param 
		 * @access public
		 */
		,chgWindowSize: function(p, el){
	
			try{
				var methodId = 13; //unique id of method within class
			
				//prepare Ajax history
				var hpParam = this.addRequestHP(this.getClassId()+methodId, p, 'chgWindowSize');
	
				//set additional parameter
				p.a = 'getcnt';
				p.mt = this.options.jr_menuType;
	
				//retrieve and process the content
				this.processRequest({
					url: this.options.jr_srcUrl + this.options.jr_phpSRC,
					data: p,
					_hp: hpParam,
					requestType: 'xol',
					onSuccess: function(txt, xmltxt, xol){
						var xmlDoc = xmltxt;
						// 1) update the style
						if($defined(xol.cssdata)) {
							this.writeCssData(xol.cssdata);
							// 2) update switch
							//by convention two style entries in DB for this option are necessary, one after another
							var strHtml = '<span class="nav" onClick="window.jrCMS.chgWindowSize({id:'+p.id+',root:'+p.root;
							strHtml+=',cssid:'+((this._windowSizeDown)?(p.cssid+1):(p.cssid-1))+'});">';
							strHtml+='<img src="src/images/spacer.gif" width="16px" height="12px" /></span>';
							$(this.options.jr_divWindowSize).empty().set('html', strHtml);
							this._windowSizeDown = (this._windowSizeDown)?(false):(true);
						}	
						// to be tended by using functions of 'this' class
					}.bind(this)
				});			
	
			} catch(err) {
				this.jrLog("F#>> jrCMS.chgWindowSize failure: "+err);
			}
		}
		
		/* ==================================================================== */
		/* CMS Core: Generic Not Implemented                                    */
		/* ==================================================================== */

		/**
		 * 
		 * @param object $p
		 * @access public
		 */
		,notImplemented: function (p){
			var methodId = 16; //unique id of method within class
			alert('sorry not implemented');
		}
	
		/* ==================================================================== */
		/* CMS Core: Show About                                                 */
		/* ==================================================================== */

		/**
		 * show the copy right notice, project informations as well as all
		 * contibutive informations provided by the plugins in the main frame
		 * Remark: This function replaces the previous used showSrcVersions
		 * 
		 * @param none
		 * @access public
		 */
		,showAbout: function(){
	
			try{
				var methodId = 17; //unique id of method within class
				
				//defined the parameter object
				var p = new Object();
				//prepare Ajax history
				var hpParam = this.addRequestHP(this.getClassId()+methodId, p, 'showAbout');
	
				//the task is not needed for history
				p.a = 'getAbout';
			
				//retrieve and process the about notice
				this.processRequest({
					url: this.options.jr_srcUrl + this.options.jr_phpSRC,
					data: p,
					_hp: hpParam,
					onSuccess: function(txt){
					
						var strHtml = '<span class="about" onClick="window.open(\'http://jrcmsdev.sourceforge.net\'); return false;">';
						strHtml+= '<img src="src/images/imacs_logo.png" /></span><br /><hr class="about" /><br />';
						//take over the provided copy right notice
						strHtml+= ($defined(txt)?txt:($defined($$('title'))?($$('title')[0].text):('CM System')))+'</b><hr class="about" />';
						var t = MooTools.version;
						strHtml+= 'Core:<br /><blockquote> imacs V'+ this.getVersion() + '<br />on base of MooTools V'+ MooTools.version + '<br />';
						strHtml+= 'under MIT-style license<br />Copyright (c) 2010,2011 Jens Raabe';
						strHtml+= '<p><i>For Code, Documentation  &amp; Developer Team please have a look on: <span class="about" onClick="window.open(\'https://sourceforge.net/apps/trac/jrcmsdev\'); return false;">';
						strHtml+= 'http:\\jrcmsdev.sourceforge.net</span></i></p></blockquote><hr class="about" />';
						strHtml+= 'Active plugins and developer info:<br /><p><table>';
						for (pN in this._pluginLoadStatus){
							//determine the instance name (convention)
							var pIN = pN.substr(0,2).toLowerCase() + pN.substr(2);
							strHtml+= '<tr><td>&nbsp; &gt; '+ pN + ': </td>';
							strHtml+= '<td>ID'+window[pIN].getClassId()+'&nbsp;&nbsp;</td>';
							strHtml+= '<td>V'+window[pIN].getVersion()+'&nbsp;&nbsp;</td>';
							strHtml+= '<td>'+window[pIN]._pluginInfo.developer + '</td></tr>';
						}
						if($defined(window['Xinha']) && $defined(window['Xinha'].version)) 
							strHtml+= '<tr><td>&nbsp; &gt; Xinha: </td><td colspan="2">V'+window['Xinha'].version.Release+'</td></tr>';
						strHtml.replace(/\$/g, "");
						this.writeContentHTML(strHtml, {noEditor: true});
					
					}.bind(this)
				});			
	
			} catch(err) {
				this.jrLog("F#>> jrCMS.showAbout failure: "+err);
			}
		}

		/* ==================================================================== */
		/* CMS Core: #### DEPRECATED FUNCTIONS ####                             */
		/* ==================================================================== */

		,showSrcVersions: function(){
	
			try{
				var methodId = 14; //unique id of method within class
				this.showAbout();
			} catch(err) {
				this.jrLog("F#>> showSrcVersions failure: "+err);
			}
		}
		
		,getSpecialLabelHTML: function (p){
			
			try{
				var methodId = 15; //unique id of method within class
				if($type(p)=='object' && $defined(p.l)) {
					p.a = 'getMnuId';
					var hpParam = this.addRequestHP(this.getClassId()+methodId, p, 'getSpecialLabelHTML');
					this.processRequest({
						url: this.options.jr_srcUrl + this.options.jr_phpSRC,
						data: p,
						_hp: hpParam,
						requestType: 'json'
					});			
				}
			} catch (err) {
				this.jrLog("F#>> getSpecialLabelHTML failure: "+err); 
			}
		}
		
		/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
		
		/**
		 * "loading", "ready" or "failed"
		 * @access private
		 */
		,_coreStatus:			"loading"
		
		/**
		 * by convention first call with small size
		 * @access private
		 */	
		,_windowSizeDown: true
		
     		
		/**
		 * 
		 * @access private
		 */
		,postLoginProcessing: function(){
			//alert('yeahaw');
		}
		
		/**
		 * @param 
		 * @access private
		 */
		,createLoginDialog: function(usrLevel){
			
			//determine the high of right side
			//TODO: a more flexible solution is needed to be flexible for the login location
			if ($defined($$('.minheight_righttaskbox')[0].clientHeight) && $$('.minheight_righttaskbox')[0].clientHeight > 0) {
				this.setOptions({jr_heightOfRMenu: $$('.minheight_righttaskbox')[0].clientHeight});
			} else {
				this.createLoginDialog.delay(500, this);
				return false;
			}
			//if DOM is ready create the login dialog
			this.createDialog({
    			'dlgDragable': false
    			,'dlgSizable': false
    			,'dlgScroller': false
    			,'dlgKillable': false
    			,'dlgParent': $(this.options.jr_divLogin)
    			,'dlgText': this.getLangItemSet()
				,'dlgUrl': this.options.jr_srcUrl
			 	,'dlgSrc':this.options.jr_phpSRC
    			,'dlgContent': 'divLoginDialog'
    			,'dlgType':'login'
    			,'dlgFrameStyle': 'top:0px;right:0px;'
    			,'dlgCssClass': 'loginDlg'
    			,'dlgTitle': (this.getUserLevel() != '000'
    						  ? this.getLangItem('logged_in')
    						  : this.getLangItem('logged_out'))
    			,'dlgWrapperOpt': {'events':{
							'show':function(e){
								$$('.minheight_rightbox')[0].setStyle('height', this.options.jr_heightOfLogin);
								$$('.minheight_righttaskbox')[0].setStyle('height', 
										this.options.jr_heightOfRMenu - this.options.jr_heightOfLogin + this.options.jr_heightOfLoginH);
								}.bind(this)
							,'hide':function(e){
								$$('.minheight_rightbox')[0].setStyle('height', this.options.jr_heightOfLoginH);
								$$('.minheight_righttaskbox')[0].setStyle('height', this.options.jr_heightOfRMenu);
								}.bind(this)
							}}
			});
			
			if(this.options.jr_loginDialogHidden)
				this.toggleHideDialog($('dlgWrapperlogin').retrieve('options'));
			else
				this.showDialog($('dlgWrapperlogin').retrieve('options'));

			//retrieve the login data
			this.getLogin({ a: 'gin'
				 ,ul: usrLevel
	     		,_div: 'divLoginDialog' });
			
		}
		
		/**
		 * @param string userLevel
		 * @access private
		 */
		,getLoginSection: function(usrLevel){
	
			try{
				if ($defined($(this.options.jr_divLogin)) && !this.options.jr_loginHidden){

					$(this.options.jr_divLogin).empty();
					this.createLoginDialog(usrLevel);

				} else if ($defined($(this.options.jr_divLogin))) {
    			
 						var p = new Object();
	    				p.a		= 'gindiv';
	    				p.ul	= usrLevel;
	    				p._div	= 'divLogin';
	    				this.processRequest({
	    						requestType: 'html',
	    						url: jrCMS.options.jr_srcUrl + jrCMS.options.jr_phpSRC,
	    						data: p
	    				});
	    		}
			} catch(err) {
				this.jrLog("F#>> getLoginSection failure: "+err);
			}
		}
	
		/**
		 * @param none
		 * @access private
		 */
		,hideMainFrameLoading: function(){
	
			if($defined($(this.options.jr_divFrame)) && !$defined(this._showFrameLoadingSpinner)) {
				
		 		//1) hide the frame
		 		this.hideFrame(this.options.jr_divFrame);
		 		//2) define the spinner div
				var dflDiv = new Element('div', {
					id: 'dflDiv',
					styles: {
						backgroundColor: 'transparent',
						overflow: 'auto',
						fontFamily: 'microsoft, sans-serif, helvetica, ariel, serif'	
					}});
				$(this.options.jr_divFrame).inject(dflDiv,'before');
		 		var div = new Element('div', {'styles': {'width': 'auto', 'margin': '0px auto', 'text-align': 'center'}});
		 		div.grab(new Element('img', {src: this.options.jr_projURL + 'src/images/prlspinner_big.gif'}));
		 		this._showFrameLoadingSpinner = new Spinner('dflDiv', {
		 			message: this.getLangItem('spinner_msg'), 
		 			img: div});
		 		//3) set global loading flag
		 		this._showFrameLoadingSpinner.show(true);
		 		
			} else {
				;//e.g. refresh the spinner, or hide at least the frame
			}
		}

		/**
		 * @param none
		 * @access private
		 */
		,showMainFrameLoaded: function(){
	
			//the content wasn't loaded
			if ($defined($(this.options.jr_divFrame)) && 
				$(this.options.jr_divFrame).getStyle('display') == 'none' &&
				!this._contentLoadedOnce) {
				
				this.jrLog('C:I>> showMainFrameLoaded waits for form loaded once! ');
				//simulate loaded content
				this._contentLoadedOnce	= true;
				//wait 1 second and start again
				this.showMainFrameLoaded.delay(400, this);
				return false;
			}
			
			//destroy the spinner
			this._showFrameLoadingSpinner.destroy();
			this._showFrameLoadingSpinner = null;
			//destroy the spinner div
			if($defined($('dflDiv'))) this.deleteFrame('dflDiv');
			//use an anonymous function for a delayed activation of main frame
			//to ensure the spinner is removed
			(function(){
				this.showFrame(this.options.jr_divFrame);
				this.jrLog('C:I>> showMainFrameLoaded set to display:block! ');
			}).delay(400,this);
			
		}

		,processDialogValue: function(el, valueName, value){
			switch (valueName) {
			case 'UserName':
				el.addEvent('focus', function(event){
					if (event.target.value == this.getLangItem('u_user')) 
						event.target.value = '';
				}.bind(this));
				return el;
				break;
			case 'UserPass':
				// === special input type password ===
				el.addEvent('focus', function(event){
					if (event.target.value == this.getLangItem('u_pw')) 
						event.target.value = '';
				}.bind(this));
				el.addEvent('keydown', function(event){
					if(event.key == 'enter')
						this.login({a:'in'});
				}.bind(this));
				return el.set('type', 'password');
				break;
			default:
				break;
			}
			return el;
		}

	}); //implements end
})();	

