      1 /**
      2  * yaf4ajn.js - Frontendcontroller 1.90.0
      3  * Copyright(c) 2009, Deutsche Telekom AG, Products & Innovation
      4  * GNU LESSER GENERAL PUBLIC LICENSE
      5  * http://www.gnu.org/licenses/lgpl-3.0.txt
      6  *
      7  * What is it?
      8  * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      9  * This is the Javascript part of the AJAX Hello World 1.90.0 Demo from Deutsche
     10  * Telekom AG, Products & Innovation for the iX article.
     11  * If this script is included in a webpage, it will start an AJAX call to a server
     12  * and manipulate the html page depending on the answer from the server.
     13  * Data exchange between the server and client happens with JSON data-inter
     14  * -change format.
     15  * Dependencies are prototype 1.6.0.3 and effects.js from script.aculo.us 1.8.2.
     16  * This code is tempered with jslint (see tools/jslint). It has a sound set of
     17  * UnitTests (see tools/jsunit) and it has documentation (see tools/jsdoc and
     18  * docs-directory).
     19  * This file is also available as a compressed version (see tools/compressed and
     20  * yaf4ajn-compressed.js in js-directory.)
     21  *
     22  * Where to go?
     23  * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
     24  * First examine the fecPagecontrol variable in the HTML page (where this
     25  * script is included). It defines what the Frontendcontroller (fec) should do.
     26  * (e.g. scopes - load data given by the scopenames)
     27  *
     28  * After the DOM of the webpage is loaded, these functions will be called
     29  * automatically:
     30  * >>> fec.base.initialize
     31  *     Initialize prototype-JS classes, read fecPagecontrol and start
     32  *     dataLoad
     33  * >>> fec.base.dataLoad
     34  *     loads the data depending on given scopes in fecPagecontrol by firing AJAX
     35  *     requests to the server. If the server gives a valid response (HTTP2XX)
     36  *     processResponse is called
     37  * >>> fec.main.processResponse
     38  *     This function receives the response data from the server and starts to
     39  *     process it. Depending on the response, requests will be fired again, the
     40  *     DOM of the will be manipulated or errormessages will be shown.
     41  *
     42  * Please use Firefox with Firebug-debugger to examine further functionality
     43  * of this script.
     44  *
     45  * Change Log:
     46  * v1.90.0
     47  * - renamed this file to yaf4ajn.js
     48  * - complete namespace refactoring (fec)
     49  * - extracted configuration variables (fec.config)
     50  * - replaced references to production environment (vespa, vsp -> fec)
     51  * - fixed jslint findings
     52  * - added documentation
     53  */
     54 /*! yaf4ajn.js - Deutsche Telekom AG, Products & Innovation */
     55 /*jslint laxbreak: true */
     56
     57
     58 /* ___________ INIT GLOBAL VARIABLES/OBJECTS ________________________________ */
     59
     60 var
     61 	/**
     62 	 * Main object holder (namespace fec -> FrontEndController). In this object
     63 	 * all important variables and functions are placed in a class-type hierarchy.
     64 	 *
     65 	 * @namespace Main object holder.
     66 	 */
     67 	fec = {},
     68 	/**
     69 	 * Holds the data that can be used by special DOM-setter (hook
     70 	 * jsSetterPrefix)
     71 	 *
     72 	 * @type object
     73 	 * @default undefined
     74 	 * @see fec.config.jsSetterPrefix
     75 	 */
     76 	fecSetterValue = undefined,
     77 	/**
     78 	 * Variable for an exception
     79 	 *
     80 	 * @type object
     81 	 * @default undefined
     82 	 */
     83 	e = undefined;
     84
     85 /** instance for class FecMain */
     86 fec.main = undefined;
     87 /** instance for class FecPageControl */
     88 fec.pageControl = undefined;
     89
     90
     91 /* ___________ CONFIGIGURATION  _____________________________________________ */
     92 /**
     93  * Base configuration class
     94  *
     95  * @namespace fec.config
     96  */
     97 fec.config = {
     98 	/**
     99 	 * Element-Id of your HTML-form.
    100 	 *
    101 	 * @type string
    102 	 * @default "fecForm"
    103 	 * @constant
    104 	 */
    105 	htmlIdForm : 'fecForm',
    106 	/**
    107 	 * Prefix of element-Ids, which should be replaced.
    108 	 *
    109 	 * @type string
    110 	 * @default "fecData"
    111 	 * @constant
    112 	 */
    113 	htmlIdDataPrefix : 'fecData',
    114 	/**
    115 	 * Prefix of element-Id, which will be shown after completion  (initially hidden)
    116 	 *
    117 	 * @type string
    118 	 * @default "fecScope"
    119 	 * @constant
    120 	 */
    121 	htmlIdScopePrefix : 'fecScope',
    122 	/**
    123 	 * Prefix of element-Id, which will be hidden after completion (initially visible)
    124 	 *
    125 	 * @type string
    126 	 * @default "fecScopeLoad"
    127 	 * @constant
    128 	 */
    129 	htmlIdLoaderPrefix : 'fecScopeLoad',
    130 	/**
    131 	 * Prefix of JS-Functions, which should be called to set data.
    132 	 *
    133 	 * @type string
    134 	 * @default "fecHookSetData"
    135 	 * @constant
    136 	 * @see fecHookSetDataValuekey
    137 	 */
    138 	jsSetterPrefix : 'fecHookSetData',
    139 	/**
    140 	 * Prefix of JS-Functions, which validate the form
    141 	 *
    142 	 * @type string
    143 	 * @default "fecHookCheckForm"
    144 	 * @constant
    145 	 * @see fecHookCheckFormScopename
    146 	 */
    147 	jsCheckformPrefix : 'fecHookCheckForm',
    148 	/**
    149 	 * URL to the server for ajax request
    150 	 *
    151 	 * @type string
    152 	 * @default "/app/json"
    153 	 * @constant
    154 	 * @see http://www.prototypejs.org/api/ajax/request
    155 	 */
    156 	urlAjaxRequest : '/app/json',
    157 	/**
    158 	 * URL to an errorpage
    159 	 *
    160 	 * @type string
    161 	 * @default "/error.html"
    162 	 * @constant
    163 	 */
    164 	urlErrorpage : '/error.html'
    165
    166 };
    167 // look for miscellaneous config-objects at the end of the file
    168
    169
    170 /* ___________ START INIT AFTER PAGE IS LOADED ______________________________ */
    171 document.observe("dom:loaded", function() { fec.base.initialize(); });
    172
    173
    174 /**
    175  * Base class for the main public fec methods
    176  *
    177  * @namespace fec.base
    178  */
    179 fec.base = {
    180     /**
    181 	 * This function is called, after the DOM is loaded. It prepares the page,
    182 	 * initializes classes and starts an AJAX request to load data from the
    183 	 * server (dataLoad).
    184 	 */
    185 	initialize: function(){
    186 		try { fecHookInitialize(); } catch (e) {}
    187 		if (fec.util.escapeFrame()) { return; }
    188 		fec.util.keypressObserver(document);
    189 		if (fec.main === undefined) {
    190 			fec.main = new FecMain();
    191 		}
    192 		if ('undefined' != typeof fecPagecontrol) {
    193 			fec.pageControl = new FecPageControl(fecPagecontrol);
    194 			if (fec.pageControl.getScopes().length > 0) {
    195 				fec.base.dataLoad();
    196 				$$('form[id^="'+fec.config.htmlIdForm+'"]').each ( function (fe) {
    197 					fec.util.submitObserver(fe.id);
    198 				});
    199 			}
    200 		}
    201 	},
    202 	/**
    203 	 * Prepares the page and starts loading data from the server.
    204 	 */
    205 	dataLoad: function (){
    206 		fec.main.showSpinner(fec.pageControl.getScopes(),true);
    207 		try { fec.form.clearErrorsInDom(); } catch(e){}
    208 		fec.main.getServerData();
    209 	},
    210 	/**
    211 	 * Prepares the page and starts sending data to the server. This function
    212 	 * will be called if a form-submit event (through event observer) fires but
    213 	 * it can also be called directly.
    214 	 */
    215 	dataSend: function () {
    216 		fec.main.showScope('vspScopeFehler',false);
    217 		if (fec.main.checkForm()) {
    218 			fec.main.disableSubmitButtons(true);
    219 			fec.main.sendServerData();
    220 		} else { fec.main.scrollToTop(); }
    221 	}
    222 };
    223
    224 /**
    225  * Values Factory handles updating an html-element with a new value
    226  *
    227  * @namespace fec.valuesFactory
    228  */
    229 fec.valuesFactory = {
    230 	/**
    231 	 * Updates a TD-Element with newValue. If the Value is boolean, default
    232 	 * Strings are set.
    233 	 *
    234 	 * @param {object} element Element that will be updated
    235 	 * @param {object} newValue newValue
    236 	 */
    237 	td: function(element, newValue){
    238 		if (typeof newValue == 'boolean') {
    239 			newValue = newValue === true ? fec.msg.YES : fec.msg.NO;
    240 		}
    241 		$(element).update(newValue.toString());
    242 	},
    243 	/**
    244 	 * Updates a P-element by calling fec.valuesFactory.td .
    245 	 *
    246 	 * @see fec.valuesFactory.td
    247 	 */
    248 	p: function(element, newValue){
    249 		fec.valuesFactory.td(element, newValue);
    250 	},
    251 	/**
    252 	 * Updates a SPAN-element by calling fec.valuesFactory.td .
    253 	 *
    254 	 * @see fec.valuesFactory.td
    255 	 */
    256 	span: function(element, newValue){
    257 		fec.valuesFactory.td(element, newValue);
    258 	},
    259 	/**
    260 	 * Updates a INPUT-element, accordingly to the input type
    261 	 *
    262 	 * @param {object} element Element that will be updated
    263 	 * @param {object} newValue newValue will be HTML-unescaped
    264 	 */
    265 	input: function(element, newValue){
    266 		switch (element.type.toLowerCase()) {
    267 			case 'submit': return true;
    268 			case 'hidden':
    269 				if ($(element.name + 'Hidden')) {
    270 					$(element.name + 'Hidden').update(newValue.toString().unescapeHTML());
    271 				}
    272 				fec.valuesFactory.textarea(element, newValue);
    273 				break;
    274 			case 'password':
    275 			case 'text':
    276 				fec.valuesFactory.textarea(element, newValue);
    277 				break;
    278 			case 'checkbox':
    279 			case 'radio':
    280 				fec.valuesFactory.inputSelector(element, newValue);
    281 				break;
    282 			}
    283 		return false;
    284 	},
    285 	/**
    286 	 * Handles lists of radio- and checbox-tags
    287 	 *
    288 	 * @param {object} element Element that will be updated
    289 	 * @param {object} newValue newValue
    290 	 * @private
    291 	 */
    292 	inputSelector: function(element, newValue){
    293 		fields = document.getElementsByName(element.name);
    294 		for (var i = 0; i < fields.length; i++) {
    295 			if (fields[i].type == 'radio') {
    296 				if (fields[i].value == newValue.toString()) {
    297 					fields[i].checked = true;
    298 				}
    299 			} else {
    300 				if (fields[i].type == 'checkbox') {
    301 					fields[i].checked = (newValue.toString() == "true") ? true : false;
    302 				}
    303 			}
    304 		}
    305 	},
    306 	/**
    307 	 * Updates a TEXTAREA-element
    308 	 *
    309 	 * @param {object} element Element that will be updated
    310 	 * @param {object} newValue newValue will be HTML-unescaped
    311 	 */
    312 	textarea: function(element, newValue){
    313 		element.value = newValue.toString().unescapeHTML();
    314 	},
    315 	/**
    316 	 * Selects the option of a SELECT-element
    317 	 *
    318 	 * @param {object} element Element that will be updated
    319 	 * @param {object} newValue newValue
    320 	 */
    321 	select: function(element, newValue){
    322 		var value = '', opt;
    323 		for (var i = 0; i < element.options.length; i++) {
    324 			if (element.options[i].value == newValue) {
    325 				element.selectedIndex = i;
    326 				return true;
    327 			}
    328 		}
    329 	}
    330 };
    331
    332 /**
    333  * General form checking class - before data is submitted to the server, the
    334  * formdata can be checked through javascript hooks (fecHookCheckFormXYZ). This
    335  * class contains functions for validation.
    336  *
    337  * @namespace fec.util
    338  * @see FecMain.checkForm
    339  */
    340 fec.form = {
    341 	/**
    342 	 * Keeps the state of form-validation, only if this property is true data
    343 	 * will be submitted to the server.
    344 	 *
    345 	 * @type boolean
    346 	 */
    347 	isValid: true,
    348 	/**
    349 	 * Counts the form-errors
    350 	 *
    351 	 * @type number
    352 	 */
    353 	errorCount: 0,
    354 	/**
    355 	 * Prepares the page for JS-Form Validation. This method is called from the
    356 	 * JS-validation-hook-functions.
    357 	 *
    358 	 * @see fecHookCheckFormScopename
    359 	 * @todo extract html to config-class
    360 	 */
    361 	initFormValidation: function() {
    362 		this.errorCount = 0;
    363 		this.isValid = true;
    364 		var s = "";
    365 		s += "\n<div id='vspFormError' class='large box naked image error' style='display:none;'>";
    366 		s += "\n<img src='"+fec.util.getImageRoot()+"fileadmin/VOS/images/16x16/warnung.png' alt='"+ fec.msg.FE004 +"'/>";
    367 		s += "\n<h3>"+ fec.msg.FE003 +":</h3>";
    368 		s += "\n<ul class='errorlist' id='vspFormErrorList'>\n</ul>";
    369 		s += "\n</div>\n";
    370 		s += "\n<div style='clear:both;height:1px'></div>";
    371 		if($('vspFormError') === null) {
    372 			if ($('vspScopeFehler')) {
    373 				$('vspScopeFehler').insert({'after':s});
    374 			}
    375 		} else {
    376 			if ($('vspFormError').childElements().size() < 1) {
    377 				$('vspFormError').replace(s);
    378 			} else {
    379 				this.clearErrorsInDom();
    380
    381 			}
    382 		}
    383 	},
    384 	/**
    385 	 * Adds an error to the DOM and tries to change the class of the surrounding
    386 	 * HTML code of the input field
    387 	 *
    388 	 * @param {object} element - HTML-Element that should me marked
    389 	 * @param {string} errtxt - Errortext
    390 	 */
    391 	setErrorInDom: function(element, errtxt) {
    392 		this.errorCount++;
    393 		try{
    394 			try {
    395 				var trElement = element.up('tr');
    396 				trElement.addClassName('error');
    397 				var tdElements = trElement.select('td');
    398 				if (tdElements.length > 1) {
    399 					tdElements[0].addClassName('left');
    400 					tdElements[1].addClassName('right');
    401 				}
    402 				if (this.errorCount==1) {
    403 					element.focus();
    404 				}
    405 			} catch (e) {}
    406 			if (errtxt) {
    407 				$('vspFormErrorList').insert({'bottom':'<li>'+errtxt+'</li>\n'});
    408 			}
    409 		} catch(e) {}
    410 		this.isValid = false;
    411 	},
    412 	/**
    413 	 * Clear the errors on the page and try to remove error-CSS-classes.
    414 	 */
    415 	clearErrorsInDom: function() {
    416 		// Entferne rote Umrandungen
    417 		var trElements = $$("tr[class*='error']");
    418 		try {
    419 			for(var i=0; i<trElements.length; i++) {
    420 				trElements[i].removeClassName('error');
    421 				trElements[i].select('td').each(function(element) {
    422 					if (element.hasClassName('left')) {
    423 						element.removeClassName('left');
    424 					}
    425 					if (element.hasClassName('right')) {
    426 						element.removeClassName('right');
    427 					}
    428 				});
    429 			}
    430 		} catch (e) {}
    431 		// Entferne Fehlermeldung in Box und blende Box aus
    432 		if ($('vspFormErrorList')) {
    433 			$('vspFormErrorList').update("");
    434 		}
    435 		if ($('vspFormError')) {
    436 			$('vspFormError').hide();
    437 		}
    438 		this.isValid = true;
    439 	},
    440 	/**
    441 	 * Checks if the form ist valid and returns true or shows the ErrorBox.
    442 	 *
    443 	 * @returns {boolean} valid or not
    444 	 */
    445 	checkIfFormValid: function() {
    446 		var warn = $('vspFormError');
    447 		if (this.isValid) {
    448 			warn.hide();
    449 			return true;
    450 		} else {
    451 			if ('undefined' != typeof Effect) {
    452 				var x = new Effect.Appear( warn, { duration:0.3, keepBackgroundImage:true } );
    453 			} else {
    454 				warn.show();
    455 			}
    456 			return false;
    457 		}
    458 	},
    459 	/**
    460 	 * Checks if the value is a number.
    461 	 *
    462 	 * @param {object} val - input value
    463 	 * @returns {boolean} number or not
    464 	 */
    465 	checkTypeNumber: function(val) {
    466 		var regex = /^\d+$/;
    467 		return regex.test(val);
    468 	},
    469 	/**
    470 	 * Converts a date Sring DD.MM.YYYY to date object
    471 	 *
    472 	 * @param {String} val - Datestring in format DD.MM.YYYY
    473 	 * @returns {Date|null} Date-object or null
    474 	 */
    475 	stringToDate: function (val) {
    476 		var regex = /^\d{2}(\.)\d{2}\1\d{4}$/;
    477 		if (regex.test(val)) {
    478 			var parts = val.split(".");
    479 			if (3 == parts.length) {
    480 				var testdate =  new Date(parts[2],parts[1]-1,parts[0]);
    481 				var testyear = testdate.getFullYear();
    482 				var testmonth = testdate.getMonth()+1;
    483 				var testday = testdate.getDate();
    484 				if (testyear == parts[2] && testmonth == parts[1]*1 && testday == parts[0]*1) {
    485 					return testdate;
    486 				}
    487 			}
    488 		}
    489 		return null;
    490 	},
    491 	/**
    492 	 * checks if String is a date
    493 	 *
    494 	 * @param {object} val - input value
    495 	 * @returns {boolean} is a Date-object or not
    496 	 */
    497 	checkTypeDate: function(val) {
    498 		var testdate = fec.form.stringToDate(val);
    499 		return null !== testdate;
    500 	},
    501 	/**
    502 	 * checks if the input value is in the past
    503 	 *
    504 	 * @param {object} val - input value
    505 	 * @returns {boolean}
    506 	 */
    507 	checkTypeDateInPast: function(val) {
    508 		return fec.form.checkTypeDate(val) && fec.form.stringToDate(val) < new Date();
    509 	},
    510 	/**
    511 	 * checks if the input value is a german zipcode
    512 	 *
    513 	 * @param {object} val - input value
    514 	 * @returns {boolean}
    515 	 */
    516 	checkTypePostleitzahl: function(val) {
    517 		var regex = /^[0-9]{5}$/;
    518 		return regex.test(val);
    519 	},
    520 	/**
    521 	 * checks if the input value is a HausnummerMitZusatz ;)
    522 	 *
    523 	 * @param {object} val - input value
    524 	 * @returns {boolean}
    525 	 */
    526 	checkTypeHausnummerMitZusatz: function(val) {
    527 		var regex = /^[1-9]{1}[0-9a-zA-Z \-]*$/;
    528 		return regex.test(val);
    529 	},
    530 	/**
    531 	 * Checks if the input value is a email adresse - intentionally weak check.
    532 	 * Serverside validation should go deeper.
    533 	 *
    534 	 * @param {object} val - input value
    535 	 * @returns {boolean}
    536 	 */
    537 	checkTypeEmail: function(val) {
    538 		var regex = /.*@.*\..*/;
    539 		return regex.test(val);
    540 	},
    541 	/**
    542 	 * regex check helper function
    543 	 *
    544 	 * @param {Regex} regex - the regex test string
    545 	 * @param {string} value - String on which the regex-condition is tested
    546 	 * @returns {boolean}
    547 	 */
    548 	checkRegex: function(regex, val) {
    549 		return regex.test(val);
    550 	},
    551 	/**
    552 	 * Set an HTML input field to readonly.
    553 	 *
    554 	 * @param {object} element - HTML input value element
    555 	 * @param {boolean} setIt - set it to readonly or not
    556 	 */
    557 	setElementReadonly: function(element, setIt) {
    558 		if(setIt) {
    559 			element.readOnly = true;
    560 			element.value = '';
    561 			element.style.backgroundColor = '#EEEEEE';
    562 		} else {
    563 			element.readOnly = false;
    564 			element.style.backgroundColor = '';
    565 		}
    566 	},
    567 	/**
    568 	 * Checks if a string validates to certain conditions and adds errors
    569 	 * if its not.
    570 	 *
    571 	 * @param {object} input - HTML input value element
    572 	 * @param {boolean} manda - is it mandatory?
    573 	 * @param {number} min - minimal string length
    574 	 * @param {number} max - maximal string length
    575 	 * @param {string} text - The beginning of the error message, e.G. "The name" or "The birthday".
    576 	 * @returns {boolean} valid or not
    577 	 */
    578 	checkTypeString: function(input, manda, min, max, text) {
    579 		var retval = true;
    580 		if (input) {
    581 			var s = input.value;
    582 			var err = text.strip();
    583 			if (manda && s.length === 0) {
    584 				fec.form.setErrorInDom(input, err+ " " + fec.msg.FE005);
    585 				retval = false;
    586 			} else if(s.length > 0){
    587 				if (min === null || max === null) {
    588 					if (min === null && max !== null && s.length > max) {
    589 						err += " " + fec.util.formatMessage(fec.msg.FE006, {'MAX' : max});
    590 					}
    591 					if (max === null && min !== null && s.length < min) {
    592 						err += " " + fec.util.formatMessage(fec.msg.FE007, {'MIN' : min});
    593 					}
    594 				} else if (s.length < min || s.length > max) {
    595 					err += " " + fec.util.formatMessage(fec.msg.FE008, {'MIN' : min, 'MAX' : max});
    596 				}
    597 				if (err.length > text.strip().length) {
    598 					fec.form.setErrorInDom(input, err);
    599 					retval = false;
    600 				}
    601 			}
    602 		}
    603 		return retval;
    604 	}
    605 };
    606
    607 /**
    608  * General utils class
    609  *
    610  * @namespace fec.util
    611  */
    612 fec.util = {
    613 	/**
    614 	 * StartTime for alertTime function (for basic profiling)
    615 	 */
    616 	timeStart : new Date().getTime(),
    617
    618 	/**
    619 	 * Formats a message with object-values
    620 	 *
    621 	 * @param {string} msg - message-String with placeholders
    622 	 * @param {object} hobj - object with values
    623 	 */
    624 	formatMessage:function(msg, hobj) {
    625 		var tokens = msg.match(/##\w+##/g);
    626 		for (var i=0; i<tokens.length; i++) {
    627 			var varStr = tokens[i].replace(/#/g, '');
    628 			eval("msg = msg.replace(/"+tokens[i]+"/g, '"+hobj[varStr]+"');");
    629 		}
    630 		return msg;
    631 	},
    632 	/**
    633 	 * Adds functions to observation list, which are executed when DOM ist loaded
    634 	 *
    635 	 * @param {object} func - a function
    636 	 */
    637 	addLoadEvent:function(func) {
    638 		document.observe("dom:loaded",func);
    639 	},
    640 	/**
    641 	 * Adds forms to observation list, which will processed when the submit event
    642 	 * is fired
    643 	 *
    644 	 * @param {object} elem - Form-Element
    645 	 */
    646 	submitObserver: function(elem) {
    647 		Event.observe(elem, 'submit',
    648 			function(event) {
    649 				fec.base.dataSend();
    650 				Event.stop(event);
    651 			}
    652 		);
    653 	},
    654 	/**
    655 	 * Adds keypress-interception for the RETURN KEY - if return key is send,
    656 	 * then the defaultbutton behaviour will be executed or the form will be
    657 	 * processed (dataSend).
    658 	 *
    659 	 * @param {object} elem - document
    660 	 */
    661  	keypressObserver: function (elem) {
    662 		Event.observe(elem, 'keypress',function(event) {
    663  			if(event.keyCode == Event.KEY_RETURN) {
    664 				try {
    665 					var defaultbutton = $('defaultbutton');
    666 					var onclick = defaultbutton.readAttribute("onclick");
    667 					if (null !== onclick) {
    668 						eval(onclick);
    669 					} else {
    670 						fec.base.dataSend();
    671 					}
    672 					Event.stop(event);
    673 				} catch (e) {}
    674 			}
    675 		});
    676 	},
    677 	/**
    678 	 * Sets a gotoPage and processes the form (dataSend) without JS-validation
    679 	 *
    680 	 * @param {string} url - URL where the server should redirect
    681 	 */
    682 	submitWithGotoPage: function (url) {
    683 		fec.pageControl.setGotoPage(url);
    684 		fec.pageControl.setParameter('validate',false);
    685 		fec.base.dataSend();
    686 	},
    687 	/**
    688 	 * Sets a action and processes the form (dataSend) without JS-validation
    689 	 *
    690 	 * @param {string} url - URL where the server should redirect
    691 	 */
    692 	submitWithAction: function (action) {
    693 		fec.pageControl.setControl('paramsSend', action);
    694 		fec.pageControl.setParameter('validate', false);
    695 		fec.base.dataSend();
    696 	},
    697 	/**
    698 	 * Turn an undefined object into an empty string and add a suffix-string
    699 	 *
    700 	 * @param {object} value - tested object
    701 	 * @param {string} suffix - suffix String
    702 	 * @returns {string}
    703 	 */
    704 	chkUndef: function(value, suffix) {
    705 		return ((value) ? value:'') + ((suffix) ? suffix:'');
    706 	},
    707 	/**
    708 	 * Basic profiling - add this function in your code, and the time
    709 	 * between the initial load of the page and the code will be put at the end
    710 	 * of the page
    711 	 *
    712 	 * @param {string} uc - UseCase, addition information
    713 	 */
    714 	alertTime: function(uc){
    715 		var now = new Date().getTime();
    716 		var s = '<br/>' + uc +': '+ (now - fec.util.timeStart) + 'ms';
    717 		$$('body')[0].insert({'bottom':s});
    718 	},
    719 	/**
    720 	 * Reads the URL query parameters, put the keys to lower case and return the
    721 	 * parameters as a hash
    722 	 *
    723 	 * @return {hash} query as hash object
    724 	 */
    725 	getQueryParams: function() {
    726 		var query = new Hash();
    727 		// try wegen %% in URI
    728 		try {
    729 			query = $H(window.location.search.toQueryParams());
    730 			// alle keys toLower
    731 			query = query.inject(new Hash(),
    732 				function(hash, obj) {
    733 					hash.set(obj[0].toLowerCase(),obj[1]);
    734 					return hash;
    735 				}
    736 			);
    737 		} catch (e) {}
    738 		return query;
    739 	},
    740 	/**
    741 	 * Shortcut to openWindow, with less amount of parameters.
    742 	 * @see fec.util.openWindow
    743 	 */
    744 	popup: function(w, h, site, opts) {
    745 		fec.util.openWindow(site, 'popUpWin', w, h, null, null, null, opts, false);
    746 	},
    747 	/**
    748 	 * Pop-Up function
    749 	 *
    750 	 * @param {string} url - popup-url
    751 	 * @param {string} winname - window name
    752 	 * @param {number} width
    753 	 * @param {number} height
    754 	 * @param {null|boolean} toolbr - with a toolbar?
    755 	 * @param {null|boolean} scrollbrs - with scrollbars?
    756 	 * @param {null|boolean} resizable - resizable?
    757 	 * @param {string} winoptions - more options
    758 	 * @param {null|boolean} trackit - refresh parent after popup closes
    759 	 * @returns {object} pop-window object
    760 	 */
    761 	openWindow: function(url, winname, width, height, toolbr, scrollbrs, resizable, winoptions, trackit) {
    762 	    var posx = screen.availWidth/2 - width/2;
    763 	    var posy = screen.availHeight/2 - height/2;
    764 	    var xyPos = 'top=' + posy + ',left=' + posx + ',screenX=' + posx + ',screenY=' + posy;
    765 	    var opt = '';
    766 		opt += 'width=' + width + ',height=' + height;
    767 		if (toolbr !== null) {
    768 			opt += ',toolbar=' + (toolbr ? 'yes':'no');
    769 		}
    770 		if (scrollbrs !== null) {
    771 			opt += ',scrollbars=' + (scrollbrs ? 'yes':'no');
    772 		}
    773 		if (resizable !== null) {
    774 			opt += ',resizable=' + (resizable ? 'yes':'no');
    775 		}
    776 		opt += ', ' + xyPos;
    777 		opt += (winoptions) ? ', '+winoptions : '';
    778 		var newWindow = window.open(url, winname, opt);
    779 		newWindow.focus();
    780 		if (trackit !== null && trackit) {
    781 			var x = new PeriodicalExecuter(function(pe) {
    782 				if (newWindow.closed) {
    783 					pe.stop();
    784 					fec.util.redirectReplace(self.location.href);
    785 				}
    786 			}, 0.5);
    787 		}
    788 		return newWindow;
    789 	},
    790 	/**
    791 	 * Get the document dimensions.
    792 	 *
    793 	 * @returns {object} { width: Number, height: Number }
    794 	 */
    795 	getDimensions: function() {
    796 		var dimensions = document.viewport.getDimensions();
    797 		if (dimensions.width === 0 || dimensions.height === 0) {
    798 			if (document.body) {
    799 				dimensions.width = document.body.offsetWidth;
    800 				dimensions.height = document.body.offsetHeight;
    801 			}
    802 		}
    803 		return dimensions;
    804 	},
    805 	resizeAndCenter: function(width, height) {
    806 		self.resizeTo(width, height);
    807 		self.moveTo(Math.floor((screen.availWidth-width)/2), Math.floor((screen.availHeight-height)/2));
    808 	},
    809 	maximizeWindow: function() {
    810 		window.moveTo(0,0);
    811 		window.resizeTo(screen.availWidth,screen.availHeight);
    812 	},
    813 	escapeFrame: function () {
    814 		if (parent && (self != parent)) {
    815 			try {
    816 				parent.document.body.style.color = '#000000';
    817 				parent.location.href = self.location.href;
    818 				return true;
    819 			} catch (e) {}
    820 		}
    821 		return false;
    822 	},
    823 	setLocation: function(url, toTop) {
    824 		if (toTop && toTop.toString() == 'true') {
    825 			top.location.replace(url);
    826 			top.focus();
    827 		} else {
    828 			self.location.replace(url);
    829 			self.focus();
    830 		}
    831 	},
    832 	getImageRoot: function(url) {
    833 		var p = 'http://localhost:8080';
    834 		if ($('defaultImage')) {
    835 			var src = $('defaultImage').src;
    836 			p = src.substr(0, src.search('fileadmin'));
    837 		}
    838 		p = p.endsWith('/') ? p : p+'/';
    839 		if (url) {
    840 			url = (url.startsWith('/') ? url.sub('/', '') : url);
    841 		}
    842 		return (url) ? p+url : p;
    843 	},
    844 	getPageAddressRoot: function(url){
    845 		var u = '#{protocol}//#{domain}#{port}'.interpolate({
    846 			protocol: location.protocol,
    847
    848 			domain: document.domain,
    849 			port: location.port ? ':' + location.port : ''
    850 			})	+ '/';
    851 		if (url) {
    852 			url = (url.startsWith('/') ? url.sub('/', '') : url);
    853 		}
    854 		return (url) ? u+url : u;
    855 	},
    856 	getErrorPage: function(errid, code) {
    857 		return fec.config.urlErrorpage + ((errid) ? ('?errid='+errid) : '');
    858 	},
    859 	// func muss als "function() { #code# }" übergeben werden
    860 	delay: function(func,time) {
    861 		window.setTimeout(func,time);
    862
    863 	},
    864 	setDatumsfelder: function(eleTag, eleMonat, eleJahr, datum) {
    865 		// fuelle Datumsfelder auf
    866 		var y = "";
    867 		if (eleTag.options.length == 1) {
    868 			for (var i=1; i<=31; i++) {
    869 				y = ( i<=9 ? '0'+i : ''+i );
    870 				$(eleTag).insert({bottom: '\n<option value="'+y+'">'+y+'</option>'});
    871 			}
    872 			$(eleTag).selectedIndex = 0;
    873 		}
    874 		var m = ['Januar','Februar','März','April','Mai','Juni','Juli','August','September','Oktober','November','Dezember'];
    875 		if (eleMonat.options.length == 1) {
    876 			for (i=0; i<m.length; i++) {
    877 				y = i<9 ? '0'+ (i+1) : ''+(i+1);
    878 				$(eleMonat).insert({bottom: '\n<option value="'+ y +'">'+m[i]+'</option>'});
    879 			}
    880 			$(eleMonat).selectedIndex = 0;
    881 		}
    882 		var d = new Date();
    883 		if (eleJahr.options.length == 1) {
    884 			for (i=d.getFullYear(); i>=1900; i--) {
    885 				$(eleJahr).insert({bottom: '<option value="'+i+'">'+i+'</option>'});
    886 			}
    887 			$(eleJahr).selectedIndex = 0;
    888 		}
    889 		if (datum) {
    890 			try {
    891 				d = datum.split('.');
    892 				fec.valuesFactory.select(eleTag, d[0]);
    893 				fec.valuesFactory.select(eleMonat, d[1]);
    894 				fec.valuesFactory.select(eleJahr, d[2]);
    895  			} catch(e){}
    896 		}
    897 	},
    898 	redirectReplace: function(url) {
    899 		fec.util.redirect(url, 10, true);
    900 	},
    901 	redirect: function(url, delay, replace) {
    902 		try { fecHookRedirect(url, delay, replace); return true;} catch(e) {}
    903 		setTimeout(
    904 			function() {
    905 				// Parameter aus aktuellem Pfad mit hinzufügen, aber nur wenn keine ID dabei ist
    906 				// sonst wird per ID immer wieder das Entity auf der Folgeseite geladen (siehe TBE-Beruf)
    907 				var params = window.location.search;
    908 				if (params.length > 0) {
    909 					if (params.toUpperCase().indexOf('ID=') > -1) {
    910 						// ID in den Params -> nichts anhängen
    911 						// todo nur id aus params entfernen
    912 					} else {
    913 						if(url.indexOf('?') != -1) {
    914 							params = '&' + params.substring(1, params.length);
    915 						} else {
    916 							url += params;
    917 						}
    918 					}
    919 				}
    920 				url = url.gsub(' ','');
    921 				if (replace) {
    922 					window.location.replace(url);
    923 				} else  {
    924 					window.location=url;
    925 				}
    926 			}.bind(this), (delay === undefined) ? 10 : delay );
    927 		// wegen Back-Button
    928 		if (fec.main) {
    929 			fec.main.disableForm(false);
    930 		}
    931 		return true;
    932 	},
    933 	capitalizeByChar: function(str, chr) {
    934 		var parts = str.split('/'), len = parts.length;
    935 		if (len == 1) {
    936 			return parts[0];
    937 		}
    938 		var capitalized = str.charAt(0) == '-' ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1)	: parts[0];
    939 		for (var i = 1; i < len; i++) {
    940 			capitalized += '/'+ parts[i].charAt(0).toUpperCase() + parts[i].substring(1);
    941 		}
    942 		return capitalized;
    943 	},
    944 	setKeepAlive: function() {
    945 		var pb = '{ "referer": "'+fec.main.getReferer()+'", "times": ['+new Date().getTime()+'], "request": ["registernext"] }';
    946 		var x = new Ajax.Request(fec.config.urlAjaxRequest,
    947 		{
    948 			contentType: 'application/json',
    949 			asynchronous: true,
    950 			postBody: pb
    951 		});
    952 		return x;
    953 	},
    954 	runKeepAlive: function(delay) {
    955 		var x = new PeriodicalExecuter(fec.util.setKeepAlive, delay ? delay : 60);
    956 	},
    957 	isCompleted: function() {
    958 		return (fec.main && fec.main.completed.length > 0) ? true : false;
    959 	},
    960 	addParamToUrl: function(url, name, value) {
    961 		url += (url.include('?') ? '&' : '?') + name + '=' + encodeURIComponent(value);
    962 		return url;
    963 	},
    964 	replaceAllCss: function(oldCss, newCss) {
    965 		$$('div[class~="'+oldCss+'"]').each ( function(ele) {
    966 			ele.removeClassName(oldCss);
    967 			ele.addClassName(newCss);
    968 		});
    969 	},
    970 	getPageName: function() {
    971 		var path = window.location.pathname;
    972 		return path.substring(path.lastIndexOf('/') + 1);
    973 	},
    974 	eleId: function(eleName) {
    975 		return fec.config.htmlIdDataPrefix + eleName;
    976 	}
    977 };
    978
    979 /**
    980  * Cookie handling class
    981  *
    982  * @namespace fec.cookies
    983  */
    984 fec.cookies = {
    985 	/**
    986 	 * Creates a cookie
    987 	 *
    988 	 * @param {string} cname The name of the cookie.
    989 	 * @param {string} value The value of the cookie.
    990 	 * @param {null|number} hours Number of hours after the cookie will expire.
    991 	 * If hours is null, the cookie will be a session cookie.
    992 	 */
    993 	set: function(cname, value, hours)  {
    994 		var expires = "";
    995 		if (hours) {
    996 			var date = new Date();
    997 			date.setTime(date.getTime()+(hours*60*60*1000));
    998 			expires = "; expires="+date.toGMTString();
    999 		}
    1000 		var cstr = cname + "=" + escape(value) + expires + "; path=/";
    1001 		document.cookie = cstr;
    1002 	},
    1003 	/**
    1004 	 * Returns the cookie value for the given name.
    1005 	 *
    1006 	 * @param {string} cname The name of the cookie to retrieve.
    1007 	 * @param {string} defaultValue The defaultValue for the cookie, if none
    1008 	 * is found.
    1009 	 */
    1010
    1011 	get: function(cname, defaultValue) {
    1012 		var regex = new RegExp(cname + "\\s*=\\s*(.*?)(;|$)");
    1013 		var cookies = document.cookie.toString();
    1014 		var match = cookies.match(regex);
    1015 		if (match) {
    1016 			return unescape(match[1]);
    1017 		}
    1018 		return defaultValue;
    1019 	},
    1020 	/**
    1021 	 * Removes a cookie
    1022 	 *
    1023 	 * @param {string} cname The name of the cookie to be erased.
    1024 	 */
    1025 	erase: function(cname) {
    1026 		fec.cookies.set(cname, '', -1);
    1027 	}
    1028 };
    1029
    1030 /* _____________________ CLASSES (PROTOTYPE) ________________________________ */
    1031
    1032 /**
    1033  * Main processing class - This class holds the main functions for retrieving
    1034  * and submitting data && processing the server response && DOM manipulation
    1035  *
    1036  * @class FecMain
    1037  */
    1038 var FecMain = Class.create({
    1039 	/** URL to the server for ajax request	 */
    1040 	ajaxRequestUrl: fec.config.urlAjaxRequest,
    1041 	/** experimental: if true you can develop html without a server */
    1042 	staticOn: false,
    1043 	/** experimental for staticOn */
    1044 	staticResponseUrl: '/staticResponse',
    1045 	/** holds the initial state of all form-buttons */
    1046 	submitButtons: [],
    1047 	/** holds the data object from the response */
    1048 	data: '',
    1049 	/** list of completed scopes */
    1050 	completed: $A([]),
    1051 	/** flag for JS-form-validation */
    1052 	isFormValid: false,
    1053 	/** will run automatically by instantiation */
    1054 	initialize: function() {
    1055 		// errorinit
    1056 		this.initErrorList();
    1057 	},
    1058 	/**
    1059 	 * Creates an Ajax-request to the server, depending on fecPagecontrol values.
    1060 	 * The server sends data back, that can be processes.
    1061 	 *
    1062 	 * @returns {boolean} true
    1063 	 */
    1064 	getServerData: function(scope){
    1065 		var request =  "", reqObj;
    1066 		var scopeArr = (scope) ? [scope]:fec.pageControl.getScopes();
    1067 		if(!this.isValueInArray(fec.pageControl.getControl('paramsLoad'),'void')){
    1068 			for(var i = 0; i < scopeArr.size(); i++) {
    1069 				if (request !== "") {
    1070 					reqObj = request.evalJSON(true);
    1071 					reqObj.request = [scopeArr[i]];
    1072 					request = Object.toJSON(reqObj);
    1073 				} else {
    1074 					request = this.getRequestBody('load', scopeArr[i]);
    1075 				}
    1076 				var x = new Ajax.Request(this.getAjaxRequestUrl('load'),
    1077 				{
    1078 					contentType:'application/json', postBody: request,
    1079 					onSuccess:function(r){
    1080 						this.processResponse('load',r.responseText);
    1081 					}.bind(this),
    1082 					on403:function(r){
    1083 						fec.util.redirect(fec.util.getErrorPage('getServerData_http'+r.status,'403'));
    1084 					}.bind(this),
    1085 					onFailure:function(r){
    1086 						fec.util.redirect(fec.util.getErrorPage('getServerData_http'+r.status));
    1087 					}.bind(this)
    1088 				});
    1089 			}
    1090 		} else {
    1091 			this.showSpinner(scopeArr,false);
    1092  			try{ executeVoid(); } catch(e){}
    1093 		}
    1094 		return true;
    1095 	},
    1096 	/**
    1097 	 * Creates an Ajax-request to the server, depending on fecPagecontrol values.
    1098 	 * The server receives data through request data (e.G. form-data).
    1099 	 *
    1100 	 * @returns {boolean} true
    1101 	 */
    1102 	sendServerData: function() {
    1103 		var request = this.getRequestBody("send");
    1104 		var x = new Ajax.Request(this.getAjaxRequestUrl('send'),
    1105 		{
    1106 			contentType:'application/json', postBody: request,
    1107 			onSuccess:function(r){
    1108 				this.processResponse('send',r.responseText);
    1109 			}.bind(this),
    1110 			on403:function(r){
    1111 				fec.util.redirect(fec.util.getErrorPage('sendServerData_http'+r.status,'403'));
    1112 			}.bind(this),
    1113 			onFailure:function(r){
    1114 				fec.util.redirect(fec.util.getErrorPage('sendServerData_http'+r.status));
    1115 			}.bind(this)
    1116 		});
    1117 		return true;
    1118 	},
    1119 	/**
    1120 	 * Creates an Ajax-request to a given url and returns the received data.
    1121 	 *
    1122 	 * @param {string} url - Serverurl or a file-url (e.G. ../data.txt)
    1123 	 * @returns {object} received data object
    1124 	 */
    1125 	getAjaxData: function(url) {
    1126 		var data = '';
    1127 		var x = new Ajax.Request(url,
    1128 		{
    1129 			contentType:'application/json', asynchronous:false,
    1130 			onSuccess:function(r){ data = r.responseText; }.bind(this),
    1131 			on403:function(r){ fec.util.redirect(fec.util.getErrorPage('getAjaxData_http'+r.status,'403')); }.bind(this),
    1132 			onFailure:function(r){ fec.util.redirect(fec.util.getErrorPage('getAjaxData_http'+r.status));}.bind(this)
    1133 		});
    1134 		return data;
    1135 	},
    1136
    1137 	/**
    1138 	 * Processes the response from the server
    1139 	 *
    1140 	 * @param {string} type - load or send
    1141 	 * @param {object} response - server response object
    1142 	 */
    1143 	processResponse: function(type, response) {
    1144 		if (response !== "") {
    1145 			//response = response.substring(0, response.length - 1) + ', "error":{"PAGE":{"ERKUND":"","E37P2F":"Juhee","E37XXX":"FEHLER FEHLER"}} }';
    1146 			var vspData = response.evalJSON(true);
    1147 			// vspData fuer spezielle Setter in HTML verfuegbar machen
    1148 			this.data = $H(vspData.data);
    1149 			this.completed = $A(vspData.completed);
    1150 			try { fecHookInitData(this.data); } catch (e) {}
    1151 			if (vspData.redirect !== undefined) {
    1152 				fec.util.redirect(vspData.redirect);
    1153 				return;
    1154 			}
    1155 			this.showContainer();
    1156 			this.processResponseTimes(vspData);
    1157 			if (this.processResponseError(vspData)) {
    1158 				if (vspData.gotoPage !== undefined) {
    1159 					// pc zuruecksetzen, falls er veraendert wurde (submitWithAction)
    1160 					fec.pageControl = new FecPageControl(fecPagecontrol);
    1161 					this.disableSubmitButtons(false);
    1162 					fec.util.redirect(fec.pageControl.getGotoUrl(vspData.gotoPage));
    1163 					return;
    1164 				}
    1165 				this.replaceWerteInDOM(vspData.data);
    1166 				if(vspData.retry && vspData.retry.length > 0) {
    1167 					var retryScope = vspData.retry[0];
    1168 					if (vspData.wait === undefined) { vspData.wait = 1000; }
    1169 					if (type == 'load') {
    1170 						fec.util.delay( function() { fec.main.getServerData(retryScope); }, vspData.wait );
    1171 					}
    1172 					if (type == 'send') {
    1173 						fec.util.delay( function() { fec.base.dataSend(); }, vspData.wait );
    1174 					}
    1175 				} else {
    1176 					this.showSpinner(vspData.completed,false);
    1177 				}
    1178 			} else {
    1179 				// auch bei Fehler, Werte ersetzen
    1180 				this.replaceWerteInDOM(vspData.data);
    1181 				// Ladefehler anstatt Ladespinner
    1182 				if (type == 'load') {
    1183 					fec.util.replaceAllCss('ladebalken','ladebalken-error');
    1184 				} else {
    1185 					this.showSpinner(fec.pageControl.getScopes(),false);
    1186 				}
    1187 				// Hook fuer spezielle Fehlerbehandlung (zb siehe service-anmelden\index.html)
    1188 				try { fecHookHandleError(vspData); } catch (e) {}
    1189
    1190 			}
    1191
    1192 		} else {
    1193 			// ein leerer Response, kann vorkommen, wenn schnell geklicked wird -> keine Fehlerseite anzeigen
    1194 		}
    1195 	},
    1196 	/**
    1197 	 * @param {object} data
    1198 	 */
    1199 	replaceWerteInDOM: function(data) {
    1200 		var domId = false, dataKeys = Object.keys(data), foundId = true;
    1201 		dataKeys = dataKeys.sortBy(function(s) {
    1202 		  return (/.*en$/).test(s) ? 0 : s.length;
    1203 		});
    1204 		try { fecHookInitially(); } catch (e) {}
    1205 		for (var index = 0, len = dataKeys.length; index < len; ++index) {
    1206 			foundId = true;
    1207 			var dataKey = dataKeys[index];
    1208 			domId = fec.config.htmlIdDataPrefix + dataKey.capitalize();
    1209 			// Die Variable fecSetterValue kann von dem zusaetzlichen Setter verwendet werden.
    1210 			fecSetterValue = ('string' == typeof data[dataKey]) ? data[dataKey].escapeHTML():data[dataKey];
    1211 			try {
    1212 				eval('fecHookSetData'+dataKey.capitalize()+'();');
    1213 			} catch (e) {
    1214 				if (this.setElementValue(domId, fecSetterValue) === false) { foundId = false; }
    1215 				// keine IDs per autoincrement updaten
    1216 				if (dataKey.toLowerCase() != 'id') {
    1217 					InnerFor: for (var i = 1; i < 10; ++i) {
    1218 						try {
    1219 							var el = $(domId+i);
    1220 							this.setElementValue(el.id, fecSetterValue);
    1221 						} catch(e) {
    1222 							break InnerFor;
    1223 						}
    1224 					}
    1225 				}
    1226 			}
    1227 		}
    1228 		try { fecHookFinally(); } catch (e) { }
    1229 	},
    1230 	/**
    1231 	 * @param {object} vspData
    1232 	 */
    1233 	processResponseError: function(vspData) {
    1234 		if (vspData.error !== undefined) {
    1235 			fec.main.isFormValid = false; // Formvalidierung beim nächsten submit wieder anstossen
    1236 			this.disableForm(false);
    1237 			this.initErrorList();
    1238 			var errors = vspData.error, errorKey = "", errorValues = "";
    1239 			var errorKeys = Object.keys(errors);
    1240 			for (var index = 0, len = errorKeys.length; index < len; ++index) {
    1241 				errorKey = errorKeys[index];
    1242 				var errorsInner = $A(errors[errorKey]);
    1243 				errorsInner.each(function(err) {
    1244 					this.errorAdd(err,errorKey);
    1245 				}.bind(this));
    1246 				fec.form.setErrorInDom($("vspData"+errorKey));
    1247 			}
    1248 			return false;
    1249 		} else {
    1250 			fec.main.showScope('vspScopeFehler',false);
    1251 		}
    1252 		return true;
    1253 	},
    1254 	/**
    1255 	 * @param {object} vspData
    1256 	 */
    1257 	processResponseTimes: function(vspData) {
    1258 		if (vspData.times !== undefined) {
    1259 			vspData.times.push(new Date().getTime());
    1260 		}
    1261 	},
    1262
    1263 	/**
    1264 	 * @param {object} scope
    1265 	 * @param {boolean} show
    1266 	 */
    1267 	showScope: function(scope, show) {
    1268 		var el = $(scope);
    1269 		if (el) {
    1270 			Element[(show) ? 'show' : 'hide'](el);
    1271 			return true;
    1272 		} else {
    1273 			return false;
    1274 		}
    1275 	},
    1276 	/**
    1277 	 * @param {object} scopes
    1278 	 * @param {boolean} show
    1279 	 */
    1280 	showSpinner: function(scopes, show) {
    1281 		if(Object.isString(scopes)) {
    1282 			scopes = [scopes];
    1283 		}
    1284 		if(Object.isArray(scopes)) {
    1285 			for (var index = 0, len = scopes.length; index < len; ++index) {
    1286 				var scope = scopes[index];
    1287 				try {
    1288 					if (show) {
    1289 						this.showScope(fec.config.htmlIdScopePrefix + scope.capitalize(),false);
    1290 						this.showScope(fec.config.htmlIdLoaderPrefix + scope.capitalize(),true);
    1291 						// Ladebalken Style wieder zuruecksetzen
    1292 						fec.util.replaceAllCss('ladebalken-error', 'ladebalken');
    1293 					} else {
    1294 						this.showScope(fec.config.htmlIdLoaderPrefix + scope.capitalize(),false);
    1295 						if ('undefined' != typeof Effect) {
    1296 							var x = Effect.Appear($(fec.config.htmlIdScopePrefix + scope.capitalize()), { duration: 0.25 });
    1297 						} else {
    1298 							$(fec.config.htmlIdScopePrefix + scope.capitalize()).show();
    1299 						}
    1300 						// Weitere Elemente einblenden per Hook
    1301 						try{ fecHookShowScope(); }catch(e){}
    1302 					}
    1303 				} catch(e) {}
    1304 			}
    1305 		}
    1306 	},
    1307 	/**
    1308 	 * If a container element is in the page, toggle visibility. This is
    1309 	 * usefull, when the dom shouldn't be visibility, before the response has
    1310 	 * arrived.
    1311 	 */
    1312 	showContainer: function() {
    1313 		if ($('container')) {
    1314 			$('container').show();
    1315 		}
    1316 		if ($('containerWarten')) {
    1317 			$('containerWarten').hide();
    1318 		}
    1319 	},
    1320 	/**
    1321 	 * @param {object} element
    1322 	 * @param {boolean} newValue
    1323 	 */
    1324 	setElementValue: function(element, newValue) {
    1325 		var element_id = element;
    1326 		element = $(element);
    1327 		if (!element){
    1328 			element = document.getElementsByName(element_id)[0];
    1329 		}
    1330 		if (!element){ return false; }
    1331 		var method = element.tagName.toLowerCase();
    1332 		var parameter = fec.valuesFactory[method](element, newValue);
    1333 	},
    1334 	/**
    1335 	 *
    1336 	 */
    1337 	getVspDataFormElements: function() {
    1338 		var form = $(fec.config.htmlIdForm), elements = new Hash();
    1339 		if (null !== form) {
    1340 			elements = $H(this.serializeElements(form.getElements(),true));
    1341 			elements.each(function(ele){
    1342 				if(!ele[0].startsWith(fec.config.htmlIdDataPrefix)) {
    1343 					elements.unset(ele[0]);
    1344 				}
    1345 			});
    1346 		}
    1347 		return elements;
    1348 	},
    1349 	/**
    1350 	 * @param {string} type
    1351 	 */
    1352 	getRequestData: function(type) {
    1353 		var elements = fec.main.getVspDataFormElements();
    1354 		if (type == 'send') {
    1355 			this.disableForm(true);
    1356 			try {
    1357 				var data = eval('fecHookGetRequestData' + fec.pageControl.getScopes()[0].capitalize()+'()');
    1358 				elements.update(data);
    1359 			} catch (e) { }
    1360 		}
    1361 		elements.update(this.getUriControlParams());
    1362 		if (elements.size() !== 0) {
    1363 			var formData = elements.toJSON();
    1364 			if (formData == '{}') { return ""; }
    1365 			return formData.gsub(fec.config.htmlIdDataPrefix,'');
    1366 		}
    1367 		return '';
    1368 	},
    1369 	/**
    1370 	 *
    1371 	 */
    1372 	getUriControlParams: function() {
    1373 		var h = fec.util.getQueryParams(), rv = new Hash();
    1374 		// URI Parameter die dem JSON Request angefuegt werden sollen, nur Kleinbuchstaben
    1375 		// confirmid, regid kommen von Bestaetigungsemail
    1376 		var controlParams = ['id','confirmid','regid','wdywtg','wdycf'];
    1377 		if(h.size() !== 0) {
    1378 			controlParams.each(function(key) {
    1379 				if (h.get(key) !== undefined) {
    1380 					rv.set(key.capitalize(),h.get(key));
    1381 				}
    1382 			}.bind(this));
    1383 		}
    1384 		return rv;
    1385 	},
    1386 	/**
    1387 	 * @param {object} elements
    1388 	 * @param {object} options
    1389 	 */
    1390 	serializeElements: function(elements, options) {
    1391 		if (typeof options != 'object') {
    1392 			options = { hash: !!options };
    1393 		}
    1394 		else if (options.hash === undefined) {
    1395 			options.hash = true;
    1396 		}
    1397 		var key, value, submitted = false, submit = options.submit;
    1398 		var data = elements.inject({ },
    1399 			function(result, element) {
    1400 				if (!element.disabled && element.name) {
    1401 					key = element.name; value = $(element).getValue();
    1402 					if ((element.type != 'submit' || (!submitted &&
    1403 						submit !== false && (!submit || key == submit) && (submitted = true)))) {
    1404 						// msch hier besondere behandlung fuer checkboxes
    1405 						if(element.type === 'checkbox' && !(key in result)) {
    1406 							result[key] = (element.checked === true) ? "true":"false";
    1407 						} else {
    1408 							if (value != null) {
    1409 								if (key in result) {
    1410 									// a key is already present; construct an array of values
    1411 									if (!Object.isArray(result[key])) {
    1412 										result[key] = [result[key]];
    1413 									}
    1414 									result[key].push(value);
    1415 								} else {
    1416 									result[key] = value;
    1417 								}
    1418 							}
    1419 						}
    1420 					}
    1421 				}
    1422 			return result;
    1423 		});
    1424 		return options.hash ? data : Object.toQueryString(data);
    1425 	},
    1426
    1427
    1428 	/* ___________ GENERELLE FUNKTIONEN __________ */
    1429 	/**
    1430 	 * Validate if an object is an array and if it contains a given value
    1431 	 *
    1432 	 * @param {object} arr
    1433 	 * @param {object} value
    1434 	 */
    1435
    1436 	isValueInArray: function(arr, value) {
    1437 		if (!Object.isArray(arr)) {
    1438 			return false;
    1439 		} else if (arr.indexOf(value) > -1) {
    1440 			return true;
    1441 		}
    1442 	},
    1443 	/**
    1444 	 * Get the referer, and use experimental staticOn flag
    1445 	 */
    1446 	getReferer: function() {
    1447 		var url = window.location.pathname;
    1448 		if (window.location.search !== "") {
    1449 			url = url + window.location.search;
    1450 		}
    1451 		url = url.replace('yaf4ajn.war','yaf4ajn');
    1452 		if(this.staticOn) {
    1453 			var pos = url.search(/yaf4ajn/);
    1454 			if(pos > 0) {
    1455 				url = url.substring(0,pos) + this.staticResponseUrl +'//yaf4ajn//'+ url.substring(pos + 'yaf4ajn'.length + 1,url.length);
    1456 			} else if (url.search(/index.php/) > 0) {
    1457 				url = '..' + this.staticResponseUrl +'/index.php';
    1458 			} else {
    1459 				url = window.location.pathname.replace(/yaf4ajn/g, this.staticResponseUrl+"/yaf4ajn");
    1460 			}
    1461 			pos = (url.lastIndexOf('\\') > pos) ? url.lastIndexOf('\\') : url.lastIndexOf('/');
    1462 			var file = url.substring(pos+1,url.length);
    1463 			if (file.indexOf('-') > 0) {
    1464 				 file = file.replace(file.match(/-.*\./g),'.');
    1465 				 url = url.substring(0, pos+1) + file;
    1466 			}
    1467 		}
    1468 		return url;
    1469 	},
    1470 	/**
    1471 	 * Get the data for the server request.
    1472 	 *
    1473 	 * @param {string} type - load or send
    1474 	 * @param {string} scope
    1475 	 */
    1476 	getRequestBody: function(type, scope) {
    1477 		var req = '{ "referer": "'+this.getReferer()+'", "times": ['+new Date().getTime()+']';
    1478 		if (type == 'load') {
    1479 			req += ', "request": '+ ((scope) ? ([scope]).toJSON():fec.pageControl.getScopes().toJSON());
    1480 		}
    1481 		if (type == 'send') {
    1482 			req += ', "request": ["' + fec.pageControl.getScopes()[0] + '"]';
    1483 		}
    1484 		req += this.getRequestBodyParams(type);
    1485 		var data = this.getRequestData(type);
    1486 		if (data !== "") {
    1487 			req += ', "data": '+data;
    1488 		}
    1489 		var gotoPage = fec.pageControl.getGotoPage();
    1490 		if (gotoPage !== "") {
    1491 			req += ', "gotoPage": "'+gotoPage+'"';
    1492 		}
    1493 		if (fec.pageControl.getPageId() !== "") {
    1494 			req += ', "pageid": "'+fec.pageControl.getPageId()+'"';
    1495 		}
    1496 		req += ' }';
    1497 		return req;
    1498 	},
    1499 	/**
    1500 	 * Get additional parameters for the server request to control the server.
    1501 	 *
    1502 	 * @param {string} type - load or send
    1503 	 */
    1504 	getRequestBodyParams: function(type) {
    1505 		var params = $H({});
    1506 		if (type == 'load') {
    1507 			var pl = fec.pageControl.getControl('paramsLoad');
    1508 			if ( this.isValueInArray(pl,'relogin') ){
    1509 				params.set('action','relogin');
    1510 				if ($('fecParamWdywtg')) {
    1511 					params.set('wdywtg',$('fecParamWdywtg').value);
    1512 				}
    1513 				pl = pl.without('relogin');
    1514 			}
    1515 			if ( this.isValueInArray(pl,'merge') ){
    1516 				params.set('merge',true);
    1517 				pl = pl.without('merge');
    1518 			}
    1519 			if (pl && pl.size() > 0) {
    1520 				params.set('action',pl[0]);
    1521 			}
    1522 		}
    1523 		if (type == 'send') {
    1524 			var ps = fec.pageControl.getControl('paramsSend');
    1525 			if( ps && ps.size() > 0 ) {
    1526 				params.set('action',ps[0]);
    1527 			}
    1528 		}
    1529 		params = params.merge(fec.pageControl.getParameter());
    1530 		return (params.size() > 0) ? ', "parameter": '+params.toJSON() : "";
    1531 	},
    1532 	/**
    1533 	 * Disable the submit buttons.
    1534 	 *
    1535 	 * @param {boolean} bol - disable or not
    1536 	 */
    1537 	disableSubmitButtons: function(bol) {
    1538 		var butValue;
    1539 		var buttons = $$('input[type="submit"]','input[type="button"]');
    1540 		if (this.submitButtons.size() === 0) {
    1541 			this.submitButtons = buttons.pluck('value');
    1542 		}
    1543 		//this.submitButtons.pop();
    1544 		for (var i = 0, len = buttons.size(); i < len; ++i) {
    1545 			butValue = fec.msg.FE010;
    1546 			for(var y = 0; y < buttons[i].title.length; ++y) {
    1547 				if (y%2 === 0) {
    1548 					butValue += " ";
    1549 				} else {
    1550 					butValue = " " + butValue;
    1551 				}
    1552 			}
    1553 			buttons[i].value=butValue;
    1554 			if (bol) {
    1555 				buttons[i].disable();
    1556 			} else {
    1557 				buttons[i].value = (this.submitButtons[i] === '') ? 'Weiter' : this.submitButtons[i];
    1558 				buttons[i].enable();
    1559 			}
    1560 		}
    1561 	},
    1562 	/**
    1563 	 * Disable the form.
    1564 	 *
    1565 	 * @param {boolean} bol - disable or not
    1566 	 */
    1567 	disableForm: function(bol) {
    1568 		if ($(fec.config.htmlIdForm) !== null) {
    1569 			if (bol) {
    1570 				$(fec.config.htmlIdForm).disable();
    1571 			} else {
    1572 				$(fec.config.htmlIdForm).enable();
    1573 			}
    1574 		}
    1575 	},
    1576 	/**
    1577 	 * Returns the configured server url
    1578 	 *
    1579 	 * @param {string} type - load or send
    1580 	 */
    1581 	getAjaxRequestUrl: function(type) {
    1582 		retVal = this.ajaxRequestUrl;
    1583 		if (this.staticOn) {
    1584 			retVal = ('send' == type) ? this.getReferer()+'.txt.send' : this.getReferer()+'.txt';
    1585 		}
    1586 		return retVal;
    1587 	},
    1588 	/**
    1589 	 * Scroll to top if possible.
    1590 	 */
    1591 	scrollToTop: function() {
    1592     	var yPos =  window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0;
    1593 		if (yPos > 150)	{
    1594 			window.scrollTo(0,100);
    1595 		}
    1596 	},
    1597 	/**
    1598 	 * Scroll to bottom if possible.
    1599 	 */
    1600 	scrollToBottom: function() {
    1601 		window.scrollTo(0,document.viewport.getHeight());
    1602 	},
    1603 	/**
    1604 	 *  Checks the form and sets Variable isFormValid
    1605 	 *
    1606 	 *  @returns {boolean} Form valid or not
    1607 	 */
    1608 	checkForm: function() {
    1609 		var retval = false;
    1610 		// Das Form nur pruefen wenn kein validate und wenn noch nicht geprueft wurde
    1611 		if (fec.pageControl.getParameter().get('validate') === undefined && !fec.main.isFormValid) {
    1612 			try {
    1613 				retval = eval(fec.config.jsCheckformPrefix + fec.pageControl.getScopes()[0].capitalize()+'();');
    1614 			} catch(e) { retval = true; }
    1615 		} else {
    1616 			retval = true;
    1617 		}
    1618 		fec.main.isFormValid = retval;
    1619 		return retval;
    1620 	},
    1621 	/**
    1622 	 * Inits the error output.
    1623 	 */
    1624 	initErrorList: function() {
    1625 		if($('vspScopeFehler') === null) {
    1626 			var s = "\n<div id='vspScopeFehler' style='display:none'>\n</div>\n";
    1627 			Try.these(
    1628 				function() {$$('h1')[0].insert({'after':s});},
    1629 				function() {$('content').insert({'top':s});},
    1630 				function() {$$('body')[0].insert({'top':s});}
    1631 			);
    1632 			$('vspScopeFehler').hide();
    1633 		} else {
    1634 			$('vspScopeFehler').update('');
    1635 		}
    1636 	},
    1637 	/**
    1638 	 * Inits the error layout.
    1639 	 *
    1640 	 * @param {string} errCss - Css class like error, warning, info
    1641 	 * @param {boolean} clear - init and clear existing errors
    1642 	 */
    1643 	initErrorBox: function(errCss, clear) {
    1644 		errCss = errCss.capitalize();
    1645 		if($('vspScopeFehler'+errCss) === null) {
    1646 			var s = "";
    1647 			if (errCss.toLowerCase()=='error') {
    1648 				s += "\n<div id='vspScopeFehler"+errCss+"' class='box large naked image "+errCss.toLowerCase()+"'>";
    1649 				s += "\n<img src='"+fec.util.getImageRoot()+"fileadmin/VOS/images/16x16/warnung.png' alt='"+errCss.toLowerCase()+"'/>";
    1650 				s += "\n<ul id='vspErrorList"+errCss+"'></ul>";
    1651 				s += "\n</div>\n";
    1652 				s += "\n<div style='clear:both;height:1px'></div>";
    1653 			} else {
    1654 				s += "\n<div id='vspScopeFehler"+errCss+"' class='box large image "+errCss.toLowerCase()+"'>";
    1655 				s += "\n<h2 id='vspErrorHeader"+errCss+"'>" + fec.msg.FE001 +"</h2>";
    1656 				s += "\n<img src='"+fec.util.getImageRoot()+"fileadmin/VOS/images/48x48/"+errCss.toLowerCase()+".gif' alt='"+errCss.toLowerCase()+"'/>";
    1657 				s += "\n<ul id='vspErrorList"+errCss+"'></ul>";
    1658 				s += "\n</div>\n";
    1659 				s += "\n<div style='clear:both;height:1px'></div>";
    1660 			}
    1661 			$('vspScopeFehler').insert({'bottom':s});
    1662 			$('vspScopeFehler').hide();
    1663 		} else {
    1664 			if (clear) {
    1665 				$('vspErrorList'+errCss).update('');
    1666 			}
    1667 		}
    1668 	},
    1669 	/**
    1670 	 * Adds an error.
    1671 	 *
    1672 	 * @param {object} err - error object
    1673 	 * @param {string} errtxt - a special errortext, that overrides the default
    1674 	 */
    1675 	errorAdd: function(err, errtxt) {
    1676 		var errObj = fec.main.getErrorObject(err, errtxt);
    1677 		// redirect?
    1678 		if (errObj.get('redir')) {
    1679 			var errUrl = fec.pageControl.getGotoUrl(errObj.get('redir'));
    1680 			// Todo jsunit
    1681 			// Verhindern, dass auf sich selbst geleitet wird
    1682 			if (errUrl === 'index.html' && errUrl === fec.util.getPageName()) {
    1683 				errUrl = '../' + errUrl;
    1684 			}
    1685 			fec.util.redirect(errUrl);
    1686 			return false;
    1687 		}
    1688 		// errObj verarbeiten
    1689 		var errCss = errObj.get('css') ? errObj.get('css').capitalize():"Error";
    1690 		this.initErrorBox(errCss,false);
    1691 		if (errObj.get('head')) {
    1692 			if ($('vspErrorHeader'+errCss)) {
    1693 				$('vspErrorHeader'+errCss).update(errObj.get('head'));
    1694 			}
    1695
    1696 		}
    1697 		//Fehler hinzufuegen
    1698 		$('vspErrorList'+errCss).insert({'bottom':'<li>'+errObj.get('text')+'</li>\n'});
    1699 		//Fehler anzeigen
    1700 		this.showScope('vspScopeFehler',true);
    1701 		this.scrollToTop();
    1702 		this.disableSubmitButtons(false);
    1703 		this.showContainer();
    1704 		return true;
    1705 	},
    1706 	/**
    1707 	 * Resolves the error configuration.
    1708 	 *
    1709 	 * @param {object} err - error object
    1710 	 * @param {string} errtxt - a special errortext, that overrides the default
    1711 	 */
    1712 	getErrorObject: function(err, errtxt) {
    1713 		//erstelle ErrorObjekt
    1714 		if (!errtxt || errtxt === "" || errtxt === "PAGE") {
    1715 			errtxt = fec.errorCode.EUNEXP;
    1716 		}
    1717 		var errid = Object.isString(err) ? err : err.Code;
    1718 		var errObj = new Hash();
    1719 		// Setze den Errortext als Template
    1720 		errObj.set('template', new Template(fec.errorCode[errid] ? fec.errorCode[errid] : errtxt));
    1721 		// setze die Templateparameter
    1722 		var params = new Hash();
    1723 		if (Object.isString(err)) {
    1724 			params.set('0', errtxt);
    1725 		} else {
    1726 			if (Object.isString(err.Args)) {
    1727 				params.set('0', err.Args);
    1728 			} else {
    1729 				if (err.Args) {
    1730 					for (var i = 0; i < err.Args.length; i++) {
    1731 						params.set(''+i, err.Args[i]);
    1732 					}
    1733 				}
    1734 			}
    1735 		}
    1736 		errObj.set('parameter', params);
    1737 		// merge mit vorhandender fec.errorConfig
    1738 		if (fec.errorConfig[errid]) {
    1739 			errObj = errObj.merge(fec.errorConfig[errid]);
    1740 		}
    1741 		var t = errObj.get('template').evaluate(errObj.get('parameter'));
    1742 		errObj.set('text', t);
    1743
    1744 		return errObj;
    1745 	}
    1746 });
    1747
    1748
    1749 /**
    1750  * PageControl class - This class holds the fecPagecontrol variable and
    1751  * offers getters and setters to the values
    1752  *
    1753  * @class FecPageControl
    1754  */
    1755 var FecPageControl = Class.create({
    1756 	/**
    1757 	 * Represents the pageControl object
    1758 	 *
    1759 	 * @type object
    1760 	 * @default false
    1761 	 */
    1762 	pc: false,
    1763 	/**
    1764 	 * Parses the pageControl variable.
    1765 	 */
    1766 	initialize: function(pcString) {
    1767 		if (this.pc === false) {
    1768 			try {
    1769 				// Wenn Fehler, dann saubere Fehlermeldung ausgeben
    1770 				// anstatt SyntaxException
    1771 				this.pc = pcString.evalJSON(true);
    1772 			}catch(e){
    1773 				fec.main.errorAdd('',fec.msg.FE002);
    1774 			}
    1775 			this.processErrorConfig();
    1776 		}
    1777 	},
    1778 	/**
    1779 	 * @returns {array} array of scopes
    1780 	 */
    1781 	getScopes: function(){
    1782 		return Object.isString(this.pc.scopes) ? [this.pc.scopes] : this.pc.scopes;
    1783 	},
    1784 	/**
    1785 	 * @returns {object} Value for the given control-key.
    1786 	 */
    1787 	getControl: function(control){ return this.pc[control]; },
    1788 	/**
    1789 	 * @params {string} control - Key for a server-control
    1790 	 * @params {string} value - Value for a server-control variable
    1791 	 */
    1792 	setControl: function(control, value){
    1793 		this.pc[control] = Object.isArray(value) ? value : [value];
    1794 	},
    1795 	/**
    1796 	 * @returns {object} Server parameters for the request.
    1797 	 */
    1798 	getParameter: function(){
    1799 	 	return (typeof this.pc.parameter == 'undefined') ? $H({}) : $H(this.pc.parameter);
    1800 	},
    1801 	/**
    1802 	 * Additional parameters to control the server (through request).
    1803 	 *
    1804 	 * @params {string} key - key for an additional parameter
    1805 	 * @params {string} val - value for an additional parameter
    1806 	 */
    1807 	setParameter: function(key, value){
    1808 		var params = this.getParameter();
    1809 		params.set(key, value);
    1810 		this.pc.parameter = params;
    1811 	},
    1812 	/**
    1813 	 * Set special parameter for a load request
    1814 	 *
    1815 	 * @params {string} val - a loading parameter like void, merge
    1816 	 */
    1817 	setParamsLoad: function(val){
    1818 	 	this.pc.paramsLoad = val;
    1819 	},
    1820 	/**
    1821 	 * Server can return urls or ids. Ids are the better option, so the server
    1822 	 * doesn't have to know about urls. Urls can be configured completely in the
    1823 	 * frontend.
    1824 	 *
    1825 	 * @params {string} gotoid - An id to a page or an url. Url will be returned
    1826 	 * immediately, and id will be resolved.
    1827 	 */
    1828 	getGotoUrl: function(gotoid){
    1829 		if (gotoid.include('.')) {
    1830 			return gotoid;
    1831 		}
    1832 		var retval = '';
    1833 		gotoid = gotoid.toLowerCase();
    1834 		if (this.pc.gotos && this.pc.gotos[gotoid]) {
    1835 			retval = this.pc.gotos[gotoid];
    1836 		} else {
    1837 			if (this.gotoPageUrls[gotoid]) {
    1838 				retval = this.gotoPageUrls[gotoid];
    1839 			} else {
    1840 				retval = fec.util.getErrorPage('getGoto_'+gotoid);
    1841 			}
    1842 		}
    1843 		return retval;
    1844 	},
    1845 	/**
    1846 	 * Mapping of URLs to Ids
    1847 	 */
    1848 	gotoPageUrls: {
    1849 		page_01_01 : "page0101.html"
    1850 	},
    1851 	/**
    1852 	 * @returns {string} URL where the server should redirect after completion
    1853 	 */
    1854 	getGotoPage: function(){
    1855 	 	return (typeof this.pc.gotoPage == 'undefined') ? "" : this.pc.gotoPage;
    1856 	},
    1857 	/**
    1858 	 * @params {string} gotoPage - URL where the server should redirect after
    1859 	 * completion
    1860 	 */
    1861 	setGotoPage: function(gotoPage){
    1862 	 	this.pc.gotoPage = gotoPage;
    1863 	},
    1864 	/**
    1865 	 * @returns {string} pageId of pagecontrol or empty-string
    1866 	 */
    1867 	getPageId: function() {
    1868 	 	return this.pc.pageid ? this.pc.pageid : "";
    1869 	},
    1870 	/**
    1871 	 * Parse a special error baheviour, given by the pageControl. So you can
    1872 	 * define a special behaviour per page.
    1873 	 */
    1874 	processErrorConfig: function() {
    1875 		if (this.pc.errorconfig) {
    1876 			var errconfs = $H(this.pc.errorconfig);
    1877 			errconfs.each(function(err) {
    1878 				fec.errorConfig[err[0]] = err[1];
    1879 			}.bind(this));
    1880 		}
    1881 	}
    1882 });
    1883
    1884
    1885
    1886
    1887 /* _____________________ CONFIG MISCELLANEOUS _______________________________ */
    1888
    1889 /**
    1890  * ErrorCode Mapping - Maps an ErrorCode from the response to a text.
    1891  *
    1892  * @namespace fec.errorCode
    1893  */
    1894 fec.errorCode = {
    1895 	EUNEXP : 'unexpected error'
    1896 };
    1897
    1898 /**
    1899  * ErrorCode behaviour configuration - You can override the default behavior for
    1900  * an error. These values are available:
    1901  *   redir - redirect immediately to redir-URL
    1902  *   head - title text
    1903  *   css - css classname
    1904  *   text - errortext, overrides fec.errorCode
    1905  *
    1906  * @namespace fec.errorConfig
    1907  */
    1908 fec.errorConfig = {
    1909 	EUNEXP : {
    1910 		head : 'Hinweis',
    1911 		css  : 'info'
    1912 	}
    1913 };
    1914
    1915 /**
    1916  * Messages mappings - Inhere you find all text-fragments that will be shown
    1917  * to the user.
    1918  *
    1919  * @namespace fec.msg
    1920  */
    1921 fec.msg = {
    1922 	YES	: 'Ja',
    1923 	NO	: 'Nein',
    1924 	FE001 : 'Es ist ein Fehler aufgetreten!',
    1925 	FE002 : 'pageControl String nicht valide',
    1926 	FE003 : 'Bitte korrigieren Sie folgende Eingabefelder',
    1927 	FE004 : 'Formularfehler',
    1928 	FE005 : 'ist ein Pflichtfeld.',
    1929 	FE006 : 'darf maximal ##MAX## Zeichen lang sein.',
    1930 	FE007 : 'muss mindestens ##MIN## Zeichen lang sein.',
    1931 	FE008 : 'muss zwischen ##MIN## und ##MAX## Zeichen lang sein.',
    1932 	FE009 : 'Achtung, diese Webseite wurde nicht von der vorgesehenen URL "##HOST##" geladen. Bitte geben Sie hier und in den verlinkten Systemen keine persönliche Daten ein.',
    1933 	FE010 : 'Bitte warten ..'
    1934 };
    1935
    1936
    1937
    1938 /* _____________________ EXAMPLE HOOK IMPLEMENTATIONS _______________________ */
    1939 /**
    1940  * An example for a special data-value setter. Default behaviour is replacing a
    1941  * data value (from the server) with the the corresponding element-id. But if
    1942  * this is not enough you can implement special setters. Valuekey is the
    1943  * data-key.
    1944  *
    1945  * @example fecHookSetDataValuekey
    1946  */
    1947 function fecHookSetDataValuekey() {
    1948 	if (fecSetterValue !== undefined) {
    1949 		// spezial handling of the setterValue
    1950 		$('elementid').update(fecSetterValue);
    1951 	}
    1952 }
    1953 /**
    1954  * An example for a form-validation function, that will be called automatically.
    1955  * "Scopename" must be the same as the page-scope-name, therefore you can have
    1956  * only one check-funktion for every scope you use
    1957  *
    1958  * @example fecHookCheckFormScopename
    1959  */
    1960 function fecHookCheckFormScopename() {
    1961 	fecForm.initFormValidation();
    1962 	var inputs = document.getElementsByTagName('input'), input = false;
    1963 	for (var i = 0, len = inputs.length; i < len; i++){
    1964 		input = inputs[i];
    1965 		// different checks for every formfield
    1966 		if (input.name == fec.util.eleId('html-id-name')) {
    1967 			if (input.value === '') {
    1968 				fecForm.setErrorInDom(input,"html-id-name is empty");
    1969 			}
    1970 		}
    1971 	}
    1972 	return fecForm.checkIfFormValid();
    1973 }
    1974
    1975
    1976