/*!
 * 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 426 2011-01-25 19:45: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.2.1",				//Release.Version.Minor
		revision:		"$Revision: 426 $",		//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 
	/**
	 * 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
	 *	1500	- JRCmsForms	provides integrates niceforms and formcheck asset
	 *	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)
	 * 
	 */
});

/* ==================================================================== */
/* ==================================================================== */
/**
 * 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:		'444'			// will be supplied by cConfig.php  
		//,jr_xinhaContentCss:	'css/xinha.css' // special styles of xinha	
			
		,jr_langTxt:			{}				// 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:		false			// 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_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_spinnerMessage:		false			// true: this.options.jr_langTxt['spinner_msg']
		,jr_spinnerOptions:{					// see mootools doc for other options
	          	containerPosition:{
					 position:'upperRight'
	        	 	,offset: {x:-34,y:10}
		 }}
    };
	
	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 activated during startup to prevent 
				// a clash with the start up spinner
				var reqP = $merge( this._processRequestDefaults, 
							$merge( {useSpinner: (!$defined(this._showFrameLoadingSpinner)?true:false)
									,spinnerOptions: this.options.jr_spinnerOptions
									,spinnerTarget: this.options.jr_divMain
									}, p));
				if(this.options.jr_spinnerMessage)
						reqP.spinnerOptions.message = this.options.jr_langTxt['spinner_msg'];
//				var reqP = $merge( this._processRequestDefaults, 
//								$merge( {useSpinner: (!$defined(this._showFrameLoadingSpinner)?true:false)
//										,spinnerOptions: {//message: this.options.jr_langTxt['spinner_msg']
//												          containerPosition:{position:'upperRight'
//												        	  				,offset: {x:-55,y:10}}}
//										,spinnerTarget: this.options.jr_divMain
//										}, p));
				
				// 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;
				default:	//xml
					reqP = $merge(
							reqP,
							{onSuccess: 
								(!$defined(reqP.onSuccess)
									? function(txt, xmltxt){
										var osp = $merge(reqP.data);	//take a copy
										this.processXmlContainer(xmltxt
												,$merge(osp
														,{'postMainFunc' : ($defined(osp.successHandler)?(osp.successHandler):null)}));
									  }.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))
						    : (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 get routine which processes a XML container 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>
		 * 
		 * XML Container
		 *		<?xml version="1.0" encoding="UTF-8"?>
		 *		<jrcmscontainer>
		 *			<dataset>
		 *				<contxml>
		 *					<conthtml></conthtml>
		 *					<ctrlhtml></ctrlhtml>
		 *					<rightconthtml></rightconthtml>
		 *				</contxml>
		 *				<menuxml>
		 *					<menuhtml></menuhtml>
		 *					<menudiv></menudiv>
		 *				</menuxml>
		 *				 ..
		 *				<stylesxml>
		 *					<cssdata></cssdata>
		 *				</stylesxml>
		 *			</dataset>
		 *		</jrcmscontainer>
		 *
		 * @param string xmlDoc, object p 
		 * @access public
		 */
		,processXmlContainer: function(xmlDoc, p){
			
			var rightFrame = false;
			if(!$defined(p)) var p = new Object();

			// 1) update the style
			if (xmlDoc.getElementsByTagName("cssdata").length > 0) {
				for (var i = 0; i < xmlDoc.getElementsByTagName("cssdata").length; i++){
					this.writeCssData(JSON.decode(xmlDoc.getElementsByTagName("cssdata")[i].firstChild.data));
				}
			}
			
			// 2) update menue
			if(xmlDoc.getElementsByTagName("menudiv").length > 0) {
				for (var i = 0; i < xmlDoc.getElementsByTagName("menudiv").length; i++){
					switch (xmlDoc.getElementsByTagName("menudiv")[i].firstChild.data) {
					case this.options.jr_divHMenu:
						//TODO: ???
						if($defined($(this.options.jr_divHMenu)))
							//update horizontal menu
							rightFrame = this.writeMenuHTML(xmlDoc.getElementsByTagName("menuhtml")[i].firstChild.data,
												{divMenu:this.options.jr_divHMenu});
						else {
							this.jrLog('F#>> processXmlContainer 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(xmlDoc.getElementsByTagName("menuhtml")[i].firstChild.data,
												{divMenu:this.options.jr_divVMenu, 
												 divRightDisplay: ($defined(p.divRightDisplay)
														 ? p.divRightDisplay 
														 : this.options.jr_divRightDisplay)
												 });
						else {
							this.jrLog('F#>> processXmlContainer 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(xmlDoc.getElementsByTagName("menuhtml")[i].firstChild.data,
												{divMenu:this.options.jr_divRMenu});
						else {
							this.jrLog('F#>> processXmlContainer element: '+this.options.jr_divRMenu+' not available !!!');
							//try to restart (to prevent deadlock only 'page' is used)
							window.jrCMS.reloadPage('page');
						}
						break;
					}
				}
			}

			// 3) update task buttons
			if (xmlDoc.getElementsByTagName("ctrlhtml").length > 0) {
				//write&show task buttons
				this.writeButtonsHTML(xmlDoc.getElementsByTagName("ctrlhtml")[0].firstChild.data);
				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 (xmlDoc.getElementsByTagName("conthtml").length > 0) 
				if($type(p.contMainFunc)=='function') 
					p.contMainFunc(xmlDoc.getElementsByTagName("conthtml")[0].firstChild.data);
				else 
					this.writeContentHTML(xmlDoc.getElementsByTagName("conthtml")[0].firstChild.data, p);
			else
				this._contentLoadedOnce = true;

			// 5) update right content (only alternatively to right menu
			if (xmlDoc.getElementsByTagName("rightconthtml").length > 0) {
				if($type(p.contRightFunc)=='function') 
					p.contRightFunc(xmlDoc.getElementsByTagName("rightconthtml")[0].firstChild.data);
				else 
					this.writeRightContentHTML(xmlDoc.getElementsByTagName("rightconthtml")[0].firstChild.data, 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)));

		}
		
		/**
		 * 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 {
				
				if($defined(strHtml)) {
				
					//for debugging only 
					//this.jrLog('T:3>> writeContentHTML.strHtml: '+strHtml.replace(/<\/?[^>]+(>|$)/g, "").substr(0, 120), 3);
					//check parameters
					if(!$defined(p)) 
						var p = new Object();
					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
				if(!$defined(p)) var p = new Object();
				p.postMainFunc = undefined;
				p.divCont = ($defined(p) && $defined(p.divRightCont))?(p.divRightCont):(this.options.jr_divRContent);
				
				if($defined(strHtml)) {
					//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);
		
					// prohibit call of editor for the right frame
					p.noEditor = true;
					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); 
			}
		}
		
		/**
		 * routine which loads an array of style files
		 * Per convention special IE6 style files must be placed at the bottom of the list
		 * the successHandler is called while the first style file was loaded
		 * 
		 * p.cssfiles		- array of style files <default = ['layout.css','navigation.css','content.css','patchIE6.css']>
		 * p.successHandler	- function to be called while first style was loaded <default = undefined>
		 * 
		 */
		,loadStyleFiles: function(p){
			
			try{
				//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 a set of general style files is defined and loaded
				if(!$defined(p)) var p = new Object();
				if(!$defined(p.cssfiles))
					p.cssfiles = ['layout.css'
					             ,'navigation.css'
					             ,'content.css'
					             ,'patchIE6.css'];
				
				p.cssfiles.each(function(item, index){
					if((item.search(/IE/) != -1 && this.options.jr_ie_bug) ||
							item.search(/IE/) == -1	) {
						//load the style
						var asset = new Asset.css((this.options.jr_projURL+'css/'+item),
													{id: 'jrcms-'+(item.substring(0, item.indexOf('.'))).toLowerCase(),
													onload: ((index == 0 && $type(p.successHandler)=='function')
															 ?(p.successHandler.run(p,this))
															 :null)});
					}
				}.bind(this));
				
			} catch (err) {
				var e = ' loadStyleFiles: '+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                                                */
		/* ==================================================================== */
		
		/**
		 * 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';
	
					this.processRequest({
						url: this.options.jr_srcUrl+'jrcms.php',
						data: p,
						async: false, //that must be an sync request
						onSuccess: function(txt){
							p.imgArray = JSON.decode(txt).img;
						}.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)});
				
			} catch(err) {
				this.jrLog('F#>> preLoadImages fail: '+err);
			}
		}
		
		/**
		 * 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({
					url: 'src/jrcms.php',
					method: 'get',
					async: false, //that must be an sync request
					data: p,
					onSuccess: function(i18n){
						i18n = JSON.decode(i18n);
						if($type(i18n)=='object') {
							this.setOptions({jr_langTxt: $merge(i18n, this.options.jr_langTxt)});
						} 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';
				
				//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 {
				if ((cssData[0] != undefined) && (cssData[0].cssid != "none") && (cssData[0].cssid != "")) {
			
					// process the styles
					if( cssData[0].mnu_css != undefined && cssData[0].mnu_css != "" && cssData[0].mnu_css != "none") {
						this.writeCSS(cssData[0].mnu_css);
					}
				
					// ### new meta description ###
					if( cssData[0].mdesc != undefined && cssData[0].mdesc != "" && cssData[0].mdesc != "none") {
						var feld = $$('meta');
						if (feld != undefined) {
							feld.each(function(item, index){
								if (item.name == "description") {
									var description = cssData[0].mdesc;
									item.content = description;
								}
							}.bind(this));
						}
					}
					// ### new meta keywords ###
					if( cssData[0].mkey != undefined && cssData[0].mkey != "" && cssData[0].mkey != "none") {
						var feld = $$('meta');
						if (feld != undefined) {
							feld.each(function(item, index){
								if (item.name == "keywords") {
									var keywords = item.content + " " + cssData[0].mkey;
									item.content = keywords;
								}
							}.bind(this));
						}
					}
				}
			} catch (err) {
				var e = ' writeCssData: '+err;
				if(this.options.jr_debug)	throw new Error(e); 
			}
		}
	
		/**
		 * mapping of style properties
		 *
		 * @param string cssProp
		 * @access private
		 */
		,getStyleId: function (cssProp) {
			var style2style = new Array();
			style2style[0] = new Object();
			style2style[0]['background-color'] = 'bgColor';
			style2style[0]['display'] = 'display';
			style2style[0]['color'] = 'color';
			style2style[0]['background-image'] = 'backgroundImage';
			style2style[0]['background-repeat'] = 'backgroundRepeat';
			style2style[0]['position'] = 'position';
			style2style[0]['top'] = 'top';
			style2style[0]['left'] = 'left';
			style2style[0]['height'] = 'height';
			style2style[0]['width'] = 'width';
			style2style[0]['margin'] = 'margin';
			style2style[0]['margin-top'] = 'marginTop';
			style2style[0]['margin-bottom'] = 'marginBottom';
			style2style[0]['margin-left'] = 'marginLeft';
			style2style[0]['margin-right'] = 'marginRight';
			style2style[0]['padding'] = 'padding';
			style2style[0]['overflow'] = 'overflow';
			style2style[0]['border-width'] = 'borderWidth';
			style2style[0]['border-style'] = 'borderStyle';
			style2style[0]['border-color'] = 'borderColor';
			style2style[0]['border-top-width'] = 'borderTopWidth';
			style2style[0]['border-bottom-width'] = 'borderBottomWidth';
			style2style[0]['border-right-width'] = 'borderRightWidth';
			style2style[0]['border-left-width'] = 'borderLeftWidth';
			style2style[0]['font-size'] = 'fontSize';
			return style2style[0][cssProp];
		}
	
		/**
		 * apply the properties of a selector
		 * Remark: no space characters are allowed
		 *
		 * @param string sel, string pstr
		 * @access private
		 */
		,cssProperty: function (sel, pstr) {
			try{
				//replace linefeed
				pstr.replace('\r','');
				// to be sure no space characters are used
				pstr = pstr.replace(/ /g, "");
	
				while (pstr.length > 0) {
					var prop = pstr.substring(0, pstr.indexOf(';'));
					if (prop.length > 0 && prop.indexOf(':') > 0) {
						var prop_ext = prop.split(':');
						var moddiv = $(sel);
						if (moddiv != undefined) {
							if(this.options.jr_ie_bug && (prop_ext[0].indexOf('mage')>0)) {
									prop_ext[1].replace(/png/,"gif");
							}
							moddiv.setStyle(this.getStyleId(prop_ext[0]),prop_ext[1]);
						} else {
							// we assume a css class
							var modClass = $$('.'+sel);
							modClass.each(function(item, index){
								if(this.options.jr_ie_bug && (prop_ext[0].indexOf('mage')>0)) {
										prop_ext[1].replace(/png/,"gif");
								}
								item.setStyle(this.getStyleId(prop_ext[0]),prop_ext[1]);
							}.bind(this));
						}
						pstr = (pstr.indexOf(';')<pstr.length)?(pstr.substring(pstr.indexOf(';')+1,pstr.length)):('');
					} else {
						pstr = '';
					}
				}
			} 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) {
			// determine selector to process with properties
			cstr.replace(' ','');
			cstr.replace('\n','');
			while(cstr.length > 0) {
				cstr = (cstr.indexOf('.') == 0 || cstr.indexOf('\#') == 0)?(cstr.substring(1,cstr.length)):(cstr);
				var selid = cstr.substring(0,cstr.indexOf('{'));
				if (selid.length > 0) {
					var selprop = cstr.substring(cstr.indexOf('{')+1,cstr.indexOf('}'));
					this.cssProperty(selid, selprop);
					cstr = (cstr.indexOf('}')<cstr.length)?(cstr.substring(cstr.indexOf('}')+1,cstr.length)):('');
				} else {
					cstr = '';
				}
			}
		}

   		/* ==================================================================== */
   		/* 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':'images/help_enabled.gif'}))).grab(
								  new Element('br')).grab(
								 (new Element('a', {'id':'helpClose', 'href':'#'})).grab(
								  new Element('img', {'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({
					url: jrCMS.options.jr_srcUrl + jrCMS.options.jr_phpSRC,
					data: p,
					onSuccess : ((!this.writeRights(this.getUserLevel(), this.options.jr_webmasterLevel))
								? (function(txt, xmltxt){
									this.writeContentHTML(xmltxt.getElementsByTagName("conthtml")[0].firstChild.data, 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
		
		/**
		 * defines the defaults used by the CMS system even in that cases
		 * where the same value is declared as default in mootools
		 * @access private
		 */
		,_processRequestDefaults: {
			method: 'post',		// default for requests
			link: 'ignore',		// default: 'ignore' or 'chain'
			async: true,		// async requests
			evalScripts: false, // don't ask mootools to process js
			onFailure: function(err){
        			this.jrLog("F#>> JRCmsApi.processRequest no content "+err);
			}.bind(this)
		}

		/* @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();
		}
		
		/**
		 * @access private
		 */
		,getHeightOfRMenu: function () {
			if ($defined($$('.minheight_righttaskbox')[0].clientHeight) && $$('.minheight_righttaskbox')[0].clientHeight > 0) {
				this.setOptions({jr_heightOfRMenu: $$('.minheight_righttaskbox')[0].clientHeight});
				return true;
			} else {
				this.getHeightOfRMenu.delay(500, this);
				this.jrLog('T:2>> getHeightOfRMenu waits for form loaded! ', 2);
				return false;
			}
		}

	}); //implements end
})();

/**
 * JRCmsForm Class
 * 
 * Class provides methods for unique processing of formulars/dialogs.
 * 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, containing of:
 *  	valueName			- database representation
 *  	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'}
 *  
 * Predefined validators 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 seperated by spaces. 
 * 
 * The data object described above has to be processed by using the 
 * method: writeDialog with the options:
 * 
 *	writeDialog({'dlgTarget': 		- Target Element
 *				 ,'dlgText': 		- Language Text of values
 *				 ,'dlgUrl': 		- Url prefix of dialog object
 *				 ,'dlgSrc':         - (opt) server script file
 *				 ,'dlgDebug':		- (opt) debugging flag
 *				 ,'dlgLeftWidth': 	- (opt) default '100px'
 *				 ,'dlgRightWidth':  - (opt) default '250px'
 *				 ,'dlgCssClass': 	- (opt) default undefined
 *				 }, <data object>)
 *  
 * The formular 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(p, preProc, postProc)
 *  
 * To complete special select options or input types the
 * 
 *  processDialogValue(el, valueName, value)
 *  
 * have to be redefined to process given elements and provide
 * the inline elements, e.g. by using the predefined methods
 * 
 *  elCheckbox( el, valueName, value, chkArray )
 *  elRadiobox( el, valueName, value, chkArray )
 *  elPassword( el, valueName, value )
 *  elOptions( el, valueName, value, optArray )
 *  
 * @author Jens Raabe <jens@raabe-berlin.de>
 */
(function(){
	
	var _dlgO = {
			dlgTarget: 			null		// will cause an exception if not provided
			,dlgText:			new Object	// placeholder for text elements	
			,dlgUrl:			undefined	// url completed by dialogObject or 
			,dlgSrc:			undefined	// by provided dlgSrc
			//optional parameter	
			,dlgDebug: 			false		// debugging flag
			,dlgUseFieldset:	true		// a frameset is used as wrapper
			,dlgLeftWidth:		'120px'		// width of left column
			,dlgRightWidth:		'300px'		// width of right column
			,dlgCssClass:		'dialog'	// special style class
			,dlgTabIndex:		1			// start index	
	};	   

	JRCmsForm.implement({
		
		/* ==================================================================== */
		/* FORMULAR API                                                         */
		/* ==================================================================== */
		/**
		 * A dialog for an object of items will be created
		 * which is placed in 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( opt, p ) {
			
			try{
				// the dialog header holds the options
				this._dlgH = $merge(_dlgO, opt);
				// we use the dialog header for the header data as well 
				this._dlgH = $merge(this._dlgH, p.header);
				p.data.each(function(item, index){
					if(!$defined($(item.valueGroup.split(':')[0]+'_tbl'))){
						// determin the server script file
						if($defined(item.valueGroup.split(':')[1]))
							this._dlgH.dlgSrc = (item.valueGroup.split(':')[1]).toLowerCase() + '/' +
												(item.valueGroup.split(':')[1]).toLowerCase() + '.php';
						else if(!$defined(opt.dlgSrc))
							throw new Error('without dlgSrc called');
						// build the formular element
						this.dlgForm(item.valueGroup.split(':')[0]
						            ,this._dlgH.dlgUrl+this._dlgH.dlgSrc);
					}
					// shorten the valueGroup, skip the object
					item.valueGroup = item.valueGroup.split(':')[0];
					// write new dialog row
					if(item.valueValidator != 'hidden')
						this.dlgRow(item);
					else
						this.dlgHiddenRow(item);
				}.bind(this));
			} catch (err) {
				var e = ' writeDialog: '+err;
				if(this._dlgH.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(p, preProc, postProc) {
	
			//ensure correct setting
			this._dlgH.elFail = false;
			//pre-processing routine
			if($defined(preProc)) preProc.run();
			//overwrite/set task/action
			if($defined(p.a)) $$('input[name="a"]').set('value',p.a);
			//retrieve all groups to be processed
			var dlgGr = $$('form');
			//clean up the list for easier processing
			//bad run time, but better for usage of last index
			dlgGr.each(function(item, index){
				if(($defined(p.formOnly) && !p.formOnly.contains(item.name.substr(0,item.name.indexOf('_')))) ||
				   ($defined(p.formExclude) && p.formExclude.contains(item.name.substr(0,item.name.indexOf('_')))))
					dlgGr[index] = null;
			});
			dlgGr = dlgGr.clean();
			dlgGr.each(function(item, index){
				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: (dlgGr.length-1==index)?true:false 
								,async: false
								,onSuccess: (this._dlgH.dlgDebug >= 4)
											?(function(response){ 
												// for traces only
												this._dlgH.dlgTarget.set('html',response);
											  }.bind(this))
											:(undefined)});
						}
						// else do nothing
			         }.bind(this)
			         ,onElementFail: function(element, validators) {
			        	 this._dlgH.elFail = true;
			        	 element.setStyle('borderColor','red');
			        	 element.focus();
			        	 alert(this._dlgH.dlgText[validators[0]]);
			         }.bind(this)
			         ,onElementPass: function(element) {
			        	 element.setStyle('borderColor',undefined);
			        	 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(dlgGr.length-1==index && $defined(postProc))
					postProc.run(!this._dlgH.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': this._dlgH.dlgCssClass+'_checkbox'
				   ,'value': (value?1:0)
				   ,'checked': value});
			el.addEvent('click', function(event){
				event.target.value = (event.target.checked?1:0);
			}.bind(this));
			return 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:'required')
			});
		}

		/**
		 * 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;
		}
		
		/* ==================================================================== */
		/* Internal Methods                                                     */
		/* ==================================================================== */
		/**
		 * internal method to complete input elements
		 * 
	 	 * @param element
	 	 * @param string
	 	 * @param string
	 	 * @param array
	 	 * @access global
		 */
		,elInput: function( el, valueName, value, chkArray) {
			// define a wrapping element for easier processing
			var wrapper = new Element('span',{'class':this._dlgH.dlgCssClass+'_checkboxes'});
			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']})); 
			});
			return wrapper;
		}
		
		/**
		 * Build up an INPUT Element
		 * per default a normal input element will be generated, depending on
		 * the definition and used class further options could be used
		 * like as a radio, checkbox, password type
		 * 
	 	 * @param object
	 	 * @access private
	 	 * @return element
		 */
		,dlgInput: function( p ) {
	
			var inp = new Element( 'input', {'id': p.valueName
											 ,'name': p.valueName
											 ,'title': this._dlgH.dlgText[p.valueName]
											 ,'class': (p.valueValidator!="none"?p.valueValidator:'')
											 ,'value': p.value
											 ,'tabindex': this._dlgH.dlgTabIndex++});
			if(p.valueValidator=="disabled") inp.set('disabled', true);
			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);
			
		}
		
		/**
		 * Build up a hidden INPUT Element
		 * 
	 	 * @param object
	 	 * @access private
	 	 * @return element
		 */
		,dlgHiddenInput: function( p ) {
	
			return new Element( 'input', {'id': p.valueName
											 ,'name': p.valueName
											 ,'value': p.value
											 ,'type': 'hidden'});
		}

		/**
		 * Build up an TEXTAREA Element
		 * 
	 	 * @param object
	 	 * @access private
	 	 * @return element
		 */
		,dlgTextarea: function( p ) {
			
			var txt = new Element( 'textarea', {'id': p.valueName
											   ,'name': p.valueName
											   ,'title': this._dlgH.dlgText[p.valueName]
											   ,'class': (p.valueValidator!="none"?p.valueValidator:'')
											   ,'html': p.value
											   ,'tabindex': this._dlgH.dlgTabIndex++});
			if(p.valueValidator=="disabled") txt.set('readonly','yes');
			return txt;
	
		}
	
		/**
		 * Build up an SELECT Element
		 * 
	 	 * @param object
	 	 * @access private
	 	 * @return element
		 */
		,dlgSelect: function( p ) {
			
			var sel = new Element( 'select', {'id': p.valueName
											 ,'name': p.valueName
											 ,'title': this._dlgH.dlgText[p.valueName]
											 ,'class': (p.valueValidator!="none"?p.valueValidator:'')
											 ,'tabindex': this._dlgH.dlgTabIndex++});
			if(p.valueValidator=="disabled") sel.set('disabled', true);
			return ($defined(p.valueDialogMethod.split(':')[1]))
					// per convention the method processDialogValue of the given class 
					// is called to complete the select with options
					? window[p.valueDialogMethod.split(':')[1]].processDialogValue(sel, p.valueName, p.value)
					// otherwise only the given value is shown
					: sel.grab(new Element( 'option', {'value': 0
													  ,'html': p.value}));
		}
		
		/**
		 * Build up an TEXTAREA Element
		 * 
	 	 * @param object
	 	 * @access private
	 	 * @return element
		 */
		,dlgAccordion: function( p ) {
			
			if(!$defined($(p.valueGroup+'_accordion')))
				
				return new Element( 'div', {'id': p.valueGroup+'_accordion'
										   ,'class': 'accordion'});
	
			if(!$defined(this._dlgH[p.valueGroup+'_accordion'])) {
				//we use the header for the Accordion
				this._dlgH[p.valueGroup+'_accordion'] = new Accordion($(p.valueGroup+'_accordion')
																	,'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': this._dlgH.dlgText[p.valueName]
			});
			// create content as textarea wrapped by a div
			var content = new Element( 'div', {'class':'accordion_element'}).grab(this.dlgTextarea(p));
			// position for the new section
			var position = 0;
			// add the section
			this._dlgH[p.valueGroup+'_accordion'].addSection(toggler, content, position);
		}
	
		/**
		 * Depending on the dialog method (first part of valueDialogMethod)
		 * the input field will be created
		 * Supported are input, select and textarea elements
		 * and as special kind an accordion of text areas
		 * 
	 	 * @param object
	 	 * @access private
	 	 * @return element
		 */
		,dlgElement: function( p ) {
			
			return (p.valueDialogMethod.split(':')[0].toLowerCase() == 'input')
					? (this.dlgInput(p))
					: (p.valueDialogMethod.split(':')[0].toLowerCase() == 'select')
					  ? (this.dlgSelect(p))
					  : (p.valueDialogMethod.split(':')[0].toLowerCase() == 'textarea')
						? (this.dlgTextarea(p))
						: (this.dlgAccordion(p));
		}
		
		/**
		 * creates a left table column element with
		 * class = "<valueGroup>_left, valueName" for 
		 * styling purposes
		 * The colspan is used for text (HTML) which use 
		 * one column only
		 * 
	 	 * @param object
	 	 * @access private
	 	 * @return element
		 */
		,dlgColL: function( p, colsp ) {
			
			var cl = new Element('td', {'class': p.valueGroup+'_left '+this._dlgH.dlgCssClass+'_left'+(colsp>1?'_c2 ':' ')+p.valueName
									   ,'colspan': colsp+''
									   ,'html':	(colsp<=1?(this._dlgH.dlgText[p.valueName]+': '):p.value)
 									   ,'styles':{'padding': 0
										   		 ,'width': this._dlgH.dlgLeftWidth.toInt()}
				 					 });
			return cl;
		}
		
		/**
		 * creates a right table column element with
		 * class = "<valueGroup>_right, valueName" for 
		 * styling purposes.
		 * For valueDialogMethod = "disabled" a read only
		 * access is assumed.
		 * The colspan is used for accordions which use 
		 * one column only
		 * 
	 	 * @param object
	 	 * @param integer
	 	 * @access private
	 	 * @return element
		 */
		,dlgColR: function( p, colsp ) {
			
			var cr = new Element('td', {'class': p.valueGroup+'_right '+this._dlgH.dlgCssClass+'_right'+(colsp>1?'_c2 ':' ')+p.valueName
									   ,'colspan': colsp+''
									   ,'styles':{'padding': 0
												 ,'width':(colsp <= 1
												 		   ?this._dlgH.dlgRightWidth.toInt()
														   :this._dlgH.dlgLeftWidth.toInt()+this._dlgH.dlgRightWidth.toInt())}
									 }).grab(this.dlgElement(p));
			return cr;
		}
		
		/**
		 * creates a table row consisting of two columns
		 * the table is identified by <valueGroup>_tbl.
		 * Except Accordions which will use an empty left
		 * column. All accordion rows are placed in the 
		 * right cloumn generated first.
		 * 
	 	 * @param object
	 	 * @access private
		 */
		,dlgRow: function( p ) {
			
			switch (p.valueDialogMethod.split(':')[0].toLowerCase()) {
			case 'text': // text (HTML string), left column is used
				// create a row with combined column (left only)
				// to create an ancore element for the accordion
				$(p.valueGroup+'_tbl').grab((new Element('tr')).grab(this.dlgColL(p, 2)));
				break;
			case 'accordion': // accordion, right column for input is used
				if(!$defined($(p.valueGroup+'_accordion')))
					// create a row with combined column (right only)
					// to create an ancore element for the accordion
					$(p.valueGroup+'_tbl').grab((new Element('tr')).grab(this.dlgColR(p, 2)));
				// afterwards only this sequence is used
				// special processing enlarge an existing row
				this.dlgAccordion(p);
				break;
			default: // left col for description, right col for input is used
				// create a row with two columns (left, right)
				$(p.valueGroup+'_tbl').grab((new Element('tr')).grab(this.dlgColL(p, 1)).grab(this.dlgColR(p, 1)));
			}
		}
		
		/**
		 * writes a hidden input element
		 * 
	 	 * @param object
	 	 * @access private
		 */
		,dlgHiddenRow: function( p ) {
			
			$$('form[name="'+p.valueGroup+'_form"]')[0].grab(
					this.dlgHiddenInput(p),'top');
		}
		
		/**
		 * creates a dialog formular within a fieldset containing
		 * an empty table. The fieldset will get the name <valueGroup>,
		 * the formular the name <valueGroup>_form and the table
		 * the id <valueGroup>_tbl.
		 * The dialog is placed in the element defined as target.
		 * 
	 	 * @param string
	 	 * @param string
	 	 * @access private
		 */
		,dlgForm: function( valueGroup, action ) {
			
			if(!$defined($$('form[name="'+valueGroup+'_form"]')[0])) {
				var nForm = (new Element('form', {'name': valueGroup+'_form'
												 ,'class': this._dlgH.dlgCssClass
					 						     ,'action': action
					 						     ,'method': "post"})).grab(
					 		 this.dlgHiddenInput({valueName:this._dlgH.refName, value:this._dlgH.value}), 'top').grab(
					 		 this.dlgHiddenInput({valueName:'a', value:this._dlgH.a}), 'top').grab(
					 	     new Element('table', {'id': valueGroup+'_tbl'
					 		 				  	 ,'class': this._dlgH.dlgCssClass}));
				
				if(this._dlgH.dlgUseFieldset) {
					var nFieldSet = new Element('fieldset', {'class' : valueGroup+' '+this._dlgH.dlgCssClass});
					nFieldSet.grab(new Element('legend', {'html': this._dlgH.dlgText[valueGroup]}), 'top').grab(nForm, 'bottom');
					this._dlgH.dlgTarget.grab(nFieldSet);
					
				} else {
					this._dlgH.dlgTarget.grab(nForm);
					
				}
				$$('form[name="'+valueGroup+'_form"]')[0].addEvent('submit', function(e){
					//Prevents a default submit event from loading a new page.
					//we don't use the submit event
					if($defined(e)) e.stop();
				});
			}
		}
		
		/**
		 * local variable which holds the actual 
		 * dialog header data
		 */
		,_dlgH: null
	}); //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;
		}
		
		/**
		 * 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.firstPage.bind(this,p) );
	  		pSDiv2.getElement('.pPrev').addEvent('click', this.prevPage.bind(this,p) );
	  		pSDiv2.getElement('.pNext').addEvent('click', this.nextPage.bind(this,p) );
	  		pSDiv2.getElement('.pLast').addEvent('click', this.lastPage.bind(this,p) );
	  		pSDiv2.getElement('.rp').addEvent('change', this.perPageChange.bind(this,p));
	  		pSDiv2.getElement('input').addEvent('keyup', this.pageChange.bind(this,p) );
	  	}

	  	/**
	  	 * 
	  	 */
	  	,firstPage: function(p){
	  		p.page = 1;
	  		this[p.a].run(p, this);
	  	}
	  	
	  	/**
	  	 * 
	  	 */
	  	,prevPage: function(p){
	  		if (parseInt(p.page)>1){
	  			p.page--;		
	  	  		this[p.a].run(p, this);
	  		}
	  	}
	  	
	  	/**
	  	 * 
	  	 */
	  	,nextPage: function(p){
	  		if( (parseInt(p.page)+1) > this.options.jr_maxPage) return;
	  		p.page++;		
	  		this[p.a].run(p, this);
	  	}
	  		
	  	/**
	  	 * 
	  	 */
	  	,lastPage: function(p){
	  		p.page = this.options.jr_maxPage;		
	  		this[p.a].run(p, this);
	  	}

	  	/**
	  	 * 
	  	 */
	  	,perPageChange: function(p){
	  		p.page = 1;
	  		p.perpage = $(this.options.jr_divMain).getElement('.rp').value;		
	  		this[p.a].run(p, this);
	  	}
	  		
	  	/**
	  	 * 
	  	 */
	  	,pageChange: 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.'
 * 
 * 	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 pluginName.replace(/([a-z])([A-Z])([a-z])/g, function (str, l1, l2, l3) { return l1 + "-" + l2.toLowerCase() + l3; }).toLowerCase();
	 	}
	 	
	 	/**
	 	 * 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.registerPluginWithArgs: This should never happen. But why does it do? ('+p.pluginName+')');
			//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); 
			}
			
	 	} 
	 
	 	/** 
	 	 * 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.registerPlugin(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, {
	 						id: 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_heightOfLogin:		100				// height of Login/Logout dialog in px, e.g. when styles change
			,jr_heightOfLoginH: 	21				// height of header of Login/Logout dialog, when styles change
			,jr_dbischanged:		false
			,jr_divFrame:			'divFrame'		// used to hide web page 
		}
		
		/*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();
			
			//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
					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({
					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;
				
				$(p._div).empty();
				this.processRequest({
					requestType: 'json',
					url: this.options.jr_srcUrl + this.options.jr_phpSRC,
					_hp: undefined,
					data: p,
					onSuccess: (function(resp){
								//3) write the dialog
								this.writeDialog({'dlgTarget': $(p._div)
									 ,'dlgText': this.options.jr_langTxt	
									 ,'dlgUrl': this.options.jr_srcUrl
									 ,'dlgSrc':this.options.jr_phpSRC
									 ,'dlgDebug': this.options.jr_debug
									 ,'dlgUseFieldset' : false
									 ,'dlgLeftWidth': '150px'
									 ,'dlgRightWidth': '250px'
									 ,'dlgCssClass': 'logindialog'}, resp);
							}.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
				
				this.saveDialog({'a':(!$defined(p)?'in':p.a),'formOnly':['loginDialog']},
						$lambda,		//no pre-processing 
						(function(passed){	//but post-processing
							if(passed)
								this.loadPlugins(this.options.jr_pluginList,
										function(){
											this.getLoginSection(this.getUserLevel());
											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

				if(!this.options.jr_loginHidden) {
					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,
					onSuccess: function(txt, xmltxt){
						var xmlDoc = xmltxt;
						// 1) update the style
						if (xmlDoc.getElementsByTagName("cssdata").length > 0) {
							this.writeCssData(JSON.decode(xmlDoc.getElementsByTagName("cssdata")[0].firstChild.data));
						}	
						// 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="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="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, 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 string userLevel
		 * @access private
		 */
		,getLoginSection: function(usrLevel){
	
			try{
				if ($defined($(this.options.jr_divLogin)) && !this.options.jr_loginHidden){
			
					if(!$defined($('divLoginDialog'))) {
						$(this.options.jr_divLogin).grab(new Element('div', {
							'id': 'divLoginDialog'
						}));
						$(this.options.jr_divLogin).grab(new Element('div', {'class': 'nf'}));
					}
	
					this.getLogin({ a: 'gin'
								   ,ul: usrLevel
								   ,_div: 'divLoginDialog' });
	
					if(!$defined(this._slideLogin)) {
						this.getHeightOfRMenu();
						this._slideLogin = new Fx.Slide('divLoginDialog', {
							duration: 75	// show und hide unterstützen das event complete nicht ?!? deswegen kurze Duration
						});
						$('loginToggle').addEvent('click', function(e){
							e.stop();
							this._slideLogin.toggle();
						}.bind(this));
						this._slideLogin.addEvent('complete', function() {
							if (this._slideLogin.open) {
								$('loginToggle').src = "images/min_view.gif";
								$$('.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);
							} else {
								$('loginToggle').src = "images/restore.gif";	
								$$('.minheight_rightbox')[0].setStyle('height', this.options.jr_heightOfLoginH);
								$$('.minheight_righttaskbox')[0].setStyle('height', this.options.jr_heightOfRMenu);
							}
						}.bind(this));
						this._slideLogin.hide();
						
					} else {
						
						this._slideLogin.fireEvent('complete');
						//update header
						if(this.getUserLevel() != '000')
							$('spanLoginHeader').set('html',this.options.jr_langTxt['logged_in']);
						else
							$('spanLoginHeader').set('html',this.options.jr_langTxt['logged_out']);
						
					}					
	
				} 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 + 'images/prlspinner_big.gif'}));
		 		this._showFrameLoadingSpinner = new Spinner('dflDiv', {
		 			message: this.options.jr_langTxt['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(1000, 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.options.jr_langTxt["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.options.jr_langTxt["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
})();	

