/*

Tyron's Toolbox (tt.js version 11.10.31) is a small Javascript framework for websites and Intranet sites
Copyright 2011 by Tyron Montgomery / Augenreiz (www.augenreiz.de)

This program is free software. You can redistribute it and/or modify it under the terms of the GNU General Public License (latest version), as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details (http://www.gnu.org/licenses/gpl.html or http://www.gnu.org/licenses/gpl.txt)

------------------------------

G E N E R A L   O V E R V I E W

Tyron's Toolbox provides ...

1) Functions for often-needed tasks, e.g. get_by_class() which returns all DOM elements of a certain class
2) Additional methods on objects and string, e.g. Object.getX() or String.isValidEmail()
3) Functions and methods for simple animation, such as fading in/out
4) Shortcuts & synonyms to existing Javascript functions/methods and to some functions of this framework itself 

------------------------------

S T R U C T U R E   I N   D E T A I L

STARTING UP - PART 1
	$frameworkError
	$USER_AGENT()
	Element.prototype													For older browser
	object(id)
	create(tagName)

DOM ELEMENT METHODS
	Element.getStyle (atr)
	Element.getX ()
	Element.getY ()
	Element.getScroll()
	Element.setScroll(scrollY)
	Element.setAttribute(atr,val)
	Element.fade(obj,timeDelay,timeStep,alphaStart,alphaEnd,alphaStep,evalCode)
	Element.fadeIn(timeDelay,timeStep,alphaStep)
	Element.fadeOut(timeDelay,timeStep,alphaStep)
	Element.setAlpha(alphaValue)													
	
DOM ELEMENT FUNCTIONS
	get_by_class (className,node,tag)									Convert this to an element method? Make it part of object() like in jQuery
	set_dynamic_styles(styleString)
	
STRING FUNCTIONS
	String.trim (options)
	String.isValidEmail()
	String.cleanString()
	
VARIOUS FUNCTIONS
	hex (dez)
	set_cookie(varname,value,expiretime)
	get_cookie
	purged_url(url);
	
GOOGLE ANALYTICS
	ga_event(cat,act,lab,val)
	
SHORTCUTS
	
STARTING UP - PART 2
	Shortcuts & Synonyms of functions and methods

------------------------------

I N T E G R A T I O N

This Javascript can be loaded at any point in your HTML document. As most functions are related to DOM elements make sure your DOM is ready before calling any functions or methods.

To find out whether this framework collides with any other Javascript, especially names of variables, functions or methods, do the following:

1) Add this Javascript to your HTML page after all (!) other Javascripts. If you are running other scripts within the document.body area, e.g. before the closing tag, then load this framework even after those scripts.

2) Un-comment the very last line of this script. This activates an alert box that will display potential errors. The alert will either be "No problems detected." or a list of names. These names show all variables, functions or methods that already exist in other Javascripts your HTML page is loading. Attention: If you are using the Internet Explorer do this test on version 8 or higher. Version 7 will throw errors even though there are none.

3) If the alert displays any names simply rename the according variables, functions or methods and run the test again, until no further problems are found.

------------------------------

D E V E L O P M E N T

NAMING CONVENTIONS
	Global vars:	Leading $ (as in PHP), small letters and new words with capital letters, e.g. theBigLebowski
	Local vars:		Small letters and new words with capital letters, e.g. theBigLebowski
	Functions:		small letters and words separated by underscores, e.g. the_big_lebowski()
	Methods:		Small letters and new words with capital letters, e.g. String.theBigLebowski()
	Classes:		Words separated by underscores and all capital letters, e.g. THE_BIG_LEBOWSKI

RESOURCES FOR NAME DECISIONS
	Reserved words:		https://developer.mozilla.org/en/JavaScript/Reference/Reserved_Words
	Global objects:		https://developer.mozilla.org/en/JavaScript/Reference#Global_Objects
	Functions:			https://developer.mozilla.org/en/JavaScript/Reference#Functions_and_function_scope
	IE specifics:		http://msdn.microsoft.com/en-us/library/ms535240.aspx

FEATURES TO COME
	Drag'n'drop, image gallery, video & audio, form-value processing, cross-fade (create second layer dynamically from first one, then call fade)

*/	


	
//========== STARTING UP - PART 1 =======================================================================================================================================================================================


// This variable gathers the names of all variables, functions and methods that could not be defined. See INTEGRATION above for more details.
$frameworkError = "";


//---------- Determine some browsers ----------

if (typeof USER_AGENT != "undefined") $frameworkError += "USER_AGENT, ";

function USER_AGENT()
	{
	/*
	Functionality:		Determines some browsers & platforms.
						For Javascript in general browser detection may not always be the best choice, but for video functionality there is no other way.
						 
	Last modified:		25 Oct 2011
	*/
	var usag = navigator.userAgent.toLowerCase();
	
	this.android = (usag.indexOf("android") != -1);
	this.chrome = (usag.indexOf("chrome") != -1);
	this.firefox = (usag.indexOf("firefox") != -1);
	this.ipad = (usag.indexOf("ipad") != -1);
	this.iphone = (usag.indexOf("iphone") != -1);
	this.kindle = (usag.indexOf("kindle") != -1);
	
	this.msie = (usag.indexOf("msie") != -1);
	this.msie6 = (usag.indexOf("msie 6") != -1);
	this.msie7 = (usag.indexOf("msie 7") != -1);
	this.msie8 = (usag.indexOf("msie 8") != -1);
	if(this.msie6 && this.msie7) this.msie6 = false;
	if(this.msie7 && this.msie8) this.msie7 = false;
	
	this.smartphone = false;
	var phoneIdentifier = new Array ("240x320","android","benq","blackberry","htc","iemobile","mda","mobile safari","mot-","netfront","nokia","panasonic","philips","pocket pc","portalmmm","sagem","samsung","sda","sgh-","sharp","sie-","skyfire","sonyericsson","symbian","vodafone","windows ce","windows phone","xda");
	for (var i in phoneIdentifier)
		{
		if (usag.indexOf(phoneIdentifier[i]) != -1)
			{
            this.smartphone = true;
			break;
            }
        }
	
	this.screenSize = "M";
	if (usag.indexOf("gt-i9000") != -1 ||
		usag.indexOf("gt-i9100") != -1 ||
		usag.indexOf("ipad") != -1)
		this.screenSize = "L";
	}

if (typeof $user != "undefined") $frameworkError += "$user, ";
$user = new USER_AGENT();


//---------- Expanding the Element model ----------
/*
	Not all browsers support the addition of methods to Element.prototype like this: Element.prototype.xxx = function () { code }.
	The following code provides a work-around. It should work even if other frameworks have already defined a custom Element object or function, e.g. Prototype.js.
	Last modified: 08 Oct 2011
	
	Attention: This work-around doesn't really add methods to the prototype of the original Elements, but to the prototype of a function named Element.
	This means that added methods are not generally available in DOM elements. They must be transferred to the prototype of an individual object before they can be used on that object.
	The following code does this for document.createElement and document.getElementById.
	
*/	
if (typeof object != "undefined") $frameworkError += "object, ";
if (typeof create != "undefined") $frameworkError += "create, ";

if (typeof Element == "undefined")
	{
	Element = function(){}
	
	object = function(id)
		/*
		Functionality:		Replaces document.getElementById() and adds Element.prototype.methods to the object.
							Redefining the original document.getElementById() didn't work on IE7, so we had to define a function with a different name.
							Returns null if object is undefined.
							13 Oct 2011
		*/
		{
		var element = document.getElementById(id);
		if (element != null) for(var key in Element.prototype) element[key] = Element.prototype[key];
		return element;
		}
		
	create = function(tagName)
		/*
		Functionality:		Replaces document.createElement() and adds Element.prototype.methods to the object.
							Redefining the original document.createElement() didn't work on IE7, so we had to define a function with a different name.
							Returns null if element is undefined.
							31 Oct 2011
		*/
		{
		var element = document.createElement(tagName);
		if (element != null) for(var key in Element.prototype) element[key] = Element.prototype[key];
		// Add id
		if (typeof id != "undefined" && id != "")
			{
			if (typeof object(id) != "undefined") return false;
			element.setAttribute("id", id);
			}
		return element;
		}
	}
else
	{
	// Last modified 31. Oct 2011 (added MSIE7 fix)
	function object(id)
		{
		var element = document.getElementById(id);
		if(element == null) return null;
		// MSIE7 supports Element.prototype but doesn't pass all the custom methods to an element for some reason
		if (typeof(element.setScroll) != "function") for(var key in Element.prototype) element[key] = Element.prototype[key];
		return element;
		}
	function create(tagName,id)
		{
		var element = document.createElement(tagName);
		if(element == null) return null;
		// MSIE7 again (see above)
		if (element != null && typeof(element.setScroll) != "function") for(var key in Element.prototype) element[key] = Element.prototype[key];
		
		// Add id
		if (typeof id != "undefined" && id != "")
			{
			if (object(id) != null) return false;
			element.setAttribute("id", id);
			}
		return element;
		}
	}
if (typeof Element.prototype == "undefined") $frameworkError += "Element.prototype, ";




//========== DOM ELEMENT METHODS =======================================================================================================================================================================================


if (typeof Element.prototype.getStyle != "undefined") $frameworkError += "Element.getStyle, ";

Element.prototype.getStyle = function(atr)
	/*
	Functionality:		Returns the value of a style attribute (atr = string) of an object.
						Returns null if atr is not a string or an empty string.
						Returns undefined if no style value can be retreived.
	Last modified:		08 Oct 2011
	Important notes:	Firefox, Safari and Chrome use window.getComputedStyle to determine style settings at runtime. Internet Explorer uses obj.currentStyle.
						Opera knows both, but doesn't understand obj.currentStyle.getAttribute(atr). That's why window.getComputedStyle must be checked first in the if-statement! 
	*/
	{
	
	// Is the attribute defined?
	if (typeof atr != "string" || atr.length < 1) return null;
	// Return style value
	var obj = this;
	if (window.getComputedStyle) return window.getComputedStyle(obj, null).getPropertyValue(atr);
	else if (obj.currentStyle) return obj.currentStyle.getAttribute(atr);
	else return undefined;
	}
	

//-------------------------------------------------------------------------------------------------------------


if (typeof Element.prototype.getX != "undefined") $frameworkError += "Element.getX, ";

Element.prototype.getX = function()
	/*
	Functionality:		Returns the absolute horizontal position of an object in pixels, with 0 being the very left edge of the browser window.
						Returns null if offsetLeft is not suported by the browser
	Last modified:		09 Oct 2011
	*/
	{
	var obj = this;
	if (typeof obj.offsetLeft == "undefined") return null;
	// Walk up the parents and add all offset values
	var x = 0;
	do { x += obj.offsetLeft; } while (obj = obj.offsetParent);
	return x;		
	}
	
		
//-------------------------------------------------------------------------------------------------------------


if (typeof Element.prototype.getY != "undefined") $frameworkError += "Element.getY, ";

Element.prototype.getY = function()
	/*
	Functionality:		Returns the absolute vertical position of an object in pixels, as a numerical value without "px", with 0 being the very top edge of the browser window.
	Last modified:		09 Oct 2011
	*/
	{
	var obj = this;
	// Walk up the parents and add all offset values
	var y = 0;
	do { y += obj.offsetTop; } while (obj = obj.offsetParent);
	return y;		
	}


//-------------------------------------------------------------------------------------------------------------


if (typeof Element.prototype.getScroll != "undefined") $frameworkError += "Element.getScroll, ";

Element.prototype.getScroll = function()
	/*
	Functionality:		Returns the scroll value of an object. Can also return the correct scroll value if FleXcroll is being used on the page / object.
						Returns null if offsetTop is not suported by the browser
	Last modified:		14 Oct 2011
	*/
	{
	if (typeof this.fleXcroll == "object") return Math.abs(this.fleXdata.scrollPosition[1][0]);
	else return Math.abs(this.scrollTop);
	}


//-------------------------------------------------------------------------------------------------------------


if (typeof Element.prototype.setScroll != "undefined") $frameworkError += "Element.setScroll, ";

Element.prototype.setScroll = function(scrollY)
	/*
	Functionality:		Sets the scroll value of an object. Can also set the scroll value if FleXcroll is being used on the page / object.
	Last modified:		14 Oct 2011
	*/
	{
	if (typeof this.fleXcroll == "object") this.fleXcroll.setScrollPos(false,Math.min(scrollY,this.fleXdata.scrollPosition[1][1]));
	else this.scrollTop = scrollY;
	}


//-------------------------------------------------------------------------------------------------------------


if (typeof Element.prototype.setAttribute != "undefined") $frameworkError += "Element.setAttribute, ";

Element.prototype.setAttribute = function(atr,val)
	/*
	Functionality:		Creates an attribute, sets the value and attaches it to the element.
						Attention: Does not check whether the attribute exists already or not.
	Last modified:		26 Oct 2011
	*/
	{
	var theID = document.createAttribute(atr);
	theID.nodeValue = val;
	this.setAttributeNode(theID);
	}


//-------------------------------------------------------------------------------------------------------------


if (typeof Element.prototype.fade != "undefined") $frameworkError += "Element.fade, ";

Element.prototype.fade = function(timeDelay,timeStep,alphaStart,alphaEnd,alphaStep,evalCode)
	/*
	Functionality:		Fades an object (obj = string or DOM object) in or out.
						Returns false is any parameter is not a valid number. Otherwise returns return-value of setTimeout
						Automatically corrects alpha values that are smaller than 0 or larger than 100. Automatically corrects the leading sign (+/-) on alphaStep
	Last modified:		26 Oct 2011 (added evalCode)
	*/
	{
	// Are all attributes set?
	if (typeof timeDelay == "undefined") return false;
	if (typeof timeStep == "undefined") return false;
	if (typeof alphaStart == "undefined") return false;
	if (typeof alphaEnd == "undefined") return false;
	if (typeof alphaStep == "undefined") return false;
	if (typeof evalCode == "undefined") evalCode = "";
	
	// Make sure the value format is correct
	timeDelay = Math.round(parseFloat(timeDelay));
	timeStep = Math.round(parseFloat(timeStep));
	alphaStart = parseFloat(alphaStart);
	alphaEnd = parseFloat(alphaEnd);
	alphaStep = parseFloat(alphaStep);
	
	// Are all attributes numbers?
	if(isNaN(timeDelay) || isNaN(timeStep) || isNaN(alphaStart) || isNaN(alphaEnd) || isNaN(alphaStep)) return false;
	
	// Auto-correct alpha values
	if (alphaStart < 0) alphaStart = 0;
	if (alphaEnd < 0) alphaEnd = 0;
	if (alphaStep < -100) alphaStep = -100;
	if (alphaStart > 100) alphaStart = 100;
	if (alphaEnd > 100) alphaEnd = 100;
	if (alphaStep > 100) alphaStep = 100;
	alphaStep = Math.abs(alphaStep);
	if (alphaEnd < alphaStart) alphaStep = -alphaStep;
	
	// Attach the values to the object
	this.alphaNow = alphaStart;
	this.alphaEnd = alphaEnd;
	this.alphaStep = alphaStep;
	this.evalCode = evalCode;
	
	// Create an id if object has none
	this.id = this.id || String(new Date().getTime());
	
	// Start the animation
	setTimeout("object('" + this.id + "').fadeInterval = window.setInterval('object(\"" + this.id + "\").setAlpha(\"fade\")', " + timeStep + ");", timeDelay);
	}


//-------------------------------------------------------------------------------------------------------------


if (typeof Element.prototype.fadeIn != "undefined") $frameworkError += "Element.fadeIn, ";

Element.prototype.fadeIn = function(timeDelay,timeStep,alphaStep)
	/*
	Functionality:		Fades in an object with certain presets: Alpha 0 >> 100, duration 0.8 second.
	Last modified:		08 Oct 2011
	*/
	{
	var timeDelay = timeDelay || 0;
	var timeStep = timeStep || 40;
	var alphaStep = alphaStep || 5;
	var alphaStart = 0;
	var alphaEnd = 100;
	return this.fade(timeDelay,timeStep,alphaStart,alphaEnd,alphaStep);
	}


//-------------------------------------------------------------------------------------------------------------


if (typeof Element.prototype.fadeOut != "undefined") $frameworkError += "Element.fadeOut, ";

Element.prototype.fadeOut = function(timeDelay,timeStep,alphaStep)
	/*
	Functionality:		Fades in an object with certain presets: Alpha 0 >> 100, duration 0.8 second.
	Last modified:		06 Oct 2011
	*/
	{
	var timeDelay = timeDelay || 0;
	var timeStep = timeStep || 40;
	var alphaStep = alphaStep || 5;
	var alphaStart = 100;
	var alphaEnd = 0;
	return this.fade(timeDelay,timeStep,alphaStart,alphaEnd,alphaStep);
	}


//-------------------------------------------------------------------------------------------------------------


if (typeof Element.prototype.crossFade != "undefined") $frameworkError += "Element.crossFade, ";

Element.prototype.crossFade = function(newURL,timeDelay,timeStep,alphaStep)
	/*
	Functionality:		Cross-fades two images
	Last modified:		26 Oct 2011
	*/
	{
	// Check parameters first
	if (typeof newURL == "undefined" || newURL == "" || newURL.indexOf("{") === 0) return false;
	// Are images identical? This return avoid repeated fade actions when mouse continues to move.
	
	if (purged_url(this.src) == purged_url(newURL)) return false;
	var timeDelay = timeDelay || 0;
	var timeStep = timeStep || 40;
	var alphaStep = alphaStep || 5;
	var alphaStart = 0;
	var alphaEnd = 100;
	
	// Create an id if object has none
	this.id = this.id || String(new Date().getTime());
	
	// Create the overlay image on top of this one
	var overlayImage = create("img", this.id+"_OVER");
	if (overlayImage == null) return;
	var styleString = "position: absolute; ";
	styleString += "left: " + this.getX() + "px; ";
	styleString += "top: " + this.getY() + "px; ";
	styleString += "width: " + this.offsetWidth + "px; ";
	styleString += "height: " + this.offsetHeight + "px; ";
	styleString += "z-index: 999999; ";
	styleString += "opacity:0.0; filter:alpha(opacity=0); ";
	overlayImage.setAttribute("style", styleString);
	overlayImage.setAttribute("src", newURL);
	document.body.appendChild(overlayImage);
	// Create evalCode for end of fade action and the fade-in the new overlay image
	var evalCode = 'object("' + this.id + '").src = "' + newURL + '"; ';
	evalCode += 'document.body.removeChild(object("' + this.id + '_OVER")); ';
	//evalCode += 'setTimout(\'object("' + this.id + '").mouseout();\', 100); ';
	//evalCode += 'alert(object("' + this.id + '").onmouseout); ';
	return object(this.id+"_OVER").fade(timeDelay,timeStep,alphaStart,alphaEnd,alphaStep,evalCode);
	}
	

//-------------------------------------------------------------------------------------------------------------

	
if (typeof Element.prototype.setAlpha != "undefined") $frameworkError += "Element.setAlpha, ";

Element.prototype.setAlpha = function(alphaValue)
	/*
	Functionality:		Sets the alpha of an object.
						Automatically corrects alpha values that are smaller than 0 or larger than 100.
						Returns null is obj.style isn't supported.
						The argument alpha can also have a special value: If it is "fade" then the alpha value is being calculated from the object attributes set in fade()
	Last modified:		25 Oct 2011
	*/
	{
	// Set default value for alpha
	if(typeof alphaValue == "undefined" || alphaValue === "") alphaValue = "fade";
	
	// Set alpha as part of fade animations
	if (alphaValue == "fade")
		{
		// Abort if any value is missing
		if (typeof this.alphaNow == "undefined" || this.alphaNow === "" || typeof this.alphaEnd == "undefined" || this.alphaEnd === "" || typeof this.alphaStep == "undefined" || this.alphaStep === "")
			{
			if(typeof this.fadeInterval != "undefined") window.clearInterval(this.fadeInterval);
			this.fadeInterval = undefined;
			this.alphaNow = undefined;
			this.alphaEnd = undefined;
			this.alphaStep = undefined;
			return false;
			}
			
		// Increment and check for fade end
		alphaValue = this.alphaNow += this.alphaStep;
		if ((this.alphaStep >= 0 && alphaValue >= this.alphaEnd) || (this.alphaStep < 0 && alphaValue <= this.alphaEnd))
			{
			// Fade end reached. Unset everything and execute evalCode
			alphaValue = this.alphaEnd;
			window.clearInterval(this.fadeInterval);
			this.fadeInterval = undefined;
			this.alphaNow = undefined;
			this.alphaEnd = undefined;
			this.alphaStep = undefined;
			if (typeof this.evalCode != "undefined" && this.evalCode != "") eval(this.evalCode);
			}
		else this.alphaNow = alphaValue;
		}
	else // i.e. regular alphaValue
		{
		alphaValue = parseFloat(alphaValue);
		if(isNaN(alphaValue)) return false;
		if (alphaValue < 0) alphaValue = 0;
		if (alphaValue > 100) alphaValue = 100;
		}
	// Set alpha
	if (typeof this.style != "object") return null;
	this.style.filter = "alpha(opacity=" + alphaValue + ")";
	this.style.opacity = alphaValue / 100;
	return true;
	}


//========== DOM ELEMENT FUNCTIONS =======================================================================================================================================================================================


if (typeof get_by_class != "undefined") $frameworkError += "get_by_class, ";

function get_by_class (className,tag)
	/*
	Functionality:		Gets all elements that are members of the same class. Can be limited to certain tags.
						Returns null if className is undefined.
						25 Oct 2011
	Development:		Make this function a method of Element to limit the selection the children of certain nodes
	*/
	{
	if (typeof className == "undefined") return null
	if(typeof tag == "undefined" || tag === "") tag = "*";
	var allTags = get_by_tag(tag);
	var count = allTags.length;
	var allClass = new Array();
	var thisClass = "";
	for (i=0; i<count; i++)
		{
		thisClass = allTags[i].className;
		// We must consider multiple class names here
		if (thisClass == className ||
			thisClass.indexOf(className + " ") === 0 ||
			(thisClass.lastIndexOf(" " + className) == thisClass.length - className.length - 1 && thisClass.length > className.length) ||
			thisClass.indexOf(" " + className + " ") != -1
			) allClass.push(allTags[i]);
		}
	return allClass;
	}


//-------------------------------------------------------------------------------------------------------------


if (typeof set_dynamic_styles != "undefined") $frameworkError += "set_dynamic_styles, ";

function set_dynamic_styles(styleString)
	{
	/*
	Functionality:		Looks for a style tag with id="dynamicStyles", placed anywhere in the document (<style type="text/css" id="dynamicStyles"></style>)
						If not found this tag will be created as last style tag in the document header, so that styles inserted dynamically will override all static header styles
	Last modified:		26. Oct 2011					
	*/
	var ds = object("dynamicStyles");
	if (ds == null)
		{
		ds = document.createElement('style');
		ds.setAttribute("type", "text/css");
		ds.setAttribute("id", "dynamicStyles");
		var hd = document.getElementsByTagName("head")[0];
		hd.appendChild(ds);
		}
	if(ds.styleSheet) ds.styleSheet.cssText = styleString;
	else ds.textContent = styleString;
	}
	
	

//========== STRING FUNCTIONS =======================================================================================================================================================================================


if (typeof String.prototype.trim == "undefined")
	{
	String.prototype.trim = function(options)
		/*
		Functionality:		Removes any type of white spaces (including tab stops etc.) from the beginning and/or the end of a string.
							Allows optional parameters to specify the behavior: "left" =trim left only, "right" = trim right only.
							Attention: This method was added to Javascript 1.8.1 (for details check out https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/String/trim)
							Keep it in the framework for older browsers.
		Last modified:		12 Oct 2011
		To-do:				Instead of parameters add trimLeft() and trimRight() as in the new standard 
		*/
		{
		// Set default option if necessary
		options = options || "left+right";
		// Trim the string
		str = this;
		if (options.indexOf("left") != -1) str = str.replace(/^\s+/, "");
		if (options.indexOf("right") != -1) str = str.replace(/\s+$/, "");
		return str;
		}
	}
else $frameworkError += "String.trim, ";


//-------------------------------------------------------------------------------------------------------------


if (typeof String.prototype.isValidEmail != "undefined") $frameworkError += "String.isValidEmail, ";

String.prototype.isValidEmail = function()
	/*
	Functionality:		This function is a plausibility test to help the user, e.g. to avoid errors in form fields.
	Last modified:		08 Oct 2011
	Important notes:	An e-mail validated by this function may still not be a valid e-mail.
						Validation patterns found on the Internet are ALL WRONG! (Check out http://de.wikipedia.org/wiki/Umlautdomain).
	*/
	{
	var str = this;
	if (str.length < 4) return false; // a@bc (considers e-mail addresses directly under TLDs)
	if (str.indexOf("@") == -1) return false; // @ is required
	if (str.indexOf("@") == 0) return false; // @ cannot be at the beginning
	if (str.indexOf("@") > str.length-2) return false; // @ cannot be at the end
	if (str.indexOf("@") != str.lastIndexOf("@")) return false; // cannot have more than one @
	if (str.indexOf(".") != -1) // . is not required, but if . exists it cannot exist in certain places
		{
		if (str.indexOf(".") > str.length-3) return false; // assuming a domain has at least two characters
		if (str.charAt(str.indexOf("@")+1) == ".") return false; // . cannot be right after @
		}
	if (str.indexOf("\"") == 0 && str.lastIndexOf("\"") != str.lastIndexOf("@")-1) return false;
	if (str.indexOf("\"") == 0 && str.lastIndexOf("\"") == 0) return false;
	var domainOK = true;
	var forbidden = "!#%&'()*+,;:<=>?^`{|}~/\\_[]÷ "; // add some more here, but don't overdo it
	for (i = str.indexOf("@"); i<str.length; i++)
		{
		if (forbidden.indexOf(str.charAt(i)) != -1)
			{
			domainOK = false;
			break;
			}
		}
	return domainOK;
	}
		

//-------------------------------------------------------------------------------------------------------------


if (typeof String.prototype.cleanString != "undefined") $frameworkError += "String.cleanString, ";

String.prototype.cleanString = function()
	/*
	Functionality:		Removes HTML and unwanted characters from a string. Main purpose is to clean form field values 
	Last modified:		08 Oct 2011
	*/
	{
	str = this;
	// Remove HTML brackets (not the entire HTML)
	str = str.replace(/</g, "(");
	str = str.replace(/>/g, ")");
	// Remove certain characters to avoid problems in form fields and scripts
	str = str.replace(/"/g, "");
	str = str.replace(/'/g, ""); 
	str = str.replace(/\\/g, ""); 
	// Trim spaces
	return str.trim();
	}



//========== VARIOUS FUNCTIONS =======================================================================================================================================================================================


if (typeof hex != "undefined") $frameworkError += "hex, ";

function hex (dez)
	/*
	Functionality:		Converts a decimal value between 0 and 255 into a hexadecimal value.
						Auto-limits incoming values.
	Last modified:		09 Oct 2011
	*/
	{
	if (dez<0) return "00";
	else if (dez> 255) return "ff";
    else return "" + hexa[Math.floor(dez/16)] + hexa[dez%16];
	}


//-------------------------------------------------------------------------------------------------------------

	
function set_cookie (varname, value, days, domain, path)
	/*
	Functionality:		Writes a cookie varname=value;expires=time;
						Returns null if vars are not set and false if cookies are disabled
	Last modified:		25 Oct 2011
	*/
	{
	if (!navigator.cookieEnabled) return false;
	if (typeof varname == "undefined" || typeof value == "undefined") return null;
	var expires = "";
	var domainString = "";
	var pathString = "";
	
	// Set expiry time
	if (typeof days != "undefined" && days !== "")
		{
		var date = new Date();
		date.setTime(date.getTime() + (days*24*60*60*1000));
		expires = "; expires=" + date.toGMTString();
		}
	
	// Set domain
	if (typeof domain != "undefined" && domain !== "") domainString = "; domain=" + domain;

	// Set path
	if (typeof path == "undefined" || path == "") path = "/";
	pathString = "; path=" + path;

	// Set cookie
	document.cookie = varname + "=" + value + expires + domainString + pathString;
	}


//-------------------------------------------------------------------------------------------------------------

	
function get_cookie (varname)
	/*
	Functionality:		Gets the value of a cookie;
						Returns an empty string
	Last modified:		25 Oct 2011
	*/
	{
	var searchString = varname + "=";
	var cookieArray = document.cookie.split(';');
	var value = "";
	for(var i in cookieArray)
		{
		cookieArray[i] = cookieArray[i].trim("left");
		if (cookieArray[i].indexOf(searchString) == 0)
			{
			value = cookieArray[i].substring(searchString.length);
			break;
			}
		}
	return value;
	}


//-------------------------------------------------------------------------------------------------------------

	
function delete_cookie (varname)
	// Last modified: 25 Oct 2011
	{
	set_cookie(varname,"",-1);
	}


//-------------------------------------------------------------------------------------------------------------

	
function purged_url (url) {
	/*
	Functionality:		Takes absolute or relative URL an returns a cleaned absolute URL.
						"Cleaned" means that URL parts like abc/def/../ghi will be reduced to abc/ghi
	Last modified:		29 Oct 2011
	*/
    var urlParts = new Array();
	var loc = window.location;
	
	// Check the type of url
	if (url.indexOf("://") != -1)
		{
		// URL is absolute, so don't change it
		}
	else if (url.indexOf("/") === 0)
		{
		// Path must be added to domain directly
		url = loc.protocol + "//" + loc.hostname + url;
		}
	else 
		{
		// Path is relative to current folder	
		url = loc.href.substring(0, loc.href.lastIndexOf('/') + 1) + url;
		}
	// Convert backslashes
	url = url.replace(/\\/g, '/');
	
	// Cut off the protocol and domain
	url = url.replace(/:\/\//g, '***');
	var domain = url.substring(0,url.indexOf("/"));
	url = url.substring(url.indexOf("/")+1);
	
	// Put url in array and reduce it
	var urlArray = url.split('/');
    while (urlArray[0] == "..") urlArray.shift();
	var arrLen = urlArray.length;					
	for (var i=1; i<arrLen; i++)
		{
		if (urlArray[i] == "..")
			{
			urlArray[i-1] = "";
			urlArray[i] = "";
			}
		}
	// Re-create url from domain and array
	for (var i=0; i<arrLen; i++) if (urlArray[i] != "") urlArray[i] = "/" + urlArray[i];
	url = domain + urlArray.join("");
	url = url.replace("***", "://");
	
	return url;
	}


//========== GOGGLE ANALYTICS =======================================================================================================================================================================================

	
if (typeof ga_event != "undefined") $frameworkError += "ga_event, ";

function ga_event(cat,act,lab,val)
	/*
	Functionality:		Triggers a Google Analytics event. The only intention of this function is to reduce the amount of code required on the page. Thus there is no error checking.
						if cat begins with _ then 
						For information check out http://code.google.com/apis/analytics/docs/tracking/eventTrackerGuide.html
						cat = category (string), act = action (string), lab = label (string), val = value (integer)	
	Last modified:		05 Oct 2011
	*/
	{
	// List of abbreviations, expand as required
	abb = 
		{
		"_ab": "aborted",
		"_cl": "clicked",
		"_cm": "completed",
		"_dc": "document",
		"_dd": "document download",
		"_dl": "download",
		"_ef": "e-mail form",
		"_el": "e-mail link",
		"_em": "e-mail",
		"_rp": "repeated",
		"_vi": "video",
		"_vd": "video download",
		"_vv": "video view"
		}
	// Check category & action for abbreviations
	if (cat.indexOf("_") == 0) cat = abb[cat];
	if (act.indexOf("_") == 0) act = abb[act];
	// Call Google Analytics function
	_gaq.push(['_trackEvent',cat,act,lab,val]);
	}




//========== VIDEO =======================================================================================================================================================================================


	
if (typeof VIDEO != "undefined") $frameworkError += "VIDEO, ";

function VIDEO(handlerName,videoID,width,height,videoL,videoM,still,skin,autostart)
	{
	/*
	Functionality:		Defines a class that allows easy handling videos, that work on all regular browsers, iPhone, iPad, Android phones and most other smartphones.
						Requires the JW Player to be loaded (http://www.longtailvideo.com/players)
	Last modified:		23 Oct 2011
	*/
	
	//---------- Set vars und general methods ----------
	
	var autoplay = "";
	
	// Set attributes
	if (typeof handlerName != "undefined") this.handlerName = handlerName; else return false;
	if (typeof videoID != "undefined") this.videoID = videoID; else return false;
	if (typeof object(videoID) != "object") return null;
	this.id = "ttVideo_" + this.videoID;
	if (typeof width != "undefined") this.width = width; else this.width = object(id).offsetWidth;
	if (typeof height != "undefined") this.height = height; else this.height = object(id).offsetHeight;
	// Add here: Check whether width and height are really numerical values
	this.videoL = videoL || "";
	this.videoM = videoM || "";
	this.still = still || "";
	this.skin = skin || "";
	this.autostart = autostart || false;
	this.status = "new";
	
	this.fade = function(timeDelay,timeStep,alphaStart,alphaEnd,alphaStep) { object(this.videoID).fade(timeDelay,timeStep,alphaStart,alphaEnd,alphaStep) }
	this.fadeIn = function(timeDelay,timeStep,alphaStep) { object(this.videoID).fadeIn(timeDelay,timeStep,alphaStep) }
	this.fadeOut = function(timeDelay,timeStep,alphaStep) { object(this.videoID).fadeOut(timeDelay,timeStep,alphaStep) }
	this.setAlpha = function(alpha) { object(this.videoID).setAlpha(alpha) }

	// Add the handler name to a global array
	if (typeof $videoHandler == "undefined") $videoHandler = new Array();
	$videoHandler [this.videoID] = this.handlerName;
	
	//---------- Video helper methods ----------
	
	/*this.autostartJW = function() // ATTENTION: This function is currently not used anymore, because autoplay + resetSmartphone seems to do the job. Nevertheless keep!
		{
		if (this.status == "loading") this.status = "normal";
		if(this.autostart)
			{
			setTimeout('jwplayer("' + this.videoID + '").play(true);',1000);
			setTimeout('jwplayer("' + this.videoID + '").play(true);',2000);
			setTimeout('jwplayer("' + this.videoID + '").play(true);',3000);
			}
		}*/
	
	this.resetIphone = function()
		{
		object(this.videoID).innerHTML = object(this.videoID).innerHTML;
		object(this.videoID + "_html5Player").addEventListener('ended', function() { window[$videoHandler[this.id.substring(0,this.id.length-12)]].resetIphone(); } );
		}
	
	this.resetSmartphone = function()
		{
		var thisVideo = this.videoM;
		if ($user.screenSize == "L") thisVideo = this.videoL;
		jwplayer(this.videoID).setup({
			file: thisVideo,
			image: this.still,
			width: this.width,
			height: this.height,
			skin: this.skin,
			controlbar: "none",
			modes: [
				{ type: "html5" },
				{ type: "download" }
       		]
		});
		jwplayer(this.videoID).onIdle(function() { window[$videoHandler[this.id]].resetSmartphone(); } );
		}
		
	//---------- Video main methods ----------
	
	/*
		play(videoL,videoM,still)
		play()
		
		If at least one argument with a video URL is found the player will begin playing the new video.			
		If there are no arguments the player shall continue to play the current video. Attention: This is not implemented yet!!! Calling play() will only return false.
		In the future maybe add a position value, so that a video can begin playing at a specific position.
	*/
	
	this.play = function (newVideoL,newVideoM,newStill)
		{
		// Check the arguments
		if (typeof newVideoL == "undefined") return false; // in the future simply play the video
		this.videoL = newVideoL;
		this.videoM = newVideoM || newVideoL;
		this.still = newStill || "";
		
		// Check whether JW Player is in download mode
		if (object(this.videoID + "_video_wrapper") === null &&
			object(this.videoID + "_wrapper") === null &&
			object(this.videoID + "_html5Player") === null) this.status = "download";

		// Start video depending on browser / platform
		if (this.status == "ipad")
			{
			var thisPlayer = object(this.videoID + "_html5Player");
			thisPlayer.pause();
			thisPlayer.poster = this.still;
			thisPlayer.src = this.videoL;
			thisPlayer.load();
			thisPlayer.play();
			}
		else if (this.status == "iphone")
			{
			var thisPlayer = object(this.videoID + "_html5Player");
			thisPlayer.pause();
			thisPlayer.poster = this.still;
			thisPlayer.src = this.videoM;
			thisPlayer.load();
			thisPlayer.play();
			thisPlayer.addEventListener('ended', function() { window[$videoHandler[this.id.substring(0,this.id.length-12)]].resetIphone(); });
			}
		else if (this.status == "smartphone")
			{
			var thisVideo = this.videoM;
			if(this.screenSize == "L") thisVideo = this.videoL;
			jwplayer(this.videoID).setup({
				file: thisVideo,
				image: this.still,
				autoplay: true,
				width: this.width,
				height: this.height,
				skin: this.skin,
				controlbar: "none",
				modes: [
					{ type: "html5" },
					{ type: "download" }
	       		]});
			jwplayer(this.videoID).onIdle(function() { window[$videoHandler[this.id]].resetSmartphone(); } );
			//jwplayer(this.videoID).onReady(function() { window[$videoHandler[this.id]].autostartJW(); } );
			}
		else if (this.status == "download")
			{
			if(this.screenSize == "L") top.location.href = this.videoL;
			else top.location.href = this.videoM;
			}
		//else top.location.href = "video.php?#-Video-" + thisVideo;
		else // i.e. "normal" browsers
			{
			this.status = "loading";
			jwplayer(this.videoID).setup({
				file: this.videoL,
				image: "",
				autoplay: true,
				width: this.width,
				height: this.height,
				skin: this.skin,
				modes: [
					{ type: "flash", src: "jw/jwplayer.swf" },
	            	{ type: "html5" },
					{ type: "download" }
	       		] });
			}
		}


	//---------- Start video player depending of browser / platform ----------
	
	if ($user.ipad)
		{
		this.status = "ipad";
		if (this.autostart) autoplay = ' autoplay="autoplay"';
		object(this.videoID).innerHTML = '<video id="' + this.videoID + '_html5Player" src="' + this.videoL + '" width="' + this.width + '" height="' + this.height + '" controls="controls" preload="metadata" poster="' + this.still + '"' + autoplay + '>';
		//if (autostart) setTimeout("start_new_video(firstVideo)",1000);
		}
	else if ($user.iphone)
		{
		this.status = "iphone";
		if (this.autostart) autoplay = ' autoplay="autoplay"';
		object(this.videoID).innerHTML = '<video id="' + this.videoID + '_html5Player" src="' + this.videoM + '" width="' + this.width + '" height="' + this.height + '" controls="controls" preload="metadata" poster="' + this.still + '"' + autoplay + '>';
		object(this.videoID).addEventListener('ended', function() { window[$videoHandler[this.id]].resetIphone(); } );
		//if (autostartVideo) setTimeout("start_new_video(firstVideo)",1000);
		}
	else if ($user.smartphone)
		{
		this.status = "smartphone";
		var thisVideo = this.videoM;
		if ($user.screenSize == "L") thisVideo = this.videoL;
		jwplayer(this.videoID).setup({
			file: thisVideo,
			image: this.still,
			autoplay: true,
			width: this.width,
			height: this.height,
			skin: this.skin,
			controlbar: "none",
			modes: [
				{ type: "html5" },
				{ type: "download" }
       		]
		});
		jwplayer(this.videoID).onIdle(function() { window[$videoHandler[this.id]].resetSmartphone(); } );
		//if (this.autostart) jwplayer(this.videoID).onReady(function() { window[$videoHandler[this.id]].autostartJW(); } );
		}
	else // i.e. "normal" browsers
		{
		this.status = "loading";
		var thisStill = this.still;
		if (this.autostart) thisStill = "";
		this.screenSize = "L";
		jwplayer(this.videoID).setup({
			file: videoL,
			image: thisStill,
			autoplay: this.autostart,
			width: this.width,
			height: this.height,
			skin: this.skin,
			stretching: "exactfit",
			modes: [
				{ type: "flash", src: "jw/jwplayer.swf" },
	            { type: "html5" },
				{ type: "download" }
       		]
		});
		//jwplayer(this.videoID).onReady(function() { window[$videoHandler[this.id]].autostartJW(); } );
		}

	}


//========== SHORTCUTS =======================================================================================================================================================================================


/*if (typeof object != "undefined") $frameworkError += "object, ";
function object(id) {return document.getElementById(id) }*/

if (typeof get_by_tag != "undefined") $frameworkError += "get_by_tag, ";
function get_by_tag(tagName) { return document.getElementsByTagName(tagName) }

	
//========== STARTING UP - PART 2 =======================================================================================================================================================================================

// Uncomment this line to detect collisions with other Javascripts you are using. See detailed descript above (INTEGRATION)
// if ($frameworkError == "") alert("No problems detected."); else alert ($frameworkError);

