/**
 * global.js
 * 
 * $Rev: 4570 $
 * $Author: andersy $
 * $Date: 2008-10-21 16:46:49 +0200 (Tue, 21 Oct 2008) $
 * 
 * 0 INIT
 * 1 COMMONS
 *    1.1 Functions
 *    1.2 Objects
 * 2 SERVICES, sorted by service names
 * 3 DEPRECATED / OBSOLETE
 */
var isIE = /*@cc_on!@*/false;
if (isIE) {
	Event.observe(window,'load',function(){init();});
}
else {
	Event.domReady.add(function(){
		init();
	});
}

/**
 * Called on page load and ajax calls, put invoke methods here.
 * 
 * @param {Element} scope set scope for invoke methods. Default value is <body>.
 */
function init(scope) {
	// init site settings
	Settings.init( (typeof scope == 'undefined') ? $$('body')[0] : scope );
	
	// preparations
	prepareNewsLists();
	prepareImageCaptions();
	prepareArticleToolbar();
	//prepareEventCalendar();
	//prepareMyPhotos();
	prepareImageGallery();
	prepareFormValidation();
	//prepareMyPageUtil();
	prepareCharacterCounter();
	prepareExternalContent();
	//prepareTogglers();
	//prepareForumMyPage();
	//prepareLeftNav();
	prepareDropDown();
	//prepareBlog();
	preparePoll();
	//prepareChat();
	prepareForms();
	prepareUserForm();
	//CrowdPictures.init();
	//TVGuide.init();
	
	// preparations set, enable enhancements
	enableEnhancements();

	// init jsdependent services
	// initTopUserToolbar();
	initTicker();
	initLinkExtensions();
	initPrint();
	
	// this is always last!
	ModalWindow.init();
}

 
/***************************** 1. COMMONS **********************************************/ 
 
/* =========================== 1.1 Functions =============================================*/ 

/* *** Javascript enhancements *** */

/**
 * Init method. Makes JS-dependent blocks visible (they are hidden by CSS in case Javascript is not available).
 * Varning! this does not apply on JS-generated markup like Modal Windows.
 * 
 */
function enableEnhancements() {
	Settings.scope.select(".JSDependent").each(function(item) {
		item.removeClassName("JSDependent");
	});
	Settings.scope.select(".hiddenByJS").each(function(item) {
		item.setStyle({position:'absolute',visibility:'hidden'});
	});
}

/**
 * Switch CSS on partly JSDependent blocks (these have fallback styles by default).
 * This function must be called manually, typically from init methods.
 * 
 * @param {Array} elements	the result array from a $$() call, ex. $$(".imageCaption div")
 * @author andersy
 * @return void
 */
function enableJSStyles( elements ) {
	elements.each(function(item) {
		item.wrap('div', {'class':'JSEnabled'});
	});
}

/* *** Form and Link types handling *** */

/**
 * Force external links to opens in new window. This is applied to all links with rel="external".
 * 
 * @param {HTMLElement} e	the link element
 */
function openExternalLink(e) {
	var el = Event.element(e);
	
	// If this isn't a link element, just exit quietly
	if (el.tagName != 'A') {
		return false;
	}
	
	// open the window		
	window.open(el.href, '_blank');
	Event.stop(e);
	return false;
}

/* *** URL / Querystrings functions *** */

/**
 * Adds a querystring parameter to a String URL.
 * 
 * @param url
 * 		The String URL
 * 
 * @param paramName
 * 		The name of the parameter
 * 
 * @param paramValue
 * 		The parameter value
 * 
 */
function addQueryStringParam(url, paramName, paramValue) {
	if(url == null || url == "")
		return null;

	var paramSuffix = "?";
	if(url.indexOf("?") > 0)
		paramSuffix = "&";

	if(url.indexOf(paramName + "=" + paramValue) > 0) {
		return url;
	}
	
	var newurl = (url.indexOf("#") < 0) ? (url + paramSuffix + paramName + "=" + paramValue) : (url.replace("#", (paramSuffix + paramName + "=" + paramValue + "#")) );
	return newurl;
}
	
/**
 * Fetches parameter from the url, empty string if it wasn't found.
 * 
 * @param {String} strParamName
 */
function getUrlParam(strParamName){
	var strReturn = "";
	var strHref = window.location.href;
	if ( strHref.indexOf("?") > -1 ){
		var strQueryString = strHref.substr(strHref.indexOf("?")).toLowerCase();
		var aQueryString = strQueryString.split("&");
		for ( var iParam = 0; iParam < aQueryString.length; iParam++ ){
			if (aQueryString[iParam].indexOf(strParamName.toLowerCase() + "=") > -1 ){
				var aParam = aQueryString[iParam].split("=");
				strReturn = aParam[1];
				break;
			}
		}
	}
	return strReturn;
}

/**
 * Set properties of a iFrame by javascript.
 * PLEASE DO NOT USE THIS! USE HTML ATTRIBUTES INSTEAD!
 * 
 * @param {Element} iframe
 * @param {src} src
 * @param {int} width
 * @param {int} height
 * @param {boolean} scrolling
 */
function setIframeProperties(iframe, src, width, height, scrolling) {
	if(iframe) {
		iframe.setAttribute("src", src);
		iframe.setAttribute("width", width);
		iframe.setAttribute("height", height);
		iframe.setAttribute("frameBorder", "0");
		iframe.setAttribute("scrolling", scrolling);
	}
}

/*
 * This is the orginial function from Stuart Langridge at http://www.kryogenix.org/
 */
 
/*
* This is the update function from Jeff Minard - http://www.jrm.cc/
*/
function superTextile(s) {
    var r = s;
    // quick tags first
    qtags = [['\\*', 'strong'],
             ['\\?\\?', 'cite'],
             ['\\+', 'ins'],  //fixed
             ['~', 'sub'],   
             ['\\^', 'sup'], // me
             ['@', 'code']];
    for (var i=0;i<qtags.length;i++) {
        ttag = qtags[i][0]; htag = qtags[i][1];
        re = new RegExp(ttag+'\\b(.+?)\\b'+ttag,'g');
        r = r.replace(re,'<'+htag+'>'+'$1'+'</'+htag+'>');
    }
    
	// underscores count as part of a word, so do them separately
    re = new RegExp('\\b_(.+?)_\\b','g');
    r = r.replace(re,'<em>$1</em>');
	
	//jeff: so do dashes
    re = new RegExp('[\s\n]-(.+?)-[\s\n]','g');
    r = r.replace(re,'<del>$1</del>');

    // links
    re = new RegExp('"\\b(.+?)\\(\\b(.+?)\\b\\)":([^\\s]+)','g');
    r = r.replace(re,'<a href="$3" title="$2">$1</a>');
    re = new RegExp('"\\b(.+?)\\b":([^\\s]+)','g');
    r = r.replace(re,'<a href="$2">$1</a>');

    // images
	// SKIT
    re = new RegExp('!\\b(.+?)\\(\\b(.+?)\\b\\)!','g');
    r = r.replace(re,'<img src="$1" alt="$2">');
    re = new RegExp('!\\b(.+?)\\b!','g');
    r = r.replace(re,'<img src="$1">');
    
    // block level formatting
	
		// Jeff's hack to show single line breaks as they should.
		// insert breaks - but you get some....stupid ones
	    re = new RegExp('(.*)\n([^#\*\n].*)','g');
	    r = r.replace(re,'$1<br />$2');
		// remove the stupid breaks.
	    re = new RegExp('\n<br />','g');
	    r = r.replace(re,'\n');
	
    lines = r.split('\n');
    nr = '';
    for (var i=0;i<lines.length;i++) {
        line = lines[i].replace(/\s*$/,'');
        changed = 0;
        if (line.search(/^\s*bq\.\s+/) != -1) { 
			line = line.replace(/^\s*bq\.\s+/,'\t<blockquote>')+'</blockquote>'; 
			changed = 1; 
		}
		
		// jeff adds h#.
        if (line.search(/^\s*h[1|2|3|4|5|6]\.\s+/) != -1) { 
	    	re = new RegExp('h([1|2|3|4|5|6])\.(.+)','g');
	    	line = line.replace(re,'<h$1>$2</h$1>');
			changed = 1; 
		}
		
		if (line.search(/^\s*\*\s+/) != -1) { line = line.replace(/^\s*\*\s+/,'\t<liu>') + '</liu>'; changed = 1; } // * for bullet list; make up an liu tag to be fixed later
        if (line.search(/^\s*#\s+/) != -1) { line = line.replace(/^\s*#\s+/,'\t<lio>') + '</lio>'; changed = 1; } // # for numeric list; make up an lio tag to be fixed later
        if (!changed && (line.replace(/\s/g,'').length > 0)) line = '<p>'+line+'</p>';
        lines[i] = line + '\n';
    }
	
    // Second pass to do lists
    inlist = 0; 
	listtype = '';
    for (var i=0;i<lines.length;i++) {
        line = lines[i];
        if (inlist && listtype == 'ul' && !line.match(/^\t<liu/)) { line = '</ul>\n' + line; inlist = 0; }
        if (inlist && listtype == 'ol' && !line.match(/^\t<lio/)) { line = '</ol>\n' + line; inlist = 0; }
        if (!inlist && line.match(/^\t<liu/)) { line = '<ul>' + line; inlist = 1; listtype = 'ul'; }
        if (!inlist && line.match(/^\t<lio/)) { line = '<ol>' + line; inlist = 1; listtype = 'ol'; }
        lines[i] = line;
    }

    r = lines.join('\n');
	// jeff added : will correctly replace <li(o|u)> AND </li(o|u)>
    r = r.replace(/li[o|u]>/g,'li>');

    return r;
}

/**
 * Checks for browser-enabled cookies and sets an arbitrary form field to true/false.
 *
 * @param id
 * 			Id of form field to populate
 */
function setFormCookie (id)
{
	var f = $(id);
	
	if (f)
	{
		f.value = (Cookie.accept()) ? "true" : "false";
	}
}

/* =========================== / 1.1 Functions ============================================ */ 

/* =========================== 1.2 Objects ================================================ */ 

var CacheUtil = {
	
	/**
	 * Add unique number in URI to prevent cache.
	 */
	noCache : function(uri) {
		return uri.concat(/\?/.test(uri)?"&":"?","noCache=",new Date().getTime(),".",Math.random()*1234567);
	}
}

/* *** CharacterCounter *** */

/**
 *	@author Pelle Andersson, Promedia, Nerikes Allehanda
 */
 
var CharacterCounter = {
	maxChars: 0,
	initsuccess: false,
	exists : function () {
		return Settings.scope.select("textarea").length;
	},
	/*
		Init #maxchar and .maxchar textareas

		NOTE: well known bug in IE if you use the
		word description or body as id of an element (it will return the meta tag???!!!).
		This is an IE fix
	*/
	init: function() {
		
		var elementCounter = Settings.scope.select("#maxchar");
		
		this.initElements(elementCounter);
		
		var elementCounter = Settings.scope.select(".maxchar");
		
		this.initElements(elementCounter);
	},
	/**
	 * Init textareas with charcount, i.e. #maxchar (for backward compability) and .maxchar
	 * 
	 * @param {Array} elements 
	 * @author na_fredrik
	 * @return void
	 */
	initElements: function (elementCounterNodes)
	{
		if(elementCounterNodes != null && elementCounterNodes.length > 0){
			
			for (var j=0; j<elementCounterNodes.length; j++)
			{
				var elementCounter = elementCounterNodes[j];
				var tree = elementCounter.up().ancestors();
				var textArea = false;
				
				for(var i=0; i<tree.length; i++) {
					if(tree[i].nodeName == 'FIELDSET' || tree[i].nodeName == 'DIV') {
						textArea = tree[i].select('textarea').last();
						break;
					}
				}

				if(textArea == false) return;
				
				CharacterCounter.initMaxCharValues(elementCounter);
				if(elementCounter.initsuccess == true){
					textArea.elementCounter = elementCounter;
					textArea.maxChars = elementCounter.maxChars;
					textArea.onkeyup = function () { CharacterCounter.countChars(this);}
					textArea.onkeydown = function () { CharacterCounter.countChars(this);}
					textArea.onfocus = function () { CharacterCounter.countChars(this);}
				} 
				else
					elementCounter.addClassName("JSDependent");
			}
		}
	},
	/**
		Method which count down number of charachter left.
			@param elementToCount
				The textarea element to count, gets called on keyup-, keydown- and focus-events. Each teaxtarea element contains a self reference to a corresponding counter element
	
	*/
	countChars: function(elementToCount){
	
		var elementCounter = elementToCount.elementCounter;
		
		if(elementToCount.value.length > elementCounter.maxChars){
			elementToCount.value = elementToCount.value.substring(0, elementCounter.maxChars);
		}
		else{
			elementCounter.value = elementCounter.maxChars - elementToCount.value.length;
		}
	},
	/**
	Attach a maxchars value to an counter element.
	
	@param elementToCount
	*/
	initMaxCharValues: function(obj) {
		if(obj.value != "" && parseInt(obj.value)){
			obj.maxChars = obj.value;
			obj.initsuccess = true;
		}
	}
}



/**
 * Init the character counter object.
 */
function prepareCharacterCounter(){
	if (CharacterCounter.exists()) {
		CharacterCounter.init();
	}
}

/**
 * Prototype extension to store and get cookies.
 */
var Cookie = {
/**
 * Set a cookie.
 * 
 * @param {Object} name	the name of the cookie
 * @param {Object} value	value of the cookie
 * @param {Object} daysToExpire	When the cookie shall expire.
 */
  setC: function(name, value, daysToExpire) 
  {
    var expire = '';
    if (daysToExpire != undefined) {
      var d = new Date();
      d.setTime(d.getTime() + (86400000 * parseFloat(daysToExpire)));
      expire = '; expires=' + d.toGMTString();
    }
    return (document.cookie = escape(name) + '=' + escape(value || '') + expire);
  }, 
 /**
  * Get stored cookie.
  * 
  * @param {Object} name
  */
  getC: function(name) 
  {
    var cookie = document.cookie.match(new RegExp('(^|;)\\s*' + escape(name) + '=([^;\\s]*)'));
    return (cookie ? unescape(cookie[2]) : null);
  },
  /**
   * Delete cookie.
   * 
   * @param {Object} name
   */
  erase: function(name) 
  {
    var cookie = Cookie.getC(name) || true;
    Cookie.setC(name, '', -1);
    return cookie;
  },
  /**
   * Test if the browser accept cookies.
   */
  accept: function() {
    if (typeof navigator.cookieEnabled == 'boolean') 
	{
      return navigator.cookieEnabled;
    }
    Cookie.setC('_test', '1');
    return (Cookie.erase('_test') === '1');
  }
}

function prepareDropDown() {
	if(DropDown.exists()) {
		DropDown.init();
	}
}

var DropDown = {
	selectors : {
		soc : 'select.submitOnChange'
	},
	instance : {
		soc : null
	},
	counts : {
		soc : null
	},
	exists : function(scope) {
		if(typeof scope == 'undefined') scope = Settings.scope.select('body')[0];
		this.instance.soc = Settings.scope.select(this.selectors.soc);
		this.counts.soc = this.instance.soc.length;
		return this.counts.soc > 0;
	},
	init : function() {
		if(this.counts.soc > 0) {
			for (var i = 0; i < this.counts.soc; i++) {
				var soc = this.instance.soc[i];
				soc.up('form').select("input[type=submit]").each(function(item){item.remove()});
				this.registerSubmitOnChange(this.instance.soc[i]);
			}
		}
	},
	registerSubmitOnChange : function(elm){
		var c = this;
		Event.observe( elm, 'change', function(item){
			elm.up('form').submit();
		});
	}
}

/* *** Form enhancement *** */

function prepareForms() {
	Form.initModalForms();
	Form.observeButtons();
}

var Form = {
	cn : {
		firedBtn : "input.buttonPressed",
		clsFiredBtn : "buttonPressed",
		clsModalForm : "postAsModal"
	},
	/**
	 * init method. Prepare forms with more than one submit button with a hidden field. 
	 * The hidden field is updated with the value of the clicked button.
	 */
	observeButtons : function () {
		Settings.scope.select('form').each(function(f){
			var sbtlen = 0;
			for(i=0,max=f.elements.length;i<max;i++){
				if(f.elements[i].type == 'submit') sbtlen++;
			}
			
			if(sbtlen > 1){
				var disp = new Element('input', {
					'class': Form.cn.clsFiredBtn,
					type: 'hidden'
				});
				f.insert( {
					bottom:disp 
				});
				Event.observe(f,'click',function(e){
					var elm = e.element();
					if (elm.nodeName == 'INPUT' && elm.type == 'submit') {
						f.select(Form.cn.firedBtn)[0].value = elm.value;
					}
				});
			}
		});
	},
	
	initModalForms : function () {
		$$("div#mainPadding form").each(function(f){
			if (f.hasClassName(Form.cn.clsModalForm)) {
				openAsModal(f);
			}
		});	
	},
	
	getCaretPos : function  (ctrl) {

		var CaretPos = 0;
		// IE Support
		if (document.selection) {
	
			ctrl.focus ();
			var Sel = document.selection.createRange ();
	
			Sel.moveStart ('character', -ctrl.value.length);
	
			CaretPos = Sel.text.length;
		}
		// Firefox support
		else if (ctrl.selectionStart || ctrl.selectionStart == '0')
			CaretPos = ctrl.selectionStart;
	
		return (CaretPos);
	
	},
	setCaretPos : function(ctrl, pos){
	
		if(ctrl.setSelectionRange)
		{
			ctrl.focus();
			ctrl.setSelectionRange(pos,pos);
		}
		else if (ctrl.createTextRange) {
			var range = ctrl.createTextRange();
			range.collapse(true);
			range.moveEnd('character', pos);
			range.moveStart('character', pos);
			range.select();
		}
	},
	updateTextArea : function(ta,insrt) {
		var crt = Form.getCaretPos(ta);
		if(!crt) (ta.value.length-1);
		var before = ta.value.substr(0,crt);
		var after = ta.value.substr(crt);
		ta.value = before + insrt + after;
		Form.setCaretPos(ta, (crt+insrt.length) );
	},
	getPasswordStrength : function (passwd) {
		var requiredLength = 6;
		var percentage = 0;
		var increase = 20;
		
		var hasLowercase = false;
		var hasUppercase = false;
		var hasInteger = false;
		var hasSpecialchar = false;
		
		// At least one lower case letter
		if (passwd.match(/[a-z]/)) {
			percentage += increase;
			hasLowercase = true;
		}
		
		// At least one upper case letter
		if (passwd.match(/[A-Z]/)) {
			percentage += increase;
			hasUppercase = true;
		}
		
		// At least one number
		if (passwd.match(/\d+/)) {
			percentage += increase;
			 hasInteger = true;
		}
	
		// At least one special character
		if (passwd.match(/[$#%@&amp;*(+){}+!,^?_~]/)) {
			percentage += increase;
			hasSpecialchar = true;
		}
		
		// At least 6 characters
		if(passwd.length >= requiredLength)
			percentage += increase;
	
		return percentage;
	},
	iframe : {
		contid : 'userFormIframe',
		html : function() {
			return "<iframe style='visibility:hidden;width:0;height:0;border:0;z-index:-1' name='" +this.id+"' id='"+this.id+"'></iframe>"
		},
		onload : function() {
			var wrp = parent.frames[Form.iframe.id].document.getElementsByTagName('body')[0];
			var html = wrp.innerHTML;
			options = {
				beforeLaunch : null,
				params : {
					href: Form.iframe.id,
					type: null,
					reloadLinks : true,
					reloadOnClose : false,
					closeButton : true,
					scrollable : false,
					wrapperClass : null
				},
				onload : null,
				onsubmit : null,
				onunload : null,
				evalResponse : null
			}
			
			if (typeof options.beforeLaunch == "function") options.beforeLaunch();
			ModalWindow.onload = options.onload;
			ModalWindow.onunload = options.onunload;
			ModalWindow.evalResponse = options.evalResponse;		
			parent.frames[Form.iframe.id].location.href = '';
			ModalWindow.inner.innerHTML = '';
			ModalWindow.importFromIframe(options,html);
		},
		init : function(formElm,onloadFunc) {
			var ifrm = new Element('div',{'id':this.contid});
			this.id = this.contid+Math.random();
			ifrm.update(this.html());
			formElm.target = this.id;
			formElm.insert(ifrm);
			var c = this;
			Event.observe(formElm,'submit',function(e){
				if (FormValidation.checkForm(formElm) == true) {
					if (ModalWindow.overlay.getStyle('display') != 'none') {
						ModalWindow.initLoader();
						ModalWindow.resetWrapper();
						Event.observe($(Form.iframe.id), 'load', (typeof onloadFunc == "undefined") ? Form.iframe.onload : onloadFunc);
					}else{
						var wrp = parent.frames[Form.iframe.id].document.getElementsByTagName('body')[0];
						var html = wrp.innerHTML;
						return html;
					}
				}
				else {
					e.preventDefault();
				}
			});
		},
		exists : function() {
			return $('modalWindowWrapper').select("#userFormIframe").length > 0;
		}
	}
}

/************************************************************************************************
 *  Form validation object.
 *	Performs dynamic validation of any form.
 *	For requirements see http://mktmedia...	
 *	@author Pelle Andersson, Promedia, Nerikes Allehanda	
 *	
 */

var FormValidation = {

	
	/*
		Different limitations used by the FormValidation object.
	*/

	MAX_CHARS : 500,
	MAX_FILE_SIZE : 4000000,
	MAX_COUNT : 100,
	MIN_PASSWORDLENGTH : 3,
	DEFAULT_SELECT_VALUE : "-- Välj --",
	
	/*
		Current validation types used by the FormValidation object.
		Add more types when required
	*/
	
	currentForm : null,

	R : "requiredfield",
	M : "maxcharsfield",
	U : "urlfield",
	E : "emailfield",
	IS : "imagesizefield",
	CT : "contenttypefield",
	MC : "maxcountfield",
	ISE : "isequalfield",
	N : "numberfield",
	D : "datefield",
	P : "pnumberfield",
	O : "orgnumberfield",
	
	/*
		General error messages used by the FormValidation object.
		NOTE:Do not remove the word field since this is dynamically replaced by the header for the specific form element
	*/

	 ERROR_HEADER : "Fel intr\u00E4ffade i inmatningsf\u00E4lten:",
	 ERROR_EMPTY : "Var v\u00E4nlig fyll i f\u00E4ltet \"field\"",
	 ERROR_MAXCHARS : "F\u00E4ltet field \u00F6verstiger maximalt antal till\u00E5tna tecken!",
	 ERROR_URL : "F\u00E4ltet inneh\u00E5ller en eller flera ogiltiga l\u00E4nkar! (ex p\u00E5 giltig l\u00E4nk http://www.doman.xx)",
	 ERROR_EMAIL : "Var v\u00E4nlig ange en giltig e-postadress! (ex. namn.efternamn@foretag.xx)",
	 ERROR_CONTENT_TYPE : "Var v\u00E4nlig ange ett giltigt filformat, endast jpg \u00E4r till\u00E5tet!",
	 ERROR_FILE_SIZE : "Filen \u00E4r f\u00F6 stor, maxstorlek f\u00F6r bild \u00E4r 4 MB!",
	 ERROR_MAXCOUNT : "Maxantal f\u00F6r field \u00E4r " + this.MAX_COUNT,
	 ERROR_NOTEQUAL : "F\u00E4lten field och efield m\u00E5ste vara exakt lika!",
	 ERROR_NOTCHECKED : "Var god kryssa i field!",
	 ERROR_NOTNUMBER : "Var v\u00E4nlig ange ett numeriskt vu00E4rde!",
	 ERROR_DATE : "Var v\u00E4nlig ange ett giltigt datum i formatet \u00C5\u00C5\u00C5\u00C5-MM-DD!",
	 ERROR_PNUMBER : "Var v\u00E4nlig ange ett giltigt personnummer i formatet \u00C5\u00C5MMDD-XXXX!",
	 ERROR_ORGNUMBER : "Var v\u00E4nlig ange ett giltigt organisationsnummer!",
	 ERROR_PASSWORD : "L\u00F6senordet m\u00E5ste inneh\u00E5lla minst 6 tecken!",
	
	
	errorDiv : "div#error",
	
	errorDivIfrm: "div#errorIfrm",
	
	errorSummary: "Fel intr\u00E4ffade i inmatningsf\u00E4lten:\n",

	/**
		Base method for the form validation object. Iterates all the
		elements in the form and performs validation (if the requirements are 
		fullfilled). 
	*/
	
	checkForm : function(f){
		
		this.currentForm = f;
		
		var validators = new Array();
		var errorMessage = "";
		var globalErrorCount = 0;
		var origClassName = "";
		var fragmentErrorMessage = "Fel intr\u00E4ffade i inmatningsf\u00E4lten:\n";
		var notShown = 0;
		
		//Remove div shown in fallback mode e.g server validation if the
		//user has turned off javascript and then turn it back on again.
		this.hideAllErrorMessages("",true);
		
		//Iterate all elements in the form to validate (f parameter)
		for(var i = 0; i < f.elements.length; i++){
			var validate = f.elements[i].type == "text" || f.elements[i].type == "textarea" || f.elements[i].type == "select-multiple" || f.elements[i].type == "file" || f.elements[i].type == "checkbox" || f.elements[i].type == "radio" || f.elements[i].type == "password" || f.elements[i].type == "select-one";
				
			var type = f.elements[i].type;
			if(validate){
				var node = f.elements[i];
				var nodeName = f.elements[i].id;
				var labelText = "";
				var fieldErrorCount = 0;
				
				//Get validators and field name for the current form element
				var validatorString = this.getValidators(nodeName);
				var header = this.getHeader(nodeName);
				
				
				if(validatorString != ""){
					//Select-multiple validation
					if(type == "select-multiple"){
						var message = this.validateDropDownList(node);
						if(message != ""){
							errorMessage += message;
							globalErrorCount++;	
							fieldErrorCount++;
							
							this.errorSummary += errorMessage + "\n";
						}
					}
					//Select-one validation
					else if(type == "select-one"){
						var message = "";
						if(validatorString.indexOf(this.D) > -1) {
							var yyyy = node.value;
							var mm = node.next().selectedIndex;
							if(mm<10 && (mm+"").length==1) mm = "0"+mm;
							var dd = node.next(1).value;
							if(dd<10 && (dd+"").length==1) dd = "0"+dd;
							var datestr = yyyy+"-"+mm+"-"+dd;
							message = (this.isDate(datestr)) ? "" : this.ERROR_DATE;
						}
						message += this.validateSingleDropDownList(node);
						if(message != ""){
							errorMessage += message;
							globalErrorCount++;
							fieldErrorCount++;
							this.errorSummary += errorMessage + "\n";
						}
					
					}
					//Checkbox validation (only required)
					else if(type == "checkbox"){
						
						// is it group or single?
						
						var isGroup = node.up('.checkboxgroup');
						
						var tempArr = new Array();
						var tempVal = validatorString;
						tempArr = tempVal.split(" ");
						var go = false;
						var checked = true;
						for(var k = 0; k < tempArr.length; k++){
							if(tempArr[k] == this.R){
								go = true;
								break;
							}
						}
							if (go == true) {
							if (isGroup) {
								var res = "";
								isGroup.select("input[type=checkbox]").each(function(i){
									var c = i.checked;
									res += c;
								});
								if(res.lastIndexOf('true') < 0) {
									globalErrorCount++;
									fieldErrorCount++;
									if (header != "") {
										var str = this.ERROR_NOTCHECKED.replace("field", header.toLowerCase());
										errorMessage = (errorMessage.indexOf(str) < 0) ? str : "";
									}
									else {
										var str = this.ERROR_NOTCHECKED.replace("field", "");
										errorMessage = (errorMessage.indexOf(this.ERROR_NOTCHECKED) < 0) ? str : "";
									}
										
									this.errorSummary += errorMessage + "\n";
								}
							}else{
								checked = node.checked;
								if (checked == false) {
									globalErrorCount++;
									fieldErrorCount++;
									if (header != "") {
										errorMessage += this.ERROR_NOTCHECKED.replace("field", header.toLowerCase());
									}
									else {
										errorMessage += this.ERROR_NOTCHECKED.replace("field", "");
									}
									
									this.errorSummary += errorMessage + "\n";
								}
							}
						}
					}
					else if(type == "radio"){
						
						// is it group or single?
						var isGroup = node.up('.radiobuttongroup');
						
						var tempArr = new Array();
						var tempVal = validatorString;
						tempArr = tempVal.split(" ");
						var go = false;
						var checked = true;
						for(var k = 0; k < tempArr.length; k++){
							if(tempArr[k] == this.R){
								go = true;
								break;
							}
						}
							if (go == true) {
							if (isGroup) {
								var res = "";
								isGroup.select("input[type=radio]").each(function(i){
									var c = i.checked;
									res += c;
								});
								if(res.lastIndexOf('true') < 0) {
									globalErrorCount++;
									fieldErrorCount++;
									if (header != "") {
										var str = this.ERROR_NOTCHECKED.replace("field", header.toLowerCase());
										errorMessage = (errorMessage.indexOf(str) < 0) ? str : "";
									}
									else {
										var str = this.ERROR_NOTCHECKED.replace("field", "");
										errorMessage = (errorMessage.indexOf(this.ERROR_NOTCHECKED) < 0) ? str : "";
									}
									
										
									this.errorSummary += errorMessage + "\n";
								}
							}else{
								checked = node.checked;
								if (checked == false) {
									globalErrorCount++;
									fieldErrorCount++;
									if (header != "") {
										errorMessage += this.ERROR_NOTCHECKED.replace("field", header.toLowerCase());
									}
									else {
										errorMessage += this.ERROR_NOTCHECKED.replace("field", "");
									}
									
									this.errorSummary += errorMessage + "\n";
								}
							}
						}
					}
					else{
						validators = validatorString.split(" ");
						
						
						//Iterate and perform validation
						for(var j= 0; j < validators.length; j++){
							//Validate required field
							if( validators[j] == this.R ){
								if(this.isEmpty(node.value)){
									globalErrorCount++;	
									fieldErrorCount++;
									//Construct html error message
									if(header != ""){
										errorMessage +=this.ERROR_EMPTY.replace("field", header.toLowerCase());
									}
									else
										errorMessage += this.ERROR_EMPTY.replace("field", "");
										
										this.errorSummary += errorMessage + "\n";										
								}
								else if (! this.isEmpty(node.value) && type == "password"){
									if(node.value.length < this.MIN_PASSWORDLENGTH){
										globalErrorCount++;	
										fieldErrorCount++;
								
										if(header != ""){
											errorMessage += this.ERROR_PASSWORD.replace("field", header.toLowerCase());
										}
										else
											errorMessage += this.ERROR_PASSWORD.replace("field","");
									
										this.errorSummary += errorMessage + "\n";
									}
								}
							}
							
							//Validate character count
							if ( validators[j] == this.M ){
								if(this.isTooLong(node, this.MAX_CHARS)){
									globalErrorCount++;
									fieldErrorCount++;
									//Construct html error message
									if(header != ""){
										errorMessage += this.ERROR_MAXCHARS.replace("field",  header.toLowerCase() );
									}
									else
										errorMessage += this.ERROR_MAXCHARS.replace("field", "");
										
										this.errorSummary += errorMessage + "\n";
								}
							}
							
							//Validate url
							if ( validators[j] == this.U ){
								
								if(! this.isUrl(node.value)){
									globalErrorCount++;
									fieldErrorCount++;
									//Construct html error message
									if(header != ""){
										errorMessage += this.ERROR_URL.replace("field",  header.toLowerCase() );
									}
									else
										errorMessage += this.ERROR_URL.replace("field", "");	
										
									this.errorSummary += errorMessage + "\n";		
								}
							}
							
							//Validate email
							if ( validators[j] == this.E ){
								if(node.value.length > 0){
									if(! this.isEmail(node.value)){
										globalErrorCount++;
										fieldErrorCount++;
										if(header != ""){
											errorMessage += this.ERROR_EMAIL.replace("field",  header.toLowerCase() );
										}
										else
											errorMessage += this.ERROR_EMAIL.replace("field", "");
											
										this.errorSummary += errorMessage + "\n";
									}
								}
							}
							
							//Validate content type
							if ( validators[j] == this.CT ){
								if(node.value.length > 0){
									if(! this.isJPG(node.value)){
										globalErrorCount++;
										fieldErrorCount++;
										if(header != ""){
											errorMessage += this.ERROR_CONTENT_TYPE.replace("field", header.toLowerCase());
										}
										else
											errorMessage += this.ERROR_CONTENT_TYPE.replace("field", "");
										
										this.errorSummary += errorMessage + "\n";
									}
								}
							}
							
							//Validate image size
							if ( validators[j] == this.IS ){
								if(node.value.length > 0){
									var size = this.isFileToLarge(node.value);
									if(size != -1){
										if(size == true){
											globalErrorCount++;
											fieldErrorCount++;
											if(header != ""){
												errorMessage += this.ERROR_FILE_SIZE.replace("field", header.toLowerCase() );
											}
											else
												errorMessage += this.ERROR_FILE_SIZE.replace("field", "");
											
											this.errorSummary += errorMessage + "\n";
										}
									}
								}
							}//if
							
							//Validate equal to
							if( validators[j].indexOf(this.ISE) > -1 ){
								var arr = new Array();
								
								/*
								Html syntax for this special validator: 
								
								<label for="password" class="required"><span>*</span></label>
								<input type="password" id="password" name="password"/>
								<label for="passwordCopy" class="required isequal:password><span>*</span></label>
								<input type="passwordCopy" id="password" name="passwordCopy"/>
								
								*/
								
								//Get the field to compare with
								arr = validators[j].split(":"); // shold be {'isequal', 'password'} from the above example
								if(arr.length > 0){
									var key = arr[1];
									var compareElement = this.currentForm.select("input#" + key);
									if(compareElement != null && compareElement.length > 0){
										if( ! (node.value == compareElement[0].value) ){
											//alert(compareElement[0].id);
											var compareElementHeader = this.getHeader(compareElement[0].id);
											globalErrorCount++;
											fieldErrorCount++;
											
											if(compareElementHeader != "" && header != "")
												errorMessage += this.ERROR_NOTEQUAL.replace("field", compareElementHeader).replace("efield", header); 
											else
												errorMessage += this.ERROR_NOTEQUAL.replace("field", "").replace("efield","");
												
											this.errorSummary += errorMessage + "\n";
										}//if
										
									}//if
								}//if
							}//if
							
							//Validate number
							if( validators[j] == this.N ){
								try{
									parseInt(node.value);
								}
								catch(err){
									globalErrorCount++;
									fieldErrorCount++;
									
									if(header != ""){
										errorMessage += this.ERROR_NOTNUMBER.replace("field", header.toLowerCase());
									}
									else
										errorMessage += this.ERROR_NOTNUMBER.replace("field", "");
										
									this.errorSummary += errorMessage;
								}//catch
							}//if
							
							//Validate date
							if( validators[j] == this.D ){
								
								var datestr = node.value;
								
								if(datestr.length > 0){
									if(this.isDate(datestr) == false){
										globalErrorCount++;
										fieldErrorCount++;
										
										if(header != ""){
											errorMessage += this.ERROR_DATE.replace("field", header.toLowerCase());
										}
										else
											errorMessage += this.ERROR_DATE.replace("field", "");
											
										this.errorSummary += errorMessage + "\n";
									
									}
								}
							}//if
							
							//Validate social security number
							if( validators[j] == this.P ){
								if(node.value.length > 0){
									if(! new this.isPNumber(node.value).valid ){
										globalErrorCount++;
										fieldErrorCount++;
										
										if(header != ""){
											errorMessage += this.ERROR_PNUMBER.replace("field", header.toLowerCase());
										}
										else
											errorMessage += this.ERROR_PNUMBER.replace("field","");
											
										this.errorSummary += errorMessage + "\n";
									}
								}
							}//if
							
							//Validate organisation number
							if( validators[j] == this.O){
								if(node.value.length > 0){
									if(! new this.isOrgNumber(node.value).valid ){
										globalErrorCount++;
										fieldErrorCount++;
										
										if(header != ""){
											errorMessage += this.ERROR_ORGNUMBER.replace("field", header.toLowerCase());
										}
										else
											errorMessage += this.ERROR_ORGNUMBER.replace("field","");
											
										this.errorSummary += errorMessage + "\n";
									}
								}
							
							}//if												
						}//for
					}//else
					if(fieldErrorCount > 0){
						if(this.hasPageErrorElements()){
							if(this.errorElementExist(nodeName)){
								this.showErrorMessage(nodeName, errorMessage, false, f.id);
							}
							else{
								notShown++;
								fragmentErrorMessage += errorMessage + "\n";
							}
						}
						errorMessage = "";
					}
					else{
						if(this.hasPageErrorElements()){
							if(this.errorElementExist(nodeName)){
								this.hideErrorMessage(nodeName, false, f.id);
							}
						}
					}
				}//if
			}//if
		}//for
		
		if(globalErrorCount > 0){
			if(typeof( Settings.scope.select(this.errorDivIfrm)[0] )!= "undefined"){
				var errorDivIfrm = Settings.scope.select(this.errorDivIfrm)[0];
				//Special treatment for reporting an comment
				if(errorDivIfrm != null){
					this.ERROR_HEADER = this.ERROR_HEADER.replace("count", "");
					errorDivIfrm.className = "error";
					errorDivIfrm.innerHTML = this.ERROR_HEADER;
				}
			}
			else
			{
				this.ERROR_HEADER = this.ERROR_HEADER.replace("count", "");
				if(this.showErrorMessage(this.errorDiv, this.ERROR_HEADER, true, f.id) == false){
					alert(this.errorSummary);
				}
				else if(notShown > 0){
					alert(fragmentErrorMessage);
					fragmentErrorMessage = "";
				}
			}

			this.adjustModalWindow();
			//this.initForm(f);
			this.errorSummary = "";
			return false;
		}
		else{
			if(typeof( Settings.scope.select(this.errorDivIfrm)[0] )!= "undefined"){
				var errorDivIfrm = Settings.scope.select(this.errorDivIfrm)[0];
				//Special treatment for reporting an comment
				if(errorDivIfrm != null){
					errorDivIfrm.className = "errorHidden";
					errorDivIfrm.innerHTML = "";
				}
			}
			else
			{
				this.hideErrorMessage(this.errorDiv, true, f.id);
			}
		}
		
		//This is needed for a multiple select box
		this.selectAllOptions(f);
		return true;
		
	},
	/**
		Simple email validation
			@param formElementValue
				The value to validate.
	*/
	isEmail : function(formElementValue){
		var regexp = /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/;
		return regexp.test(formElementValue);
	},
	/**
		Simple url validation
		TODO: Maybe add https and ftp?
		
		@param formElementValue
			The value to validate
			
	*/
	isUrl: function(formElementValue) {
		var regexp = /http:\/\/([\w-]+\.)+[\w-]+(\/[\w- ./?%&=]*)?/;
		return regexp.test(formElementValue);
	},
	/**
		Checks if form element is empty.
			@param formElementValue
				The value to validate.
	*/
	isEmpty: function(formElementValue){
		return formElementValue.length == 0;
	},
	/**
		Simple max character validation.
			@param formElementValue
				The value to validate
			@param maxchars
				Character limit.
	*/
	isTooLong: function(formElement, maxchars){
		var max = formElement.maxChars;
		var m;
		
		m = (max != null) ? max : maxchars;
			
		return formElement.value.length > m;
	},
	/**
		Simple file extension validation.
			@param formElementValue
				The value to validate.
	*/
	isJPG: function(formElementValue){
		return formElementValue.toLowerCase().indexOf(".jpg") > -1;
	},
	/**
		Does not currently work at all, unless a plugin is
		installed in FF. Remove later...?
	
	*/
	isFileToLarge: function(formElementValue){
		var binary;
		var size = 0;
		
		
		if(this.isJPG(formElementValue)){
			var img = new Image();
			img.src = formElementValue;
			//alert(img.fileSize);
			
			if(typeof(img.fileSize) != "undefined"){
				if(img.fileSize != -1)
					return parseInt(img.fileSize) > this.MAX_FILE_SIZE;
			}
			
			if(typeof(img.fileSize) == "undefined"){
			
				// request local file read permission
				try {
					netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
				} catch (e) {
					//alert("Permission to read file was denied.");
					return -1;
				}
				
				// open the local file
				var file = Components.classes["@mozilla.org/file/local;1"]
					.createInstance(Components.interfaces.nsILocalFile);
				file.initWithPath( formElementValue );		
				stream = Components.classes["@mozilla.org/network/file-input-stream;1"]
					.createInstance(Components.interfaces.nsIFileInputStream);
				stream.init(file,	0x01, 00004, null);
				var bstream =  Components.classes["@mozilla.org/network/buffered-input-stream;1"]
					.getService();
				bstream.QueryInterface(Components.interfaces.nsIBufferedInputStream);
				bstream.init(stream, 1000);
				bstream.QueryInterface(Components.interfaces.nsIInputStream);
				binary = Components.classes["@mozilla.org/binaryinputstream;1"]
					.createInstance(Components.interfaces.nsIBinaryInputStream);
				binary.setInputStream (stream);
	
					
				return parseInt(size) > this.MAX_FILE_SIZE;
			}
		}
		
		return -1;
		
	},
	
	/*  The code contained in this  file is copyrighted by www.jojoxx.net
		The file may be used for none commercial applications and distributed
		as long as these lines remain intact.  The file or part of it may not
		be sold  or  included  in any  other commercial  application  without
		agreement from the author. If you have questions or comments, contact
		the author at http://www.jojoxx.net
		
		? Copyright - www.jojoxx.net - 2004
		
		Social security number validation
			@param formElementValue
				The value to validate
	*/
	
	isPNumber: function(formElementValue){
		this.valid = false;
		if(! formElementValue.match(/^(\d{2})(\d{2})(\d{2})\-(\d{4})$/)){ return false; }
		this.now=new Date(); this.nowFullYear=this.now.getFullYear()+""; this.nowCentury=this.nowFullYear.substring(0,2); this.nowShortYear=this.nowFullYear.substring(2,4);
		this.year=RegExp.$1; this.month=RegExp.$2; this.day=RegExp.$3; this.controldigits=RegExp.$4;
		this.fullYear=(this.year*1<=this.nowShortYear*1)?(this.nowCentury+this.year)*1:((this.nowCentury*1-1)+this.year)*1;
		var months = new Array(31,28,31,30,31,30,31,31,30,31,30,31);
		if(this.fullYear%400==0||this.fullYear%4==0&&this.fullYear%100!=0){ months[1]=29; }
		if(this.month*1<1||this.month*1>12||this.day*1<1||this.day*1>months[this.month*1-1]){ return false; }
		this.alldigits=this.year+this.month+this.day+this.controldigits;
		var nn="";
		for(var n=0;n<this.alldigits.length;n++){ nn+=((((n+1)%2)+1)*this.alldigits.substring(n,n+1)); }
		this.checksum=0;
		for(var n=0;n<nn.length;n++){ this.checksum+=nn.substring(n,n+1)*1; }
		this.valid=(this.checksum%10==0)?true:false;
		this.sex=parseInt(this.controldigits.substring(2,3))%2;
	
	},
	/*  The code contained in this  file is copyrighted by www.jojoxx.net
		The file may be used for none commercial applications and distributed
		as long as these lines remain intact.  The file or part of it may not
		be sold  or  included  in any  other commercial  application  without
		agreement from the author. If you have questions or comments, contact
		the author at http://www.jojoxx.net
		
		? Copyright - www.jojoxx.net - 2004
		
		Organisationnumber validation
			@param formElementValue
				The value to validate
	*/
	isOrgNumber: function(formElementValue){
		this.valid=false;
		if(! formElementValue.match(/^(\d{1})(\d{5})\-(\d{4})$/)){ return false; }
		this.group=RegExp.$1;
		this.controldigits=RegExp.$3;
		this.alldigits=this.group+RegExp.$2+this.controldigits;
		if(this.alldigits.substring(2,3)<2){ return false }
		var nn="";
		for(var n=0;n<this.alldigits.length;n++){ nn+=((((n+1)%2)+1)*this.alldigits.substring(n,n+1)); }
		this.checksum=0;
		for(var n=0;n<nn.length;n++){ this.checksum+=nn.substring(n,n+1)*1; }
		this.valid=(this.checksum%10==0)?true:false;
	
	},
	/**
		Basic date validation
			@param formElementValue
				The value to validate
	
	*/
	isDate: function(formElementValue){
		var validformat = /^\d{4}\-\d{2}\-\d{2}$/ //Format validity
		var isValid = true;
	
		if (! validformat.test(formElementValue)){
			isValid = false;
		}
		else{ //Check date ranges
			var yearfield = formElementValue.split("-")[0]
			var monthfield = formElementValue.split("-")[1]
			var dayfield = formElementValue.split("-")[2]
			var dayobj = new Date(yearfield, monthfield-1, dayfield)
			
			if ( ( (dayobj.getMonth()+ 1) != monthfield )||( dayobj.getDate()!= dayfield )||( dayobj.getFullYear()!= yearfield )){  
				isValid = false;
			}
		}
		
		return isValid;
	},
	/**
	 * Seperate method for validating a mulitple select box, simply
	 * because the base method was too long :-)
	 *	
	 *	@param formElement
	 *		The select input element
	 */
	validateDropDownList: function(formElement){
		
		var errorMessage = "";
		this.deleteDefaultValue(formElement);
		var validators = new Array();
		
		var parent = formElement.parentNode;
		var validatorString = this.getValidators(formElement.id);
		var labelText = this.getHeader(formElement.id);
		
		if(validatorString != ""){
			validators = validatorString.split(" ");
			
			for(var i = 0; i < validators.length; i++){
				if(validators[i] == this.R){
					if(formElement.length == 0){
						if(labelText != ""){
							errorMessage += this.ERROR_EMPTY.replace("field", labelText.toLowerCase());
						}
						else
							errorMessage += this.ERROR_EMPTY.replace("field", "");
					}
				}
				if(validators[i] == this.M)
					continue;
				if(validators[i] == this.E)
					continue;
				if(validators[i] == this.MC){
					if(formElement.length >= this.MAX_COUNT){
						if(labelText != ""){
							errorMessage += this.ERROR_MAXCOUNT.replace("field", labelText.toLowerCase());
						}
						else
							errorMessage += this.ERROR_MAXCOUNT.replace("field","");
					
					}
				}
				
				if(validators[i] == this.U){
					if(formElement.length > 0){
						for(var j = 0; j < formElement.length; j++){
							if(! this.isUrl(formElement.options[j].value)){
								if(labelText != ""){
									errorMessage += this.ERROR_URL.replace("field", labelText.toLowerCase());
								}
								else
									errorMessage += this.ERROR_URL.replace("field",  "");
										
								break;
							}
						}
					}
				}
			}
		}
		
		return errorMessage;
	
	},
	
	/**
	 * Validates a single dropdown list. Only required.
	 * 
	 *	
	 *	@param formElement
	 *		The select input element
	 */
	 
	validateSingleDropDownList: function(formSelect){
		var validatorString = this.getValidators(formSelect.id);
		var labelText = this.getHeader(formSelect.id);
		var errorMessage = "";
		
		if(validatorString != ""){
			var validators = validatorString.split(" ");
			
			if(validators.length > 0){
				for(var i = 0; i < validators.length; i++){
					if(validators[i] == this.R){
						var selectedValue = formSelect.options[formSelect.selectedIndex].value;
						if(this.isEmpty(selectedValue) || selectedValue.length == 0 || selectedValue.length == this.DEFAULT_SELECT_VALUE){
							if(labelText != ""){
								errorMessage += this.ERROR_EMPTY.replace("field", labelText.toLowerCase());
							}
							else{
								errorMessage += this.ERROR_EMPTY.replace("field", "");
							}
						}	
					}
				}
			}
		}
		return errorMessage;
	},
	
	/**
	 *	This method selects all the validated options in
	 *	a multiple select box. This is required since no
	 *	values will be saved unless this is done. The 
	 *	method is called after that all elements in the
	 *	form passed its validation.
	 *	
	 *	@param f
	 *		The form
	 */
	selectAllOptions: function(f){
		for(var i= 0; i < f.elements.length; i++){
			if(f.elements[i].type == "select-multiple"){
				var selectbox = f.elements[i];
				if(selectbox.length > 0){
					for(var j = 0; j < selectbox.length; j++){
						if(selectbox.options[j].value == ""){
							selectbox.remove(j);
						}
						else
							selectbox.options[j].selected = true;
					}
				}
			}
		}
	},
	
	/**
	 *	Get the header from the label tag which is bound to 
	 *	the input form element. Is used to dynamically indicate
	 *	which field the error occured in.
	 *	
	 *	@param elementId
	 *		The form element id
	 */
	getHeader: function(elementId){
		var header = "";
		if (elementId != "") {
			var elm = $(elementId);
			if ( (typeof elm.up('fieldset.checkboxgroup') != 'undefined') || (typeof elm.up('fieldset.radiobuttongroup') != 'undefined')) {
				var h = $(elementId).up('fieldset').down('legend');
				if(h) return h.innerHTML;
				var ps = $(elementId).up('fieldset').select('p');
				h = (ps.length>1 && ps[0].up().hasClassName('error')) ? ps[1] : ps[0];
				if(h) {
					return h.innerHTML;
				}
			}
		}
		var allLabels = Settings.scope.select('label');
		var header = "";
		for(var i = 0; i < allLabels.length; i++){	
			if(allLabels[i].htmlFor == elementId){
				header = allLabels[i].innerHTML;
				if(header.toLowerCase().indexOf("<span") > -1)
					header = header.substring(0, header.toLowerCase().indexOf("<span"));
					
				break;
			}
		}
	
		return header;
	},
	/**
	 *  Returns validators for form element with specific id
	 *  
	 *  @param elementId
	 *	The id of the element to find validators for
	 *	
	 *	@returns
	 *	A string with one or more validators separated with whitespace
	 */
	getValidators: function(elementId){
		var validators = "";
		if (elementId != "") {
			var elm = $(elementId);
			if ((typeof elm.up('fieldset.checkboxgroup') != 'undefined') || (typeof elm.up('fieldset.radiobuttongroup') != 'undefined')) {
				return $(elementId).up('fieldset').className;
			}
		}
		var allLabels = Settings.scope.select('label');
		
		for(var i = 0; i < allLabels.length; i++){	
			if(allLabels[i].htmlFor == elementId){
				validators = allLabels[i].className;
				break;
			}
		}
	
		return validators;
	},
	/**
	 *	Shows an error message if an error ocurred
	 *	
	 *	@param elementId
	 *		The elementId of the formelement which will be used
	 *		as a part to form the div id to show.
	 *	
	 *	@param message
	 *		The error message to show
	 *	
	 *	@param isHeader
	 *		Indicate if we are showing a specific error
	 *		or the general error message.
	 *	
	 *	@param theFormId
	 *		The id on the form	
 	 */
	showErrorMessage: function(elementId, message, isHeader, theFormId){
		
		if(isHeader == false)
			var div = this.getErrorElement(elementId);//$$(this.errorDiv + elementId)[0];
		else
			var div = this.getErrorElement(theFormId);//$$(this.errorDiv)[0];
		
		var span = Settings.scope.select("span#" + elementId + "Exclamationmark");
		
		if(span != null && span.length > 0){
			span[0].className = "exclamationmark_visible";
		}
			
		if(div != null){
			div.className = "error";
			div.innerHTML = "<p>" + message + "</p>";
			return true;
		}
		
		return false;
	
	},
	/**
	 * Hides an error message if an error ocurred
	 *	@param
	 *		The form element id.
	 *	@param isHeader
	 *		Indicate if we are hiding a specific error
	 *		or the general error message
	 *	@param theFormId
	 *		The id on the form.
	 */
	hideErrorMessage: function(elementId, isHeader, theFormId){
	
		if(isHeader == false)
			var div = this.getErrorElement(elementId);//$$(this.errorDiv + elementId)[0];
		else
			var div = this.getErrorElement('error' + theFormId);//$$(this.errorDiv)[0];
			
		var span = Settings.scope.select("span#" + elementId + "Exclamationmark");
		
		if(span != null && span.length > 0){
			span[0].className = "exclamationmark_hidden";
		}
			
		if(div != null){
			div.innerHTML = "";
			div.className = "errorHidden";
			return true;
		}
		
		return false;
		
	},
	/**
	 *	Deletes a default value form a select-multiple box, usually an item with an empty value
	 *		@param formElement
	 *			The form element (select-multiple)
	 */
	deleteDefaultValue: function(formElement){
		//Delete the default value before submitting (if it is still there)
		for(i = formElement.length - 1; i >= 0; i--){
			if(formElement.options[i].value == "")
				formElement.remove(i);
		}
	},
	/**
	 *	Hides all previous error messages.
	 *		@param elementId
	 *			The form element id
	 *		@hideAll
	 *			Indicates if all errors will be hidden or if
	 *			all eccept one (@param elementId).
	 */
	hideAllErrorMessages: function(elementId, hideAll){
		var allDivs = Settings.scope.select('DIV');
		for(var i = 0; i < allDivs.length; i++){
			if(hideAll == true){
				if(allDivs[i].className == "error")
					allDivs[i].className = "errorHidden";
			}
			else{
				if(allDivs[i].className == "error" && allDivs[i].id != elementId)
					allDivs[i].className = "errorHidden";
					
			}
		}
	},
	/**
	 *	Makes sure that the ModalWindow appearance is ok.
	 */
	adjustModalWindow: function(){
		// removed since it has no function and created 
		// a unwanted blink effect. 
		// See #1565 
		//ModalWindow.finishLoad();
		
		// scroll to the top of the window.
		if(typeof($('modalWindowInner')) != "undefined" && $('modalWindowInner') != null){
			if(typeof($('modalWindowInner').childElements()[0]) != "undefined" && $('modalWindowInner').childElements()[0] != null){
				$('modalWindowClose').focus();
				ModalWindow.reposition();
			}else{
				var errs = $$('div.mainColumn div.error');
				if(errs.length>0) $$('div.mainColumn div.error')[0].scrollTo();
			}
		}
	},
	/**
	 *	Focus the first field in the form.
	 *		@param theForm
	 *			The form element
	 */
	initForm: function(theForm){
		for(var i = 0; i < theForm.elements.length; i++){
			var type = theForm.elements[i].type;
			var element = theForm.elements[i];
			
			if(type == "text"){
				element.focus();
				break;
			}
		}
	},
	/**
	 *	Check if the page has multiple login forms.
	 */
	hasDuplicateLogin: function(){
		var allForms = $$("form#formLoginStart");
		var allDivs = $$("div#login_container");
		return allForms.length > 1 && allDivs.length > 1;
	
	},
	/**
	 *	Get the error (div element) element to show the error message in.
	 *	@param elementId
	 *		The element.
	 */
	getErrorElement: function(elementId){
		var elm = $(elementId);
		if(elm != null){
			if( (typeof elm.up('fieldset.checkboxgroup')!='undefined' ) || (typeof elm.up('fieldset.radiobuttongroup')!='undefined') ){
				return elm.up('fieldset').select('div[class^=error]')[0];
			}else{
				var div = null;
				if(this.hasDuplicateLogin() && this.isModalVisible()){
					var id = elementId.replace("div#", "");
					var divs = this.getAllErrorElements(1);
					for(var i = 0; i < divs.length; i++){
						if( (divs[i].className == "error" || divs[i].className == "errorHidden") && divs[i].id == id){
							div = divs[i];
							break;
						}
					}
				}
				else{
					div = this.currentForm.select('#error'+elementId)[0];
				}
				
				return div;
			}
		}
	},
	/**
	 *	Get all div elements from a given container. Used
	 *	when there are mulitple login forms and containers.
	 *	
	 *	@param index
	 *		
	 */
	getAllErrorElements: function(index){
		return this.currentForm.getElementsByTagName("DIV");
	},
	/**
	 *	Check if the ModalWindow is visible or not.
	 */
	isModalVisible: function(){
		var modalDiv = $$("div#modalWindowWrapper");
		
		if(modalDiv != null && modalDiv.length > 0){
			return $$("div#modalWindowWrapper")[0].style.display == "block";
		}
		else
			return false;
	},
	/**
	  * Checks if there are error container elements on the page
	  *
	  */
	  
	hasPageErrorElements: function(){
		var allDivs = $$('DIV');
		var occurrence = 0;
		
		if(allDivs.length > 0){
			for(var i = 0; i < allDivs.length; i++){
				var id = allDivs[i].id;
				if(typeof(id) != "undefined" && id != null){
					if(id.indexOf("error") > -1){
						occurrence++;
					}
				}
			}
		}
		
		return occurrence > 0;
	},
	
	errorElementExist: function(elementId){
		var element = "div#error" + elementId;
		if(Settings.scope.select(element).length == 0){
			var isgrp = $(elementId).up('fieldset[class*=group]');
			if(isgrp){
				return isgrp.select('div[class^=error]').length > 0;
			}else {
				return false;
			}
		}else{
			return true;
		}
	},
	
	/**
	 * If the user log out the login form is shown in the main page (full screen). 
	 * If the user clicks the login link in the top menu again the 
	 * modal login window is shown on top on login page in the background. 
	 * This method removes all disturbance for FormValidation if the above occur.
	 */
	removeDuplicateFormEvent : function (){
		var allForms = $$("form#formLoginStart");
		
		/*
			Oops, there is two login forms on the page with
			the same id (e.g login forms).
			Remove the onsubmit event from the login form
			in the background since we don?t need it.
		*/
		
		/*
			Detach the onsubmit event for the first form, since we know
			that this is the form in the disabled background.
		*/
		
		if(allForms.length > 1){
			if(allForms[0].detachEvent){
				allForms[0].detachEvent('onsubmit', FormValidation.checkForm);
			}
			else if (allForms[0].removeEventListener){
				allForms[0].removeEventListener('submit', FormValidation.checkForm, false);
			}
		}
		
		/*
			Remove all configured error div elements from the first
			login_container div in the background since we
			know that those elements belongs to the form in
			the disabled background.
		*/
		
		if($$("div#login_container").length > 1){
			var allDivs = $$("div#login_container")[0].getElementsByTagName("DIV");
			for(var i = 0; i < allDivs.length; i++){
				if(allDivs[i].className == "error"){
					$(allDivs[i].id).remove();
				}
			}
		}
	}
}

/**
 *  Init form validation on all existing forms on the page.
 */
function prepareFormValidation() {
	if(!Settings.isEnabled('FormValidation')) return;
	
    Settings.scope.select("form").each( function(item){
		Event.observe(item,'submit',function(e) {
			var f = e.element();
			var firedButton = f.select(Form.cn.firedBtn);
			var cancelButtonPressed = false;
			if(firedButton.length > 0) {
				cancelButtonPressed = firedButton[0].value.toLowerCase().indexOf('avbryt') >= 0;
			}
			if (cancelButtonPressed == false) {
				if (!FormValidation.checkForm(f)) e.preventDefault();
			}
		});
	});
	/* Disabled since method does not work properly */
	// FormValidation.removeDuplicateFormEvent();
}

/* *** End FormValidation *** */

/* *** Modal Window *** */

/**
 * Gets defined window options for the given element, or a default setting if no custom options are set.
 * This function is called every time a ModalWindow instance is loaded or reloaded.
 * See wiki for further explanations.
 * 
 * @param url
 * 		String URL, in case element isn't a link
 * 
 * @param element
 * 		The event element
 * 
 */
function getModalOptions(url, element) {
	// Default options
	var options = {
		beforeLaunch : null,
		params : {
			href: url,
			type: null,
			reloadLinks : true,
			reloadOnClose : false,
			closeButton : true,
			scrollable : false,
			wrapperClass : null
		},
		onload : null,
		onsubmit : null,
		onunload : null,
		evalResponse : null
	}
	
	if(element.className.length > 0) {
		var wcl = "";
		var cns = element.className.split(" ");
		for(var i=0,max=cns.length;i<max;i++){
			wcl += "mw_"+cns[i]+" ";
		}
		options.params.wrapperClass = wcl;
	}
	
	if(element.id.length > 0) {
		options.params.wrapperClass += "mw_"+element.id+" ";
	}
	
	// Customize options by element classnames
	
	if(element.hasClassName('tipAFriend')) {
		options.params.width = 300;
		options.params.closeButton = true;
	}
	
	else if(element.hasClassName('reportForm')) {
	}
	
	else if(element.hasClassName('viewMyPhoto')) {
		options.params.width = 468;
		options.onload = function() {
			MyPhotos.initViewer();
		}
	}
	
	else if(element.id == "registerAndEditForm") {
		options.onload = function() {
			if ($$("#modalWindowWrapper p.back a").length > 0) {
				$$("#modalWindowWrapper p.back a")[0].onclick = function(){
					ModalWindow.reload(addQueryStringParam(this.href, "m", "modal"), this);
					return false;
				}
			}
		}
		options.evalResponse = function(response) {
			if($$("#modalWindowWrapper div.confirmation").length > 0) {
				ModalWindow.options.reloadOnClose = true;
			}
			else if($$("#modalWindowWrapper div.loggOffContainer").length > 0){
				ModalWindow.options.reloadOnClose = true;
			}
		}
		options.onsubmit = function() {
			setFormCookie('acceptsCookies');
			return true;
		};
	}
	
	else if(element.id == 'formLoginStart') {
		options.onsubmit = function() {
			setFormCookie('acceptsCookies');
			return true;
		};
		options.evalResponse = function(response){
			if($$("#modalWindowWrapper #registerAndEditForm").length > 0) {
				location.reload();
				/*for (var i=0; i < element.elements.length; i++) {
					var inpt = element.elements[i];
					if(inpt.name == "redirectUrl") {
						location.assign(inpt.value.replace(/m=modal/,""));
						break;
					}
				}*/
			}
		}
	}
	
	else if(element.id == 'registerConfirmForm') {
		options.onload = function() {
			for (var i=0; i < element.elements.length; i++) {
				var inpt = element.elements[i];
				if(inpt.name == "redirectUrl") {
					inpt.value = addQueryStringParam(inpt.value,"m","modal");
					break;
				}
			}
		}
		options.params.reloadOnClose = true;
		options.onsubmit = function() {
			setFormCookie('acceptsCookies');
			return true;
		};
	}
	
	else if(element.id == 'recoverPasswordForm') {
		options.onload = function() {
			for (var i=0; i < element.elements.length; i++) {
				var inpt = element.elements[i];
				if(inpt.name == "redirectUrl") {
					inpt.value = addQueryStringParam(inpt.value,"m","modal");
					break;
				}
			}
		}
	}
	
	else if(element.id == 'reportContent') {

	}
	
	else if(url == 'blogFormExtras_link') {
		options.onload = function() {
			Blog.ManageEntry.prepareLinkDialog();
		}
		options.params.reloadLinks = false;
	}
	
	else if(url == 'blogFormExtras_image') {
		options.onload = function() {
			Blog.ManageEntry.prepareImageDialog();
		}
		options.params.reloadLinks = false;
	}
	
	else if(url == 'blogFormExtras_movie') {
		options.onload = function() {
			Blog.ManageEntry.prepareMovieDialog();
		}
		options.params.reloadLinks = false;
	}
	
	return options;
}

/**
 * The MKTWebb lightbox/thickbox copy. Needs Prototype 1.6 or higher to work properly.
 */

var ModalWindow = {
	anchor:null,
	options : {
		iefixClassName : null,
		href : null,
		top : null,
		left : null,
		type :	null,
		height : null,
		width :	null,
		reloadLinks : true,
		reloadOnClose : false,
		scrollable : false,
		closeButton : true
	},
	loader : null,
	wrapper : null,
	inner : null,
	errors : null,
	overlay : null,
	onload : null,
	onunload : null,
	evalResponse : null,
	labels : {
		exception : "Ett fel intr&auml;ffade. Var god stäng fönstret och försök igen om en stund.",
		notFound : "Sidan finns inte.",
		loading : "Hämta eller ",
		cancel : "avbryt",
		close : "Stäng"
	},
	elabel : null,
	buttons: {
		close: null,
		cancel:null
	},
	time : {
		delay : 1000
	},
	/**
	 * Open a modal window. This is how the "outside" can create a new ModalWindow.
	 * 
	 * @param {Object} options	created from getModalOptions(). required.
	 */
	open : function(options) {
		if(this.overlay.getStyle("display") == "block") {
			return;
		}
		this.options = Object.extend({
			iefixClassName : null,
			href : null,
			top : null,
			left : null,
			type : null,
			height : null,
			width : null,
			wrapperClass : null,
			reloadLinks : true,
			reloadOnClose : false,
			scrollable : false,
			closeButton : true
		}, options || {});
		this.iefix.ie6_selects("open");
		this.flashfix("open");
		this.flashiframefix("open");
		this.overlay.setStyle({ display:"block" });
		this.initLoader();
		this.load(this.options.href);
		return false;
	},
	importInline : function(options) {
		this.options = Object.extend({
			iefixClassName : null,
			href : null,
			top : null,
			left : null,
			type : null,
			height : null,
			width : null,
			wrapperClass : null,
			reloadLinks : true,
			reloadOnClose : false,
			scrollable : false,
			closeButton : true
		}, options || {});
		this.iefix.ie6_selects("open");
		this.flashfix("open");
		this.flashiframefix("open");
		this.initLoader();
		this.resetWrapper();
		var htlm = $(this.options.href).cloneNode(true);
		htlm.id += "-eyecandy";
		if(htlm.select("input").length>0 && htlm.select("form").length==0) {
			var actile = $(this.options.href).up('form').action;
			this.options.href = actile;
			htlm = htlm.wrap('form',{action:actile,'method':'post','target':Form.iframe.id,'enctype':'multipart/form-data'});
			htlm = htlm.wrap('div',{'id':'userForm'});
		}
		htlm.select('input[id]').each(function(item){
			var l = item.id+"-eyecandy";
			var lbl = htlm.select("label[for="+item.id+"]");
			if(lbl.length>0) lbl[0].setAttribute('for',l);
			item.id = l;
		});
		this.inner.insert(htlm);
		var c = this;
		if(typeof c.evalResponse == "function") c.evalResponse();
		setTimeout(function(){
			c.finishLoad()
		}, this.time.delay);
		return false;
	},
	importFromIframe : function(options,htlm) {
		this.options = Object.extend({
			iefixClassName : null,
			href : null,
			top : null,
			left : null,
			type : null,
			wrapperClass : null,
			height : null,
			width : null,
			reloadLinks : true,
			reloadOnClose : false,
			scrollable : false,
			closeButton : true
		}, options || {});
		this.iefix.ie6_selects("open");
		this.flashfix("open");
		this.flashiframefix("open");
		this.inner.insert(htlm);	
		var c = this;
		
 		if(typeof c.evalResponse == "function") c.evalResponse();
		setTimeout(function(){
			c.finishLoad()
		}, this.time.delay);

		return false;
	},
	/**
	 * refresh the options for the new modal window. Is called every time the window reloads with new content.
	 * 
	 * @param {Object} options	the result from a openAsModal call.
	 */
	loadOptions : function(options) {
		if (typeof options.beforeLaunch == "function") options.beforeLaunch();
		this.onload = options.onload;
		this.onunload = options.onunload;
		this.evalResponse = options.evalResponse;
		this.options = Object.extend({
			iefixClassName : null,
			href : null,
			top : null,
			left : null,
			type : null,
			wrapperClass : null,
			height : null,
			width : null,
			reloadLinks : true,
			reloadOnClose : false,
			scrollable : false,
			closeButton : true
		}, options.params || {});
	},
	/**
	 * Evaluates the content size, then expand and reposition window. Is called every time a form don't pass validation, but
	 * can also be called manually. 
	 */
	reposition : function() {
		if (this.wrapper != null && this.wrapper.getStyle('display') == 'block') {
			this.inner.setStyle({
				height: 'auto'
			});
			this.wrapper.setStyle({
				height: 'auto'
			});
			var y = this.wrapper.getHeight();
			if (y != parseInt(this.height)) {
				var old = this.options.height;
				this.options.height = y;
				this.getDimensions();
				this.renderWindow();
				this.options.height = old;
			}
		}
	},
	/**
	 * Closes the Modal Window. Also quits any ajax calls quietly.
	 */
	close : function() {
		this.overlay.setStyle({ display:"none" });
		this.wrapper.setStyle({ display:"none",width:"auto",height:"auto" });
		this.loader.setStyle({ display:"none" });
		this.errors.setStyle({ display:"none" });
		this.inner.setStyle({ width:"auto",height:"auto" });
		this.inner.innerHTML = null;
		this.elabel.nodeValue = "";
		if(typeof this.onunload == "function") this.onunload();
		if(this.options.reloadOnClose == true) location.assign( location.href );
		this.iefix.ie6_selects("close");
		this.flashfix("close");
		this.flashiframefix("close");
		return false;
	},
	/**
	 * Init variuos buttons. The classnames attach events to buttons, ex .close make the button close the Modal. 
	 */
	initButtons : function() {
		var c = this;
		$$("#modalWindowWrapper .close").each(function(item){
			item.onclick = function(){return c.close();}
		});
		$$("#modalWindowWrapper .btnOk").each(function(item){
			item.onclick = function(){return c.close();}
		});
	},
	/**
	 * Invoke method. Initiates and prepares the Modal Window markup.
	 */
	init : function() {
		if($$(Chat.App.cn.bclass).length > 0 || $$('body.modalWindow').length > 0 || $$('body.print').length > 0 || $('modalWindowWrapper')) return;
		var c = this;
		this.buttons.close = document.createElement("a");
		this.buttons.close.className = "close";
		this.buttons.close.onclick = function(){return c.close();};
		this.buttons.close.href = "#";
		this.buttons.close.appendChild(document.createTextNode( this.labels.close ));
		this.buttons.cancel = document.createElement("a");
		this.buttons.cancel.onclick = function(){return c.close();};
		this.buttons.cancel.className = "cancel";
		this.buttons.cancel.href = "#";
		this.buttons.cancel.appendChild(document.createTextNode( this.labels.cancel));
		this.loader = document.createElement("div");
		this.loader.id = "modalWindowLoader";
		var txt = document.createElement("p");
		txt.appendChild(document.createTextNode( this.labels.loading ));
		txt.appendChild(this.buttons.cancel);
		this.loader.appendChild(txt);
		this.errors = document.createElement("div");
		this.errors.id = "modalWindowErrors";
		this.elabel = document.createTextNode("");
		var ew1 = document.createElement("p");
		ew1.appendChild(this.elabel);
		this.errors.appendChild(ew1);
		var ew2 = document.createElement("p");
		var errclose = this.buttons.close.cloneNode(true);
		errclose.onclick = function(){ return c.close(); }
		ew2.appendChild(errclose);
		this.errors.appendChild(ew2);
		this.wrapper = document.createElement("div");
		this.anchor = document.createElement("a");
		this.anchor.href = "";
		this.anchor.id = "focusModalWindow";
		this.anchor.name = "focusModalWindow";
		this.anchor.title = "";
		this.anchor.appendChild(document.createTextNode("."));
		this.wrapper.appendChild(this.anchor);
		this.inner = document.createElement("div");
		this.inner.id = "modalWindowInner";
		this.wrapper.appendChild(this.inner);
		this.wrapper.id = "modalWindowWrapper";
		this.overlay = document.createElement("div");
		this.overlay.id = "modalWindowOverlay";
		this.overlay.onclick = function(){return c.close()};
		this.mainclose = this.buttons.close.cloneNode(true);
		this.mainclose.id = "modalWindowClose";
		this.wrapper.appendChild(this.mainclose);
		var b = $$("body")[0];
		b.appendChild(this.loader);
		b.appendChild(this.errors);
		b.appendChild(this.wrapper);
		b.appendChild(this.overlay);
		this.loader = $("modalWindowLoader");
		this.errors = $("modalWindowErrors");
		this.wrapper = $("modalWindowWrapper");
		this.overlay = $("modalWindowOverlay");
		this.inner = $("modalWindowInner");
		this.anchor = $("focusModalWindow");
		this.mainclose = $('modalWindowClose');
		this.overlay.setStyle({
			height:b.getHeight()+"px"
		});
	},
	/**
	 * displays the loader dialog while fetching the content of the Modal.
	 */
	initLoader : function() {
		var os = document.viewport.getScrollOffsets();
		this.loader.setStyle({ 
			display:"block",
			marginTop:((this.loader.getHeight()/2) - os.top)*(-1)+"px",
			marginLeft:((this.loader.getWidth()/2) - os.left)*(-1)+"px"
		});
		if(this.overlay.getStyle('display') == 'none') {
			this.overlay.setStyle({display:'block'});
		}
		this.wrapper.className = "";
	},
	/**
	 * Shows error messages when ajax errors occur. The error message dialog is similar to the
	 * loader, but have a error sign instead of ajax loader animation.
	 * 
	 * @param {Object} value	the error code, which determines what error message to show.
	 */
	showErrors : function(value) {
		this.loader.setStyle({display:"none"});
		var os = document.viewport.getScrollOffsets();
	switch (value) {
		case 1:
		this.elabel.nodeValue = this.labels.exception;
		break;
		case 2:
		this.elabel.nodeValue = this.labels.notFound;
		break;
	}
	this.errors.setStyle({ 
		display:"block",
			marginTop:((this.loader.getHeight()/2) - os.top)*(-1)+"px",
			marginLeft:((this.loader.getWidth()/2) - os.left)*(-1)+"px"
		});
		this.initButtons();
	},
	/**
	 * Reload the Modal with other content. This method is called frm inside the modal.
	 * 
 	* @param {string} url	url to the new content.
 	*/
	reload : function(url,el) {
		if (typeof el != "undefined") {
			var options = getModalOptions(url, el);
			this.loadOptions( options );
		}
		this.initLoader();
		this.wrapper.setStyle({ display:"none",width:"auto",height:"auto" });
		this.inner.setStyle({ width:"auto",height:"auto" });
		this.inner.innerHTML = "";
		this.load(url);
		return false;
	},
	resetWrapper : function() {
		this.wrapper.setStyle({ display:"none",width:"auto",height:"auto" });
		this.inner.setStyle({ width:"auto",height:"auto" });
	},
	/**
	 * Load the content and append it to Modal. This is done by an ajax request.
	 * 
	 * @param {string} url
	 */
	load : function(url) {
		this.iefix.ie6_width(this);
		var funcObj = {
			OnSuccess : function(response){
				setTimeout(function(){
					ModalWindow.finishLoad();
				}, ModalWindow.time.delay);
			},
			OnException : function(response){
				ModalWindow.showErrors(1);
			}, 
			OnFailure : function(response){
				ModalWindow.showErrors(2);
			}
		}
		mktAjax.load( url, this.inner, funcObj);
	},
	/**
	 * Makes some general link fixes. Similar to initLinkExtensions(), but for Modal purposes.
	 */
	hreffix : function() {
		var c = this;
		if (this.options.reloadLinks) {
			this.wrapper.select("* a").each(function(elem){
				if(elem.href.indexOf("javascript:") < 0) {
					if( !elem.hasClassName('toggleContent') && !elem.hasClassName('toggleTerms')) {
						elem.href = addQueryStringParam(elem.href, "m", "modal");
						elem.onclick = function(){
							return c.reload(this.href,this);
						}
					}
				}
			});
		}
	},
	/**
	 * Init form instances and prepare onsubmit events. Custom onsubmit events is stored by openAsModal() utilities based on the form's ID.
	 */
	initForms : function() {
		var c = this;
		var forms = $$("#modalWindowWrapper form");
		if (forms.length > 0) {
			var userFormExists = UserForm.exists() || Form.iframe.exists();
			forms.each(function(f){
				if ((f.action.indexOf && f.action.indexOf("#") > 0) || f.action == "#"  || f.action == null || f.action == "") {
					f.action = c.options.href;
				}
				if (!userFormExists) {
					openAsModal(f);
				}else{
					f.action = addQueryStringParam(f.action,'m','modal');
				}
				for(var i = 0; i < f.elements.length; i++){
					if(f.elements[i].type == "text"){
                    	f.elements[i].focus();
                        break;
                    }
                }
			});
		}
	},
	/**
	 * Send form event inside a Window, works much like reload(). This method is called from th openAsModal function.
	 * @param {String} url		the action url
	 * @param {String} pbody	the POST body. Is set by openAsModal().
	 */
	sendForm : function (url,form,options) {
		this.options = Object.extend({
			iefixClassName : null,
			href : null,
			top : null,
			left : null,
			type : null,
			height : null,
			wrapperClass : null,
			width : null,
			reloadLinks : true,
			reloadOnClose : false,
			scrollable : false,
			closeButton : true
		}, options || {});
		this.initLoader();
		this.wrapper.setStyle({ display:"none",width:"auto",height:"auto" });
		this.inner.setStyle({ width:"auto",height:"auto" });
		this.iefix.ie6_width(this);
		if (this.overlay.getStyle('display') != 'block') {
			this.overlay.setStyle({
				display: "block"
			});
		}
		var c = this;
		
		var funcObj = {
			OnSuccess : function(response){
					if (response.responseText != "") {
						if (typeof ModalWindow.evalResponse == "function") {
							ModalWindow.evalResponse(response);
						}
						setTimeout(function(){
							ModalWindow.finishLoad();
						}, ModalWindow.time.delay);
					}else{
						ModalWindow.close();
					}
			},
			OnException : function(response){
				ModalWindow.showErrors(1);
			}, 
			OnFailure : function(response){
				ModalWindow.showErrors(2);
			}
		}
		mktAjax.send(url, this.inner, form, funcObj);
		return false;
	},
	/**
	 * Finish the (successfull) ajax load by appending the content and hide the loader.
	 */
	finishLoad : function() {
		if (this.overlay.getStyle("display") == "none") {
			this.wrapper.setStyle({display:"none"});
			this.loader.setStyle({display:"none"});
		}else {
			this.wrapper.setStyle({
				width:"auto",
				height:"auto",
				marginTop:"0",
				marginLeft:"0"
			});
			this.wrapper.addClassName("factory");
			if (this.options.reloadLinks) {
				this.hreffix();
			}
			this.initButtons();
			if(!this.options.closeButton) {
				this.mainclose.setStyle({display:"none"});
			}else{
				this.mainclose.setStyle({display:"block"});
			}
			this.getDimensions();
			this.renderWindow();
			this.anchor.focus();
			this.initForms();
			if (typeof this.onload == "function") this.onload();
			this.wrapper.className = this.options.wrapperClass;
			this.wrapper.className += this.getChildWrapperClass();
		}
	},
	getChildWrapperClass : function() {
		if(this.inner.innerHTML) {
			var cw = this.inner.select("div");
			
			if(cw.length > 0) {
				var cls = " ";
				var element = (cw[0].className=='modalWindow') ? cw[1] : cw[0];
				if(element.className.length > 0) {
					var wcl = "";
					var cns = element.className.split(" ");
					for(var i=0,max=cns.length;i<max;i++){
						if(!this.wrapper.hasClassName("mw_"+cns[i])) {
							wcl += "mw_"+cns[i]+" ";
						}
					}
					cls += wcl;
				}
				
				if(element.id.length > 0) {
					cls += "mw_"+element.id+" ";
				}
				return cls;
			}
		}
		return "";
	},
	/**
	 * Render the window: remove the loader, set sizes and positions and make the loaded content visible.
	 */
	renderWindow : function() {
		this.loader.setStyle({display:"none"});
		this.wrapper.setStyle({
			width : this.width,
			height : this.height,
			marginTop : this.top,
			marginLeft : this.left,
			display : "block"
		});
		this.inner.setStyle({
			width : this.width,
			height : this.height
		});
		if(this.options.scrollable) {
			this.inner.addClassName("scrollable");
		}
	},
	/**
	 * calculates the dimensions of the Modal. If the modal is to big to fit viewport, size is reduced.
	 * Size can be set manually by either getModalOptions() or by using CSS on the fetched content block.
	 */
	getDimensions : function() {
		var x,y,max,os;
		max = document.viewport.getDimensions();
		os = document.viewport.getScrollOffsets();
		x = (this.options.width != null) ? this.options.width : this.wrapper.getWidth();
		y = (this.options.height != null) ? this.options.height : this.wrapper.getHeight();
		this.wrapper.removeClassName("factory");
		if (this.inner.hasClassName("scrollable")) {
			this.inner.removeClassName("scrollable");
		}
		if (max.width <= x) {
			x = (max.width - 20);
			this.inner.addClassName("scrollable");
			this.iefix.ie67_overflowx(this,x)
		}
		if (max.height <= y) {
			y = (max.height - 20);
			this.inner.addClassName("scrollable");
			this.iefix.ie67_overflowy(this,y);
		}
		this.width = x + "px";
		this.height = y + "px";
		this.top = ((y/2)-os.top)*(-1) + "px";
		this.left = ((x/2)-os.left)*(-1) + "px";
	},
	/**
	 * iefixes object. This fixes some lack of standards support for ie without using browser sniffing. all methods in the object
	 * has a prefix which tells of the targeted ie version. Methods can therefore be removed when no longer needed.
	 */
	iefix : {
		ie6_selects : function(e) {
			var selfix = (e=="close") ? "visible" : "hidden";
			$$("#mainPadding select").each(function(s){
				s.setStyle({
					visibility: selfix
				});
			});
		},
		ie6_width : function(c){
			if (c.options.iefixClassName != null) {
				c.inner.addClassName(c.options.iefixClassName);
			}
		},
		ie67_overflowx : function (c,x) {
			var ft = $$("."+c.options.iefixClassName);
			if(ft.length==0) return;
			ft[0].setStyle({width:x+"px",overflow:"auto",position:"relative"});
		},
		ie67_overflowy : function (c,y) {
			var ft = $$("."+c.options.iefixClassName);
			if(ft.length==0) return;
			ft[0].setStyle({height:y+"px",overflow:"auto",position:"relative"});
		}
	},
	/**
	 * Cross browser flash fixes. Called initially to hide flash movies below the overlay, 
	 * and called again onclose to restore visibility.
	 */
	flashfix : function(e) {
		var fix = (e=="close") ? "visible" : "hidden";
		$$('#mainPadding .flashContent').each(function(b){
			b.setStyle({visibility:fix});
		});
	},
	/**
	 * Cross browser flash inside iframe fixes. Called initially to hide flash movies below the overlay, 
	 * and called again onclose to restore visibility. Have to use try an catch, since fetching properties
	 * from elements inside a html document which belongs to another domain is prohibited.
	 */
	flashiframefix: function(e){
		var fix = (e=="close") ? "block" : "none";
		var len = 0;
		var objects = null;
		var useScriptTag = false;
		
			//which belongs to another domain.
			$$('iframe').each(function(b){
				if(b.contentDocument){//FF or IE8
					try{
						var eArray = $A(b.contentDocument.getElementsByTagName('embed'));
					}
					catch(err){
						//alert(err.description);
					}
				}
				else{ //IE
					try{
						var eArray = $A(b.contentWindow.document.getElementsByTagName('embed'));
					}
					catch(err){
						//alert(err.description);
					}
					//IE are not able to read JS generated embed tags, get script tag instead if no
					//embed tag was found.
					if(typeof(eArray) != "undefined" && eArray != null){
						if(eArray.size() == 0){
							try{
								eArray = $A(b.contentWindow.document.getElementsByTagName('script'));
							}
							catch(err){
								//alert(err.description);
							}
							useScriptTag = true;
						}
					}
				}
				if(typeof(eArray) != "undefined" && eArray != null){
					if(!useScriptTag){
						eArray.each(function(item){
						 	item.style.display = fix;
						 	
						});
					}
					else{
						eArray.each(function(item){
							//Check if the script is used for flash or other embedded objects
							if(item.innerHTML.toLowerCase().indexOf('flash') > - 1 || item.innerHTML.toLowerCase().indexOf('embed') > -1){
								b.contentWindow.document.getElementsByTagName('body').item(0).style.display = fix;
							}
						});
					}
				}
			
			});
	}
}

/**
 * Make links with rel="modal" open in ModalWindow instead of default action. 
 * This is made by adding querystring M and appending the modal configuation needed.
 * 
 * @param {HTMLElement} el	the link element
 */
function openAsModal(el,href) {					
	var eType = null;
	var targetURL = null;
	if (typeof href == 'undefined') {
		var eType = (el.nodeName == "A") ? "href" : "action";
		if (el.getAttribute(eType)) {
			// The event fired on a link element
			targetURL = el.getAttribute(eType);
		}
		else {
			// Try to get the parent element instead, nested tags
			// inside a link-tag can catch an onclick as well.
			var parent = el.up(el.nodeName.toLowerCase());
			if (parent != undefined && parent.getAttribute(eType)) {
				el = parent;
				targetURL = parent.getAttribute(eType);
			}
		}
	}
	else {
		targetURL = href;
		eType = (!$(href)) ? 'href' : 'inline';
	}
	
	if (targetURL != null) {
		if(targetURL.indexOf('/cmsintegration')<0){
			targetURL='/cmsintegration/ajaxproxy.php?url='+targetURL;	
		}
		// Add m parameter (rendermode) to link URL	
		if(eType=="action") {
			// el.submit is for catching a selfmade event, onsubmit handles the "normal" submit.
			// OBS! el.submit first, and then el.onsubmit, else it fails in Explorer
			/*el.submit = */el.onsubmit = function() {
				
				targetURL = addQueryStringParam(targetURL, "m", "modal");
				var options = getModalOptions(targetURL, el);
				if (typeof options.beforeLaunch == "function") options.beforeLaunch();
				ModalWindow.onload = options.onload;
				ModalWindow.onunload = options.onunload;
				ModalWindow.evalResponse = options.evalResponse;
				var valid = FormValidation.checkForm(el);
				var ok = (typeof options.onsubmit == "function") ? options.onsubmit() : true;
				var lol = "";
				if(!valid) {
					ModalWindow.reposition();
				}
				if (ok && valid) {
					ModalWindow.sendForm(targetURL, el, options.params);
				}
				return false;
			}
		}else if(eType=='href'){
			el.onclick = function() {
				targetURL = addQueryStringParam(targetURL, "m", "modal");
				var options = getModalOptions(targetURL, el);
				if (typeof options.beforeLaunch == "function") options.beforeLaunch();
				ModalWindow.onload = options.onload;
				ModalWindow.onunload = options.onunload;
				ModalWindow.evalResponse = options.evalResponse;
				ModalWindow.open(options.params);
				return false;
			}
		}else if(eType=='inline'){
			el.onclick = function(){
				var options = getModalOptions(targetURL, el);
				if (typeof options.beforeLaunch == "function") options.beforeLaunch();
				ModalWindow.onload = options.onload;
				ModalWindow.onunload = options.onunload;
				ModalWindow.evalResponse = options.evalResponse;
				
				ModalWindow.inner.innerHTML = "";
				ModalWindow.importInline(options.params);
			}
		}
	}
}

/* *** News lists functions *** */

/**
 * NewsList object, shared by "Senaste Nytt" and "Mest lästa" services. Enhance news lists by toggle functionality.
 */
var NewsList = {
	NEWSLIST_CONTAINER_CLASS : "newsListContainer",
	NEWSLIST_NAVIGATION_TAGNAME : "li",
	NEWSLIST_NAVIGATION_SELECTED_CLASSNAME : "selected",
	NEWSLIST_NAVIGATION_DESELECTED_CLASSNAME : "",	
	/**
	 * Search the page for instances of NewsLists and return boolean as answer.
	 */
	exists : function() {
		return Settings.scope.select("."+this.NEWSLIST_CONTAINER_CLASS).length > 0;
	},
	/**
	 * Init method. 
	 * Prepares newslists interaction schemes for readersList and LatestNews.
	 * LatestNews also gets handmade toggle functionality.
	 * 
	 */
	init : function() {
		var lns = Settings.scope.select("div.latestNewsContainer", "div.readerListContainer");
		for(var x=0; x<lns.length; x++) {
			var wrap = lns[x];
			var titles = wrap.select(".newsNavigation a");
			var cnts = wrap.select(".newsListContainer");
			for(var i=0; i<titles.length; i++) {
				if(cnts[i]) {
					cnts[i].style.display = (i>0) ? "none" : "block";
					cnts[i].id = "newList_"+(Math.round( Math.random()*1000 ));
					this.registerShowNewsList(titles[i], wrap, cnts[i], i);
				}
			}
			if (wrap.hasClassName("latestNewsContainer")) {
				var tl = wrap.select(".entire_list");
				for (var i = 0; i < tl.length; i++) {
					this.registertoggleLongList(tl[i],wrap);
				}
			}
		}
	},
	/**
	 * registers to help newslists to keep scope. 
	 * 
	 * @param {HTMLElement} elem	the element to toggle visible
	 * @param {HTMLElement} wrap	the wrapper reference
	 */
	registertoggleLongList : function(elem,wrap) {
		var c = this;
		elem.onclick = function(){ return c.toggleLongList(this, wrap); }
	},
	/**
	 * registers to help newslists to keep scope. 
	 * 
	 * @param {HTMLElement} elem	the element to toggle visible
	 * @param {String} containerId	
	 * @param {String} newsListId
	 * @param {Integer} navPosition
	 */
	registerShowNewsList : function(elem, containerId, newsListId, navPosition) {
		var c = this;
		elem.onclick = function(){ return c.showNewsList(elem, containerId, newsListId, navPosition); }
	},
	/**
	 *  Shows the selected newslist.
	 * This method does two things:
	 * 1. Iterates the newslist containers and shows 
	 *    the one asked for, and hides the others.
	 * 2. Iterates the navigation elements and 
	 *    changes their classes. This is to mark the
	 *    button selected.
	 *  
	 */
	showNewsList : function(elem, containerDiv, selectedNewsList, navPosition) {
		// Get list of containers and show the one asked for, hide the rest
		var lists = containerDiv.getElementsByTagName("div");
		for (var i = 0; i < lists.length; i++) {
			var tempDiv = lists[i];
			if(tempDiv.style) {
				// Only affect elements with the required classname
				if(tempDiv.className == this.NEWSLIST_CONTAINER_CLASS) {
					if(tempDiv.id == selectedNewsList.id) {
						tempDiv.style.display = "block";
					}else{
						tempDiv.style.display = "none";
					}
				}
			}
		}
		// Iterate all nav-elements and set their classNames
		var liList = containerDiv.getElementsByTagName(this.NEWSLIST_NAVIGATION_TAGNAME);
		for (var i = 0; i < liList.length; i++) {
			var li = liList[i];
			if(i == navPosition) {
				li.className = this.NEWSLIST_NAVIGATION_SELECTED_CLASSNAME;
			}else{
				li.className = this.NEWSLIST_NAVIGATION_DESELECTED_CLASSNAME;
			}
		}
		return false;
	},
	/**
	 * Toggles the newslist between short or long list.
	 * 
	 * @param {HTMLElement} elem	the element to toggle children in
	 * @param {HTMLElement} wrap	the wrapper
	 */ 
	toggleLongList : function(elem,wrap) {
		var cats = wrap.getElementsByTagName('dl');
		for(var j=0; j<cats.length ; j++ ) {
			var news = cats[j].getElementsByTagName('dt');
			for(var i=0; i<news.length ;i++) {
				if(news[i].className == 'visibleAfterToggle') {
					news[i].className = 'hiddenAfterToggle';
					var next = news[i].nextSibling;
					if(next.nodeName!='DD') next = next.nextSibling;
					next.className = 'hiddenAfterToggle';
				} else if(news[i].className == 'hiddenAfterToggle') {
					news[i].className = 'visibleAfterToggle';
					var next = news[i].nextSibling;
					if(next.nodeName!='DD') next = next.nextSibling;
					next.className = 'visibleAfterToggle';
				}
			}
		}
		var tl = getElementsByClassName('entire_list',"a",wrap);
		for(var i=0;i<tl.length;i++) {
			var elem = tl[i];
			if(elem.className == 'entire_list visibleAfterToggle') {
					elem.className = 'entire_list hiddenAfterToggle';
				} else {
					elem.className = 'entire_list visibleAfterToggle';
				}
		}
		return false;
	}
}

/**
 * Invoke method. Search the page for NewsList instances and activate the JS enhancement if found.
 */
function prepareNewsLists() {
	if(NewsList.exists()) {
		NewsList.init();
	}
}

/* *** Site Settings *** */

/**
 * Tool to allocate disabled features by site-specific JS. 
 * 
 * @type Object
 */
var Settings = {
	/**
	 * Contains List of disabled features for current page.
	 * 
	 * @type {Array} Arry set by sitejs
	 * @fieldOf Settings
	 */
	disabled : [],
	scope : null,
	/**
	 * invoke method: fetches the disabledFeatures array from site-specific JS 
	 * 
	 * @type void
	 * @returns void
	 * @methodOf Settings
	 */
	init : function(scope) {
		this.scope = scope;
		this.disabled = (typeof disabledFeatures == "undefined") ? [] : disabledFeatures;
	},
	/**
	 * Checks if a functionality is enabled or disabled. Returns bool.
	 * 
	 * @returns {Boolean} is the quested feature enabled?
	 * @param {String} name	The keyword to the service
	 * @type Boolean
	 */
	isEnabled : function(name) {
		return this.disabled.toString().indexOf(name) < 0;
	}
}

/* *** Toggler *** */

var Toggler = {
	classnames : {
		hidden : 'visibleAfterToggle',
		visible : 'hiddenAfterToggle',
		expanded : 'expanded',
		toggable : 'fieldset.toggable',
		dnt : 'open'
	},
	defaults : {
		extendedSearch : false
	},
	labels : {
		show : "Visa",
		hide : "Göm"
	},
	toggler : null,
	hide : function(element) {
		element.addClassName( this.classnames.hidden );
		element.removeClassName( this.classnames.visible );
		ModalWindow.reposition();
	},
	show : function(element) {
		element.addClassName( this.classnames.visible );
		element.removeClassName( this.classnames.hidden );
		ModalWindow.reposition();
	},
	toggle : function(elem) {
		var element = Element.extend(elem);
		var k = element.hasClassName(this.classnames.hidden);
		var l = element.hasClassName(this.classnames.visible);
		if(!k && !l) {
			element.addClassName(this.classnames.hidden);
		}
		if(k) {
			element.removeClassName(this.classnames.hidden);
			element.addClassName(this.classnames.visible);
		}
		if(l) {
			element.removeClassName(this.classnames.visible);
			element.addClassName(this.classnames.hidden);
		}
		ModalWindow.reposition();
	},
	childrenByParentId : function(objId) {
		var parent = document.getElementById(objId);
		if(parent)
			toggleMyChildren(parent);
		ModalWindow.reposition();
	},
	children : function(parent) {
		var c = this;
		var x = parent.select("."+this.classnames.hidden);
		var y = parent.select("."+this.classnames.visible);
		x.each(function(elm){
			c.show(elm);
		});
		y.each(function(elm){
			c.hide(elm);
		});
		ModalWindow.reposition();
	},
	restore : function(elem) {
		elem.removeClassName(this.classnames.hidden);
		elem.removeClassName(this.classnames.visible);
		ModalWindow.reposition();
	},
	ToggableContent : {
		instance : null,
		instance2 : null,
		labels :  {
			toggler : [".toggleTerms",".toggleContent"],
			content : [".toggableTerms",".toggableContent"],
			hide : "a.hide"
		},
		exists : function() {
			this.instance = Settings.scope.select(this.labels.toggler[0]).concat(Settings.scope.select(this.labels.toggler[1]));
			if(this.instance.length > 0) {
				for (var i = 0, max = this.instance.length; i < max; i++) {
					
					var t = this.instance[i].next(this.labels.content[ (this.instance[i].hasClassName(this.labels.toggler[0]) ? this.labels.content[0] : this.labels.content[1] ) ]);
					
					if (t == null) {
						var wrp = this.instance[i].up();
						
						t = wrp.select(this.labels.content[0]).concat(wrp.select(this.labels.content[1]));
					}
					
					
					
					if (t.length == 0) {
						var wrp = wrp.up();
						t = wrp.select(this.labels.content[0]).concat(wrp.select(this.labels.content[1]));
					}
					
					if(t.length == 0) return false;
				}
				return true;
			}
			return false;
		},
		init : function() {
			for (var i = 0, max = this.instance.length; i < max; i++) {
				var toggler = this.instance[i];
				var cls = (toggler.hasClassName(this.labels.toggler[0].substr(1))) ? 0 : 1; 
				var taa = toggler.up(2).select(this.labels.content[cls])[0];
				taa.addClassName(Toggler.classnames.hidden);
				this.registerToggle(toggler,taa);
				var c = this;
				taa.select(this.labels.hide).each(function(item){
					c.registerToggle(item,taa);
				});
			}
		},
		registerToggle : function(toggler,taa) {
			Event.observe(toggler,'click',function(e) {
				Toggler.toggle(taa);
				ModalWindow.reposition();
				e.preventDefault();
			});
		}
	},
	ToggableFieldset : {
		instance : null,
		labels : {
			toggable : 'fieldset.toggable',
			dnt : 'open'
		},
		exists : function() {
			return Settings.scope.select(this.labels.toggable).length > 0;
		},
		fieldset : function(fldset) {
			if( fldset.hasClassName(Toggler.classnames.expanded) ) return;
			var l = fldset.select('legend');
			if( l.length == 0 ) return;
			var c = this;
			fldset.select("*").each(function(item){
				Toggler.hide(item);
			});
			var item = l[0];
			item.cleanWhitespace();
			var text = /*c.labels.show + " " + */item.firstChild.nodeValue;
			var nl = new Element('a',{href:"#"}).update(text);
			Toggler.restore(item);
			nl.onclick = function() {
				var nlt = c.fold(this,fldset);
				return false;
			}
			Element.remove(item.firstChild)
			item.appendChild(nl);
			item.appendChild( new Element('span',{'class':'togglerIcon'}) );
		},
		createToggler  :function() {
			if(this.toggler == null) this.toggler = new Element('a', { 'class':"JS_toggler" , href:"#"}).update(this.labels.show);
			return this.toggler;
		},
		fold : function(toggler,wrapper) {
			var c = this;
			if(wrapper.hasClassName( Toggler.classnames.expanded )) {
				wrapper.removeClassName(Toggler.classnames.expanded);
				Toggler.children(wrapper);
				return Toggler.labels.show;
			}else{
				wrapper.addClassName(Toggler.classnames.expanded);
				Toggler.children(wrapper);
				return Toggler.labels.hide;
			}
			ModalWindow.reposition();
		},
		init : function() {
			var c = this;
			Settings.scope.select(this.labels.toggable).each(function(item){
				if(!item.hasClassName(c.labels.dnt)) {
					c.fieldset(item);
				}
			});
		}
	}
}

function prepareTogglers() {
	if(Toggler.ToggableFieldset.exists()) {
		Toggler.ToggableFieldset.init();
	}
	if(Toggler.ToggableContent.exists()) {
		Toggler.ToggableContent.init();
	}
}

var mktAjax = {
	load: function(url, wrapper, funcObj){
		new Ajax.Request(CacheUtil.noCache(url), {
			method: 'get',
			parameters: '',
			onException: function(response){
				if (typeof funcObjOnException == "function") {
					funcObj.OnException(response);
				}
			},
			onFailure: function(response){
				if (typeof funcObj.OnFailure == "function") {
					funcObj.OnFailure(response);
				}
			},
			onSuccess: function(response){
				wrapper.innerHTML = response.responseText;
				if (typeof funcObj.OnSuccess == "function") {
					funcObj.OnSuccess(response);
				}
				var scr = response.responseText.extractScripts();
				scr.each(function(s){
					eval(s);
				});
				if (wrapper.id != 'modalWindowInner' || (wrapper.id == 'modalWindowInner' && !ModalWindow.overlay.getStyle('display') == 'none')) {
					init(wrapper);
				}
			}
		});
	},
	send: function(url, wrapper, form, funcObj){
		var c = this;
		var pb = this.genPostBody(form);
		new Ajax.Request(CacheUtil.noCache(url), {
			postBody: pb,
			onException: function(response){
				if (typeof funcObjOnException == "function") {
					funcObj.OnException(response);
				}
			},
			onFailure: function(response){
				if (typeof funcObj.OnFailure == "function") {
					funcObj.OnFailure(response);
				}
			},
			onSuccess: function(response){
				wrapper.innerHTML = response.responseText;
				if (typeof funcObj.OnSuccess == "function") {
					funcObj.OnSuccess(response);
				}
				var scr = response.responseText.extractScripts();
				scr.each(function(s){
					eval(s);
				});
				if (wrapper.id != 'modalWindowInner' || (wrapper.id == 'modalWindowInner' && !ModalWindow.overlay.getStyle('display') == 'none')) {
					init(wrapper);
				}
			}
		});
	},
	genPostBody: function(form){
		var postBody = "";
		var ins = form.select('input', 'textarea','select');
		for (var i = 0, max = ins.length; i < max; i++) {
			var inpt = ins[i];
			var name = inpt.name + '=';
			var value = encodeURIComponent(inpt.value) + '&';
			
			if (inpt.type == "checkbox" || inpt.type == "radio") {
				if (!inpt.checked) {
					value = "";
					name = "";
				}
			}
			postBody += name;
			postBody += value;
			
		}
		return postBody;
	}
}

/* =========================== / 1.2 Objects ================================================ */
 
/***************************** 2. SERVICES *********************************************/ 
 
/* *** Image captions *** */

/**
 * Image Caption object. Progressive enhancement to captions by hiding the 
 * text body in a semitransparent div in the bottom of the image, and trig it by rollover.
 * Fallback to simply showing the caption directly after the image.
 */
var ImageCaption = {
	scope : null,
	cn : 'div.imageCaption',
	exists : function() {
		this.instances = Settings.scope.select(this.cn);
		return this.instances.length > 0;
	},
	init : function(modal) {
		var c = this;
		this.instances.each( function(item) {
			item.up().style.position = "relative";
			item.up().style.width = "100%";
			item.style.visibility = "hidden";
			// append rollover button
			var rob = document.createElement("div");
			rob.className = "imageCaptionIcon";
			rob.style.visibility = "visible";
			// append events
			Event.observe(item.up(),'mouseover', function(){ c.showImageCaption(item,rob); }, false);
			Event.observe(item.up(),'mouseout', function(){ c.showImageCaption(item,rob); }, false);
			item.up().insert(rob,'after');
		})
		// switch styles
		enableJSStyles( this.instances );
	},
	/**
	 * Toggles the image caption. The icon and the imagecaption is never viewed at the same time.
	 * @param {HTMLElement} imageCaption	the imageCaption element.
	 * @param {HTMLElement} icon	the icon element.
	 */
	showImageCaption : function(imageCaption,icon) {
		imageCaption.style.visibility = (imageCaption.style.visibility == "hidden") ? "visible" : "hidden";
		icon.style.visibility = (icon.style.visibility == "visible") ? "hidden" : "visible";
	}
}

/**
 * Init method. If any Image Captions exists on page, the image caption's JS viewmode is trigged.
 * An icon to indicate image caption is appended to wrapper.
 * JS viewmode: hidden and triggered by notice icon onmouseover.
 * NoJS viewmode: small sized text below image. Fallback when JS is not available.
 */
function prepareImageCaptions() {
	if(!Settings.isEnabled('ImageCaption')) return;
	
	if (ImageCaption.exists()) {
		ImageCaption.init();
	}
}

/* *** Left nav *** */

function prepareLeftNav() {
	if(LeftNav.exists() && Settings.isEnabled('LeftNav')) {
		LeftNav.init();
	}
}

var LeftNav = {
	currentAnimation : null,
	animation : {
		from : 0,
		to : 0.7,
		duration : 0.5,
		currentWait : 1000,
		curtainDuration : {
			main: 1,
			current : 1.5
		}
	},
	labels : {
		selected : 'selected',
		id : 'leftNavWrapper',
		section : {
			main : 'leftNav',
			current : 'currentSection',
			subcurrent : '#Kommunvis li ul'
		},
		jsgen : 'eyecandy',
		item : 'li.item a'
	},
	refs : {
		main : null,
		current : null
	},
	exists : function() {
		return ($(this.labels.id));
	},
	init : function() {
		enableJSStyles([$(this.labels.id)]);
		this.refs.main = $(this.labels.section.main);
		this.refs.current = $(this.labels.section.current) || null;
		if (this.refs.current != null) {
			this.prepareCurrentSection();
		}
		this.prepareMainHovers();
	},
	prepareCurrentSection : function () {
		var c = this;
		var subcur = this.refs.current.select(this.labels.subcurrent);
		if (subcur.length > 0) {
			var cur = subcur[0].wrap('div');
			cur.hide();
			setTimeout(function(){
				new Effect.SlideDown(cur, {
					duration:c.animation.curtainDuration.current
				});
			}, this.animation.currentWait);
		}
		else {
			var cur = this.refs.current.wrap('div');
			cur.hide();
			setTimeout(function(){
				new Effect.SlideDown(cur, {
					duration:c.animation.curtainDuration.main
				}); 
			}, this.animation.currentWait);
		}
	},
	prepareMainHovers : function () {
		var c = this;
		var mainItems = this.refs.main.select(this.labels.item);
		for(var i=0,max=mainItems.length; i<max; i++) {
			var item = mainItems[i];
			if (this.isSelected(item) == false) {
				var l = item.childElements()[0];
				var ecl = new Element('span').update(l.innerHTML);
				var ec = ecl.wrap(new Element('div').addClassName(this.labels.jsgen).setStyle({
					opacity:0,visibility:'hidden'
				}));
				item.insert({
					'top': ec
				});
				var eyec = item.childElements()[0];
				
				Event.observe(l, 'mouseover', function(e){
					var ec = this.previous();
					if (ec != null && ec.className == 'eyecandy') {
						c.hilightMain(ec);
					}
				});
				
				Event.observe(eyec, 'mouseout', function(e){
					//var ec = this;
					if (ec.className == 'eyecandy') {
						c.restoreMain(this);
					}
				});
			}
		}
	},
	isSelected : function(elm) {
		return elm.up().hasClassName(this.labels.selected);
	},
	hilightMain : function (elm) {
		if (this.isSelected(elm.up(1)) == false) {
			var c = this;
			elm.setStyle( {visibility:'visible',opacity:0});
			new Effect.Opacity(elm, {
				from: c.animation.from,
				to: c.animation.to,
				duration: c.animation.duration
			});
		}
	},
	restoreMain: function(elm){
		if (this.isSelected(elm.up(1)) == false) {
			var c = this;
			new Effect.Opacity(elm, {
				from: c.animation.to,
				to: c.animation.from,
				duration: c.animation.duration,
				afterFinish: function(){
					elm.setStyle({
						visibility: 'hidden'
					});
				}
			});
		}
	}
}

/*********************************************************************************
 * Article Toolbar
 * 
 * @service t02.01
 */

var ArticleToolbar = {
	articleZoomLevel : [100,120,130,140,150],
	exists : function() {
		this.instance = Settings.scope.select(".textSizerContainer");
		return this.instance.length > 0;
	},
	init : function() {
		this.restoreArticleZoom();
		var wr = this.instance;
		for (var j = 0, max = wr.length; j < max; j++) {
			var l = wr[j].select("a");
			for (var i = 0; i < l.length; i++) {
				this.registerSetArticleZoom(l[i], i);
			}
			
			Event.observe(wr[j].up().select('span.print a')[0],'click',function(e){
				/**** 1.3 *******
				var src = e.element().href;
				var x = (screen.availWidth - 640) / 2;
				window.open(src,'printArticle',"address=no,resizable=yes,scrollbars=yes,height=640,location=no,left="+x+",top=50,width=640");
				*****/
				/**** 1.2 *****/ window.print();
				e.preventDefault();
			});
		}
	},
	/**
	 * register function to help keep scope and closure.
	 * @param {HTMLElement} elem	the setter link element
	 * @param {Integer} lev	the level index.
	 */
	registerSetArticleZoom : function(elem,lev) {
		var c = this;
		elem.onclick = function(){
			c.setArticleZoom(lev);
			return false;
		}
	},
	/**
	 * Sets the new Article Zoom level.
	 * @param {Integer} level	the new zoom level
	 */
	setArticleZoom : function(level) {	
		new Element.setContentZoom('articleContent', this.articleZoomLevel[level]);
	
		Cookie.erase('zoomLevel');
		Cookie.setC('zoomLevel', level);
	
		var currentElement;
	
		// activate/inactivate buttons
		for (var i=0; this.articleZoomLevel.length > i; i++)
		{
			var f = getElementsByClassName ('textSize' + (i+1)); 
			
			if (!f[0])
				var f = getElementsByClassName ('textSize' + (i+1) + " selected");
			
			for (var j=0; f.length > j; j++)
			{
				currentElement = f[j];
			
				if (level == i)
					currentElement.className = "textSize" + (i+1) + " selected";
				else
					currentElement.className = "textSize" + (i+1);
			}
		}
	},
	/**
	 * Init method. Fetch stored Article Zoom from Cookie.
	 */
	restoreArticleZoom : function(){
		var myLevel = parseInt(Cookie.getC('zoomLevel'));
		
		if (myLevel > -1)
			this.setArticleZoom (myLevel);
	}
}

/**
 * invoke method. Add onclick event on all Article Zoom setters.
 */
function prepareArticleToolbar() {
	if(ArticleToolbar.exists()) {
		ArticleToolbar.init();
	}
}

/* *** External contents *** */

/**
 * Shared object to handle and progressively enhance external contents within IFrames.
 * 
 */
var ExternalContent = {
	slcts : ".externalContent > iframe",
	wrappers : null,
	/**
	 * init method to trig and hook on JS enhancements.
	 */
	init : function() {
		this.resize();
		Event.observe(window,'resize',function(){
			ExternalContent.resize();
		});
	},
	/**
	 * resize all chosed IFrames to the height of the viewport. Is called by init() and on RESIZE event.
	 */
	resize : function() {
		for(var i=0, max=this.wrappers.length; i<max; i++) {
			var ifrm = this.wrappers[i];
			var isFixed = (ifrm.up('.externalContent').hasClassName('fixed')) ? true : false;
			if (!isFixed) {
				this.setSize(ifrm);
			}
		}
	},
	/**
	 * Updates the height of an iFrame if the iFrames's height is lower than the available viewport height.
	 * @param {Element} ifrm	the iframe Element ref.
	 */
	setSize : function(ifrm) {
		var y; // the height to be calculated in pixels.
		var max = 0; // max value if SDP.
		
		// is there any (min-)HEIGHT set on iframe?
		var heightSet = !(isNaN(parseInt(ifrm.height))) || !(isNaN(parseInt(ifrm.getStyle('height'))));
		
		// is part of the iframe visible? NOT USED RIGHT NOW
		//isPartlyVisible = (posTop-vscroll) < vp && (posTop-vscroll) >= 0;
		
		// has the page scrolled down?
		var vscroll = document.viewport.getScrollOffsets().top;
		
		// where is the iframe positioned?
		var posTop = ifrm.cumulativeOffset().top;
		
		// how much viewport does we have?
		var vp = document.viewport.getHeight();
		
		// if the iframe follows SDP, calculate a max-height.
		try{
			var doc = (ifrm.contentWindow.document) ? ifrm.contentWindow.document : ifrm.contentDocument;
			max = doc.getElementsByTagName('body').offsetHeight;
		}catch(e){
			// let's hope this iframe is not published in the extra column, cuz it's gonna get high ...
		}
		
		// default value: the same height as the  viewpot
		y = vp;
		
		// if HEIGHT is set and the calculated height is less than HEIGHT,
		// let the HEIGHT become min-height!
		if(heightSet && y <= ifrm.height) {
			y = !(isNaN(parseInt(ifrm.height))) ? ifrm.height : parseInt(ifrm.getStyle('height'));
		}
		
		// if max is set, reduce height if to high.
		if(max > 0 && y > max) {
			y = max;
		}
		
		ifrm.setStyle({height:y+'px'});
	},
	/**
	 * Called by the invoke method to see if there are any external contents on the page.
	 */
	exists : function() {
		this.wrappers = Settings.scope.select(this.slcts);
		return this.wrappers.length > 0;
	}
}

/**
 * invoke method to check for external contents instances. If there are any, the JS enhancements are activated.
 */
function prepareExternalContent(){
	if(ExternalContent.exists()) {
		ExternalContent.init();
	}
}

/** ======= T02.12 | T06.12 =======
 * Blog @ mktwebb 1.2
 * 
 * $Rev: 4570 $
 * $Date: 2008-10-21 16:46:49 +0200 (Tue, 21 Oct 2008) $
 * $Author: andersy $
 */
var Blog = {
	instance : null,
	cn : {
		wrap : 'blog'
	},
	exists : function() {
		this.instance = $(Blog.cn.wrap);
		return this.instance;
	},
	ManageEntry : {
		cn : {
			tagsep : ", ",
			wrap : 'manageBlogEntry',
			tagcloud : 'tagCloud',
			tagfld : 'taTags',
			tag : 'span',
			me : '#extraForm > fieldset > legend',
			txtbody : 'taBlogBody',
			ewi : "div#extraForm input",
			preview : "#blog blockquote.preview"
		},
		youtube : function(url){
			return '<object width="425" height="344"><param name="movie" value="'+ url +'"></param><embed src="'+ url +'" type="application/x-shockwave-flash" width="425" height="344"></embed></object>'
		},
		img : function(imgSize,imgJustify,imgUrl) {
			return "\n\n!(" + imgSize + " " + imgJustify + ")" + imgUrl + "!\n\n";
		},
		exists : function() {
			return Blog.instance.hasClassName(this.cn.wrap);
		},
		init : function () {
			this.clickableTaggs();
			this.modalExtras();
			this.preview();
		},
		preview : function() {
			var btn = Settings.scope.select('#blog .btnPreview');
			var wrp = Settings.scope.select(this.cn.preview);
			var ta = Settings.scope.select('textarea.'+this.cn.txtbody)[0];
			var bq = new Element("blockquote",{'class':'preview inactive'}).update("");
			var bqp = new Element("div",{'class':'preview richText'}).update("");
			var bqts = new Element("div",{'class':'toolstrip'}).update("");
			var bqpb = new Element("input",{'class':'btnPreview','type':'button'});
			bqpb.value = "Förhandsgranska";
			var bqtsA = new Element("input",{'class':'btnClose',type:"button"});
			bqtsA.value = "Stäng";
			bqts.insert({bottom:bqtsA});
			bq.insert({bottom:bqts});
			bq.insert({bottom:bqp});
			ta.insert({after:bqpb});
			ta.insert({after:bq});
			var c = this;
				Event.observe(bqpb,'click',function(e){
					bqp.innerHTML = superTextile(ta.value);
					bq.removeClassName('inactive');
					bqpb.addClassName("inactive");
				});
				Event.observe(bqtsA,'click',function(e){
					bq.addClassName('inactive');
					bqpb.removeClassName("inactive");
				});
				Event.observe(ta,'keyup',function(e){
					if(!bq.hasClassName('inactive')) {
						bqp.innerHTML = superTextile(ta.value);
					}
				});
		},
		clickableTaggs : function () {
			var tc = $(this.cn.tagcloud);
			var fld = $(this.cn.tagfld);
			if(!tc || !fld) return;
			
			tc.select(this.cn.tag).each(function(item){
				var ne = new Element('a',{'class':item.className,'href':'#'}).update(item.innerHTML);
				tc.insert(ne);
				tc.insert(' ');
				item.remove();
			});
			var c = this;
						
			Event.observe(tc,'click',function(e){
				var ne = e.element();
				if(ne.nodeName != 'A') return;
				var tag = ne.innerHTML;
				var exists = fld.value.indexOf(tag);
				if(exists >= 0){
					var str = tag+c.cn.tagsep;
					fld.value = fld.value.replace(str,"");
					fld.value = fld.value.replace(tag,"");
				}else{
					var str = (fld.value.length==0) ? tag : c.cn.tagsep+tag;
					fld.value += str;
				}
				if (fld.value.substr((fld.value.length - 2), 2) == c.cn.tagsep) {
					fld.value = fld.value.substr(0, (fld.value.length - 2));
				}
				e.preventDefault();
			});
		},
		modalExtras : function () {
			var txtbody = $(this.cn.txtbody);
			if(!txtbody) return;
			Settings.scope.select(this.cn.me).each(function(item){
				if (!txtbody.previous('button.'+item.up().id) && item.up().id!="blogFormExtras_image") {
					var btn = new Element('button', {
						type: 'button',
						'class': item.up().id
					}).update(item.innerHTML);
					openAsModal(btn, btn.className);
					txtbody.insert({
						before: btn
					});
				}
			});
			// temporary fix
			$('blogEntryForm').insert($('blogFormExtras_image'));
			// end temporary fix
		},
		prepareLinkDialog : function() {
			var wrp = $('modalWindowWrapper');
			var btn = wrp.select('form')[0];
			var c = this;
			btn.onsubmit = null;
			Event.observe(btn,'submit',function(e){
					var ta = $(c.cn.txtbody);
					var inpt = wrp.select('input[type=text]');
					var insrt = '"' + inpt[1].value + '":' + inpt[0].value;
					Form.updateTextArea(ta, insrt);
					ModalWindow.close();
					ta.focus();
				Event.stop(e);
			});
		},
		prepareMovieDialog : function() {
			var wrp = $('modalWindowWrapper');
			var btn = wrp.select('form')[0];
			var c = this;
			btn.onsubmit = null;
			Event.observe(btn,'submit',function(e){
					var ta = $(c.cn.txtbody);
					var inpt = wrp.select('input[type=text]')[0];
					var url = c.youtube(inpt.value);
					Form.updateTextArea(ta, url);
					ModalWindow.close();
					ta.focus();
				Event.stop(e);
			});
		},
		prepareImageDialog : function() {
			var wrp = $('modalWindowWrapper');
			var btn = wrp.select('form')[0];
			var c = this;
			var elms = $('blogEntryForm').elements;
			for(var i=0,max=elms.length; i<max; i++) {
				var elm = elms[i];
				if (!elm.up('fieldset') || elm.up('fieldset').id != 'blogFormExtras_image') {
					if(typeof elm.name !="undefined" || elm.name == null || elm.name=="") {
					btn.insert(new Element('input', {
						'name': elm.name,
						'value': elm.value,
						'type': 'hidden'
					}));
					}
				}
			}
			Form.iframe.init(btn, c.getUploadedPicture);
		},
		getUploadedPicture : function() {
			if (parent.frames[Form.iframe.id]) {
				var tat = $(Blog.ManageEntry.cn.txtbody);
				var p = parent.frames[Form.iframe.id].document;
				var taz = p.getElementsByTagName('textarea');
				var newValue = "";
				for (var i = 0, max = taz.length; i < max; i++) {
					var ta = taz[i];
					if (ta.className == 'taBlogBody') {
						newValue = ta.value;
						break;
					}
				}
				tat.value = newValue;
				parent.frames[Form.iframe.id].location.href = '';
				ModalWindow.onload = null;
				ModalWindow.inner.innerHTML = '';
				ModalWindow.close();
				tat.focus();
			}
		}
	}
}

function prepareBlog() {
	if (Blog.exists()) {
		if (Blog.ManageEntry.exists()) {
			Blog.ManageEntry.init();
		}
	}
}
/** ===/Blog=== **/


/**
 * Locates all links with customized rel-attributes
 * and makes them open up as modal windows or in new windows.
 */
function initLinkExtensions() {
	// Get all links with a rel attribute
	var relLinks = Settings.scope.select('a[rel]');
	
	// Iterate found links and set behaviour	
	relLinks.each(function(link) {
		var relValue = link.getAttribute('rel');
		// Set different behaviour depending on value
		switch(relValue) {

			case "external":
				link.observe('click', openExternalLink, false);
				break;
			
			case "modal":
				if (Settings.isEnabled('ModalWindow') && Settings.scope.id != 'modalWindowWrapper') {
					openAsModal(link);
				}
				break;
		}
	});
}

/* *** Day in pictures *** */

/**
 * Day in pictures, a modified version of the general image gallery service.
 */
var ImageGallery = {
	selectors : {
		wrapper : ".dip_container",
		pictures : ".dip_nrOfRows a",
		placeholder : ".dip_placeholder",
		collapseLink : ".dip_placeholder a"
	},
	labels : {
		dayId : "bigPic_"
	},
	wrapper : null,
	pictures : [],
	placeholder : [],
	current : [],
	/**
	 * Check if any Days in Pictures services is on the current page. Called by the invoke method.
	 */
	exists : function() {
		this.wrapper = Settings.scope.select(this.selectors.wrapper);
		return this.wrapper.length > 0;
	},
	/**
	 * Starts the Days in pictures service by adding some event listeners and toggles.
	 */
	init : function() {
		var c = this;
		var id = 0;
		this.wrapper.each(function(wrap) {
			c.pictures.push(wrap.select(c.selectors.pictures));
		
			var phw = wrap.select(c.selectors.placeholder)[0];
			var ph = phw.select("img")[0];
			
			if (!ph) {
					phi = new Element('img', {
						src: '',
						alt: ''
					});
					phw.insert(phi);
				}
			
			for(var i=0,max=c.pictures[id].length; i<max; i++){
				var item = c.pictures[id][i];
				item.onclick = function() {
					return c.show(this,wrap);
				}
			}
			var clps = wrap.select(c.selectors.collapseLink);
			if (clps.length == 0) {
				return;
			}
			else {
				clps[0].onclick = function(){
					return c.hide(wrap);
				}
			}
			id++;
		});
	},
	/**
	 * reload placeholder with image.
	 * @param {Element} elem	the image wrapper to show.
	 */
	show : function(elem,wrap) {
		var phw = wrap.select(this.selectors.placeholder)[0];
		var ph = phw.select("img")[0];
		ph.src = elem.href;
		if (phw.hasClassName("collapsed")) {
			phw.toggleClassName("collapsed");
		}
		if(Settings.scope.id == 'modalWindowWrapper') {
			ModalWindow.reposition();
		}
		return false;
	},
	/**
	 * reset placeholder by removing the current image.
	 * @param {Element} elem	the image to remove.
	 */
	hide : function(wrap) {
		wrap.select(this.selectors.placeholder)[0].addClassName("collapsed");
		return false;
	}
}

/**
 * Invoke method: check if any Image Gallery instances is on the page, and initiate if true.
 */
function prepareImageGallery() {
	if(!Settings.isEnabled('ImageGallery')) return;
	
	if(ImageGallery.exists()) {
		ImageGallery.init();
	}
}

function initPrint() {
	if($$('body.print').length > 0) {
		window.print();
	}
}

/* *** ticker *** */

/**
 * Initiates and starts the ticker.
 * interval parameters sets the update time in milliseconds.
 * 
 * Letters : the time between printing of a single line's characters.
 * Lines : how long a printed line will be saved before switching.
 */
var Ticker = {
	// update interval
	interval : { letters:50, lines:3000 },
	// pointers
	pos : 0,
	current : 0,
	// overflow handler (scrolls the line to the left if line is too long -> wider than maxwidth)
	maxwidth : 0,
	// containers
	elems : [],
	chars : [],
	max : [],
	/**
	 * Initiates and prepare the ticker to get started.To start ticker, call this.start.
	 * 
	 * @param {Array} elems	an array of elements, like $$('#ticker dd a')
	 */ 
	init : function(elems) {
		for(var i=0; i<elems.length; i++) {
			this.chars[i] = elems[i].innerHTML.strip().toArray();
			this.max[i] = this.chars[i].length;
			this.elems[i] = elems[i];
			this.elems[i].update("");
		}
		this.maxwidth = this.elems[0].up(1).getWidth() - this.elems[0].up().previous().getWidth();
		this.elems[0].up().addClassName("active");
	},
	/**
	 * print characters in line (i.e. the headline). Also triggers the next line when done. interval.letters defines the speed.
	 * 
	 */ 
	printChars : function() {
		if(this.max[this.current] > this.pos) {
			if (this.elems[this.current].movement) {
				clearTimeout(this.elems[this.current].movement)
			}
			this.elems[this.current].update( this.elems[this.current].innerHTML + this.chars[this.current][this.pos] )
			this.pos++;
			var overflow = this.maxwidth - (this.elems[this.current].getWidth()+10);
			if( overflow < 0 ) this.elems[this.current].style.marginLeft = (overflow-5)+"px";
			var closure = this;
			this.elems[this.current].movement = setTimeout( function(){ closure.printChars(); }, closure.interval.letters );
		}else {
			var closure = this;
			this.pos = 0;
			this.movement = setTimeout( function(){closure.nextLine()}, closure.interval.lines )
			return true;
		}
	},
	/**
	 * restore printed line to default values. Called before the next line starts.
	 * 
	 * @param {HTMLElement} elem	the element which should be restored.
	 */
	cleanup : function (elem) {
		elem.up().removeClassName("active");
		elem.style.marginLeft = "0";
		elem.update("");
	},
	/**
	 * switch lines. When the last line is printed, the whole set is rewinded to first line. 
	 */
	nextLine : function() {
		if (this.current >= this.elems.length) {
			return true;
		}
		this.cleanup(this.elems[this.current]);
		var next;
		if(this.current < (this.elems.length-1)) {
			next = this.current+1;
			this.current++;
		}else{
			next = this.current = 0;
		}
		this.elems[next].up().addClassName("active");
		this.printChars();
	},
	/**
	 * starts the ticker by printing the first line.
	 */
	start : function() {
		this.pos = 0;
		this.printChars();
	}
}

/**
 * Init method. Search the page for ticker instance.If ticker is found, init and start it. Aborts and return if otherwise. 
 * JSDependent service.
 */
function initTicker() {
	var elem = Settings.scope.select("#ticker dd a");
	if(elem.length == 0) return false;
	Ticker.init( elem );
	Ticker.start();
}

/* *** Image Slideshow functions *** */

/**
 * Collects all images in Slideshow and obtain event handlers for the pager.
 */
var ImageSlideshow = {
	rewert : "#viewImageSlideshow_rewert a",
	forward : "#viewImageSlideshow_forward a",
	/**
	 * Init method. Append the first image to document.
	 * @param {HTMLElement} elem
	 */
	init : function () {
		Settings.scope.select(this.rewert)[0].onclick = Settings.scope.select(this.forward)[0].onclick = function(){
			return ModalWindow.reload(this.href);
		};
	}
}

/************************************************************
 * CrowdPictures, by andersy @ T04.15
 * 
 * Light-version: only opens facebook in popup. 
 */
var CrowdPictures = {
	instance : null,
	sels : {
		wrp : 'div.crowdPictures',
		fb : 'li.facebook a'
	},
	exists : function(){
		this.instance = Settings.scope.select(this.sels.wrp);
		return this.instance.length > 0; 
	},
	// init method
	init : function(){
		if(!this.exists()) return;
		this.shareLinks();
	},
	// give facebook sharelinks a popup target
	shareLinks : function(){
		Settings.scope.select(this.sels.fb).each(function(elm){
			Event.observe(elm,'click',function(e){
				window.open(e.element().href,'shareFacebook',"location=no,resizable=yes,scrollbars=yes,height=500,location=no,left=50,top=50,width=800");
				e.preventDefault();
			});
		});
	}
}/** ===/CrowdPictures=== **/

/**
 * Interactive form widget which calculate and tell strength on password inputs.
 * 
 * @param {HTMLElement} formField
 * @param {String} passwordMeterElementId
 */
function measurePasswordStrength(formField, passwordMeterElementId) {
	var meter = document.getElementById(passwordMeterElementId);
	if(formField && meter) {
		var strength = Form.getPasswordStrength(formField.value);
		meter.className = "percentage" + strength;
	}
}

/* *** Event calendar *** */

/**
 * Initiates and prepares the Event Calendar with toggle functions. The description of each event is
 * toggled. One can toggle all descriptions at the same time, or each one manually. 
 */
var EventCalendar = {
	rowsFinder : "#eventCalendarList-hits tr.vevent",
	rowToggle : "td.eventLocation",
	pToggle : "parentToggle",
	eventCont : "eventCalendarList-hits",
	expanded : "expanded",
	selregion : "select#eventCity",
	rows : 0,
	/**
	 * initiates the rows which should be toggle handled and set their visibility.
	 * Also creates the toggle buttons and append them to document.
	 */
	exists : function() {
		return Settings.scope.select('#eventCalendar').length > 0;
	},
	init : function() {
		this.initEventToggler();
		this.initRegionChanger();
	},
	initEventToggler : function() {
		this.rows = Settings.scope.select( this.rowsFinder	 );
		if(this.rows.length == 0) return;
		for(var i=0; i<this.rows.length; i++) {
			var e = this.rows[i];
			var btn = document.createElement("a");
			btn.href = "#";
			btn.className = "toggle";
			e.select( this.rowToggle )[0].insert({ top:btn });
			this.registerToggleECDesc(e);
			e.next().addClassName(Toggler.classnames.hidden);
		}
		var pt = $( this.pToggle );
		pt.addClassName("expand");
		var closure = this;
		pt.onclick = function() {
			closure.toggleAll(this);
			return false;
		}
	},
	initRegionChanger: function() {
		var selectRegion = Settings.scope.select(this.selregion)[0];
		if (selectRegion) {
			var c = this;
			// Add event click event
			selectRegion.onchange = function(){
				c.changeRegion(this);
			}
			
			// Check if there is a value selected
			var selectedParent = $('eventCity').value;
			if (selectedParent != "undefined") {
				this.changeRegion(selectRegion);
			}
		}
	},
	/**
	 * register function to keep scope and closure.
	 * @param {HTMLElement} e	the toggle button element
	 */
	registerToggleECDesc : function(e) {
		var closure = this;
		e.select("a.toggle")[0].onclick = function() {
			closure.toggleECDesc(e.next());
			e.toggleClassName( closure.expanded );
			return false;
		}
	},
	/**
	 * Toggles the description of events. 
	 * @param {HTMLElement} e	the toggle button element
	 */
	toggleECDesc : function(e) {
		var cl = [Toggler.classnames.hidden,Toggler.classnames.visible];
		if(e.hasClassName(cl[1])) {
			e.removeClassName(cl[1]);
			e.addClassName(cl[0]);
		}else{
			e.removeClassName(cl[0]);
			e.addClassName(cl[1]);
		}
		ModalWindow.reposition();
	},
	/**
	 * Global toggle function. Make all elements which can be toggled visible or hidden.
	 * @param {Object} e	the parent element; the classname defines the action.
	 */
	toggleAll : function(e) {
		var ct = (e.hasClassName("expand")) ? Toggler.classnames.visible : Toggler.classnames.hidden;
		var cf = (e.hasClassName("expand")) ? Toggler.classnames.hidden : Toggler.classnames.visible;
		for(var i=0; i<this.rows.length; i++) {
			if (ct == "hiddenAfterToggle") {
				this.rows[i].addClassName(this.expanded);
			} else {
				this.rows[i].removeClassName(this.expanded);
			}
			this.rows[i].next().addClassName(ct);
			this.rows[i].next().removeClassName(cf);
		}
		e.className = (ct == Toggler.classnames.visible) ? "collapse" : "expand" ;
		ModalWindow.reposition();
	},
	changeRegion : function (selectElement){
		var selectCity = Settings.scope.select("select#eventNeighbourhood")[0];
		selectCity.disabled = false;
		selectCity.length = 0;
		var a = new Array();
		var b = new Array();
		var selectedValue = selectElement.options[selectElement.selectedIndex].value;
		if(selectedValue != ""){
			selectCity.enable();
			if(cityArray.length > 0){
				for(var i = 0; i < cityArray.length; i++){
					a = cityArray[i].split(",");
					if(a.length > 0){
						b = a[0].split(":");
						
						if(b.length > 0 && selectedValue == b[0]){
							var index = selectCity.length;
							// If first, add empty option
							if(index == 0) {
								selectCity.options[index++] = new Option("--V\u00E4lj ort--", "");
							}
							
							// Add new option, select if value is identical
							selectCity.options[index] = new Option(a[1], b[1]);
							if(selectedCityId != "" && selectedCityId == b[1]){
								selectCity.selectedIndex = index;
							}
						}
					}
				}
			}
		}
		
		if(selectCity.length <= 1) {
			selectCity.disable();
		}
	}
}

/**
 * Init method. Search the page for a EventCalendar instance, and initiates the calendar if instance exists. Return if null. 
 */
function prepareEventCalendar() {
	if(!Settings.isEnabled('EventCalendar')) return;
	
	if (EventCalendar.exists()) {
		EventCalendar.init();
	}
}

function preparePoll() {

	if(Poll.exists()) {
		Poll.init();
	}
}



/**
 *	@author Fredrik Herlitz, Promedia, Nerikes Allehanda
 *	
 *	Handle polls. They have to have a <form>-element inside an element with class ".pollContainer"
 */

var Poll = {
	labels :  {
		pollForms : '.pollContainer form',
		submitOnSelect : 'input[type="hidden"][name="submitOnSelect"]',
		noOptionSelectedText : 'input[type="hidden"][name="noOptionSelectedText"]',
		submitLinkID : 'input[type="hidden"][name="submitLinkID"]',
		radios : 'input[type="radio"]'
	},
    init : function () {
		var c = this;
		Settings.scope.select(this.labels.pollForms).each(function(theForm) {
				
			var submitOnSelect;
			var noOptionSelectedText;
			
			c.replaceBtnWithLink(theForm);
			
			try
			{
				submitOnSelect = theForm.select(Poll.labels.submitOnSelect)[0].value;
				noOptionSelectedText = theForm.select(Poll.labels.noOptionSelectedText)[0].value;
			}
			
			catch(e){}
			
			if (submitOnSelect == 'true') {
			
				try
				{
					var arrRadios = theForm.select(Poll.labels.radios);
			
					arrRadios.each(function(item) {
					
						item.onclick = function() {	
							theForm.onsubmit();
						}
					})
				}
				
				catch(e){}
			}	
			else {
			
				try
				{
					var submitLinkID = theForm.select(Poll.labels.submitLinkID)[0].value;
				
					$(submitLinkID).onclick = function(evt) { 
						if (Poll.checkChecked(theForm, noOptionSelectedText)){ 
							theForm.onsubmit();
							return false;
						}else{
							return false;
						}
					}
				}
				
				catch(e){}
			}
			
		});
	},
	checkChecked : function (theForm, noOptionSelectedText) {
		var optionSelected = false;
		var arrRadios = theForm.select(this.labels.radios);
		
		for (i = 0; i < arrRadios.length; i++) {
	        if (arrRadios[i].checked) {
				optionSelected = true;
				break;
	        }
	     }
		 
	     if (!optionSelected) {
	         alert(noOptionSelectedText);
	         return false;
	     }
		 return true;
	},
	exists : function() {
		return Settings.scope.select(this.labels.pollForms).length > 0;
	},
	replaceBtnWithLink : function(frmElm){
		var btn = frmElm.select("input.btnSubmit");
		if (btn.length > 0) {
			var lnk = new Element('a', {
				'id': ((frmElm.id.replace("pollForm_", "")) + "_submit"),
				'href': ""
			}).update(btn[0].value);
			btn[0].insert({
				after: lnk
			});
			btn[0].remove();
		}
	}
}

/* *** My photos *** */

/**
 * MyPhotos, "Läsarnas bilder". Enhance forms and search results listing.
 */
var MyPhotos = {
	wrapId : { 
		search:"myPhotoSearch", 
		upload1:"newMyPhotoContainer", 
		upload1Form:"newMyPhoto", 
		confirm:"newMyPhotoConfirmation"
	},
	agreement : "#newMyPhotoContainer .agreement",
	/**
	 * Init the view Image service. Is called when the ModalWindow instance is loaded.
	 */
	initViewer : function() {
		enableEnhancements();
		prepareImageCaptions();
	},
	/**
	 * Makes the whole resultrow clickable instead of just the image thumbnail.
	 */
	initSearch : function() {
		Settings.scope.select("#" + this.wrapId.search + " ol.images > li").each( function(item){
			item.addClassName("clickable");
			Event.observe( item, 'click', function(){item.select("a")[0].onclick();},false);
		})
	},
	/**
	 * Disables the submit button and don't enable it until the user has agreed to the terms and conditions (checking a checkbox).
	 */
	initUploadForm : function() {
		var sbmt = Settings.scope.select("#" +MyPhotos.wrapId.upload1 + " input[type=submit]")[0];
		sbmt.disabled = true;
		closure = this;
		var agreed = Settings.scope.select("#" +MyPhotos.wrapId.upload1 + " .chkAgreement")[0];
		this.checkDisabled(agreed,sbmt);
		agreed.onchange = function() {
			closure.checkDisabled(agreed,sbmt);
		}
	},
	/**
	 * function to enable or disable the terms and conditions checkbox
	 * @param {Element} agreed	the terms and conditions checkbox reference
	 * @param {Element} sbmt	the submit button reference
	 */
	checkDisabled : function(agreed,sbmt) {
		if(agreed.checked) {
			sbmt.disabled = false;
		}else{
			sbmt.disabled = true;
		}
	}
}

/**
 * Invoke method. Prepare various JS to myPhoto service.
 */
function prepareMyPhotos(){
	if (!Settings.isEnabled('MyPhotos')) return;

	if ( Settings.scope.select('#'+MyPhotos.wrapId.search).length > 0 ) {
		MyPhotos.initSearch();
	}
	if (Settings.scope.select('#'+MyPhotos.wrapId.upload1).length > 0 ) {
		MyPhotos.initUploadForm();
	}
}

/** ======= T06.15 =======
 * Chat @ mktwebb 1.2
 * 
 */
var Chat = {
	cn : {
		wrap : '.chatWrapper'
	},
	frms : {
		q : "listQuestions",
		a : "chatEditor"
	},
	exists : function () {
		return Settings.scope.select(this.cn.wrap).length > 0;
	},
	// moderator window. add cancel actions to the answer <textarea>.
	Moderator : {
		cn : {
			lnk : 'chatSubmitEntryEditorForm',
			frm : 'chatSubmitAnswerEditorForm',
			bck : 'hiddenURLforBackwardNavigation'
		},
		exists : function(){
			var frm = $(this.cn.frm);
			return frm;
		},
		init : function(){
			var frm = $(this.cn.frm);
			var lnk = $(this.cn.lnk);
			if (frm && lnk) {
				var bck = getUrlParam(this.cn.bck);
				Event.observe(Settings.scope.select("input[name=Cancel]")[0], 'click', function() {
					Settings.scope.select('textarea').each(function(ta){
						ta.value="";
					})
				});
			}
		}
	},
	// chat manager focus the answer <textarea> field and 
	// add close functionality to the app window's close buttons.
	ManageChat : {
		cn : {
			wrp : 'chatSubmitQuestionForm',
			cls : 'input.btnClose'
		},
		exists : function() {
			return $(this.cn.wrp); 
		},
		init : function() {
			Settings.scope.select('textarea')[0].focus();
			Settings.scope.select(this.cn.cls).each(function(i){
				Event.observe(i,'click',function(){
					window.close();
				});
			});
		}
	},
	// app window. toggles the class names in the nav tabs.
	// also appends a periodical updater for the incomig questions
	App : {
		settings : {
			constr : "resizable=yes,height=400,left=50,top=50,width=500"
		},
		cn : {
			wrp : "chatAppWrapper",
			bclass : 'body.webapp',
			nav : 'level1',
			wapp : '#panelB #level1',
			sel : 'selected',
			qs : 'listQuestions'
		},
		intervals : {
			questions : 30,
			answers: {
				p: 10,
				d: 2
			},
			wait : 3
		},
		exists : function(){
			return Settings.scope.select(this.cn.wapp).length > 0;
		},
		init : function(){
			var c = this;
			Event.observe(Settings.scope.select(this.cn.wapp)[0],'click',function(e){
				var i = e.element();
				if(i.nodeName=='A' && !(i.up().hasClassName(c.cn.sel))) {
					this.select('li').each(function(item){
						item.toggleClassName(c.cn.sel);
					});
				}
			});
			var qs = parent.frames[this.cn.qs].document;
			if (qs) {
				new PeriodicalExecuter(function(){
					qs.location.reload();
				}, this.intervals.questions);
			}
		}
	},
	// opens the app window.
	JoinChat : {
		cn : {
			wrap : 'chatJoinForm'
		},
		exists : function() {
			return $(this.cn.wrap);
		},
		init : function() {
			var c = this;
			Event.observe($(this.cn.wrap),'submit',function(e){
				c.open( e.element().action );
				e.preventDefault();
			});
		},
		open : function(url) {
			window.open(url,'chatapp',Chat.App.settings.constr);
		}
	},
	Questions : {
		cn : {
			q : 'chatViewAnswersForm',
			a : 'chatSubmitAnswerEditorForm',
			aq : "listQuestionsOther",
			btn : 'btnDefault',
			confirm : "Du kan bara svara på en fråga i taget!",
			confirmE : "Du kan bara redigera en fråga åt gången!",
			ta : "textarea"
		},
		q : null,
		aq : null,
		exists : function() {
			this.q = $(this.cn.q);
			return this.q;
		},
		init : function() {
			var c = this;
			Event.observe(this.q, 'click', function(e){
				var btn = e.element();
				if (btn.value && btn.name == 'answer') {
					c.answer(btn);
				}
				if (btn.value && btn.name == 'reject') {
					c.drop(btn);
				}
				if (btn.value && btn.name == 'edit') {
					c.edit(btn);
				}
				if (btn.value && btn.name == 'approve') {
					c.approve(btn);
				}
			});
		},
		answer : function(btnPressed) {
			var answer = this.getFromFrame(Chat.frms.a,this.cn.a);
			var ta = answer.select( this.cn.ta )[0];
			var q = btnPressed.up().previous('h3').innerHTML;
			var aid = btnPressed.up(".message").id.replace("message_","");
			
			// no question set, abort
			if (ta.value.length > 0) {
				if (q != answer.select("h3")[0].innerHTML) {
					alert(this.cn.confirm);
				}
				ta.focus();
			}
			else {
				var answer = this.getFromFrame(Chat.frms.a, this.cn.a);
				answer.select("input#inReplyTo")[0].value = aid;
				answer.select("h3")[0].innerHTML = q;
				ta.focus();
				
				var c = this;
				Event.observe(answer, 'submit', function(){
					
					if (ta.value.length > 0) {
						c.refresh(0);
					}
				});
			}
		},
		edit : function(btnPressed) {
			var answer = this.getFromFrame(Chat.frms.a,this.cn.a);
			var ta = answer.select( this.cn.ta )[0];
			var q = btnPressed.up().previous('h3').innerHTML;
				
			if (ta.value.length > 0) {
				if (q != answer.select("h3")[0].innerHTML) {
					alert(this.cn.confirmE);
				}
				ta.focus();
			}
			else {
				
				ta.value = btnPressed.up().previous('h3').lastChild.nodeValue.strip();
				ta.focus();
				
				var c = this;
			}
		},
		drop : function(btnPressed) {
			var q = btnPressed.up('div.message');
			
			/**
			 * @todo här behövs ett ajaxanrop till backend för att markera en fråga som godkänd.
			 */
			
			this.refresh(1);
			q.remove();
		},
		approve : function(btnPressed) {
			var q = btnPressed.up('div.message');
			
			/**
			 * @todo här behövs ett ajaxanrop till backend för att markera en fråga som avfärdad.
			 */
			
			this.refresh(0);
			q.remove();
		},
		refresh : function(item) {
			var prnt = this.getFromParent(Chat.App.cn.nav);
			var cnt = prnt.select("span")[item];
			cnt.innerHTML = "(" + (parseInt(cnt.innerHTML.substr(1)) + 1) + ")";		
			var cntp = cnt.up('li');
			var c = this;
			if (cntp.hasClassName(Chat.App.cn.sel)) {
				setTimeout(function(){
					var aq = parent.frames[c.cn.aq].document;
					if (aq) {
						aq.location.reload();
					}
				}, (Chat.App.intervals.wait * 1000))
			}
		},
		// return document from <iframe>.
		getFromFrame : function(frame,wrapperElmId) {
			var awrap = parent.frames[frame].document;
			return Element.extend(awrap.getElementById(wrapperElmId));
		},
		// return parent to <iframe>.
		getFromParent : function(wrapperElmId) {
			var awrap = parent.document;
			return Element.extend(awrap.getElementById(wrapperElmId));
		}
	}
	/*LatestAnswers : {
		cn : {
			wrp : 'chatRead',
			lst : '.chatList'
		},
		exists : function() {
			var wrp = $(this.cn.wrp);
			if(!wrp) return false;
			return wrp.select(this.cn.lst).length > 0;
		},
		init: function(){
			var url = addQueryStringParam(location.href, 'm', 'modal');
			new Ajax.PeriodicalUpdater( $(this.cn.lst).up(), url, {
				method: 'get',
				frequency: Chat.App.intervals.answers.p,
				decay: Chat.App.intervals.answers.p
			});
		}
	}*/
}

function prepareChat() {
	if (Chat.exists()) {
		if (Chat.App.exists()) {
			Chat.App.init();
		}
		if (Chat.JoinChat.exists()) {
			Chat.JoinChat.init();
		}
		if (Chat.Questions.exists()) {
			Chat.Questions.init();
		}
		if (Chat.ManageChat.exists()) {
			Chat.ManageChat.init();
		}
		if (Chat.Moderator.exists()) {
			Chat.Moderator.init();
		}
		/*if (Chat.LatestAnswers.exists()) {
			Chat.LatestAnswers.init();
		}*/
	}
} 
/** ===/end T06.15 - Chat=== **/


/* *** MyPageUtil *** */

/**
 *	@author Pelle Andersson, Promedia, Nerikes Allehanda
 *	
 *	This object and its methods performs misc operation with
 *	form elements. Used when editing my page information.
 */
var MyPageUtil = {

	links: "select#links",
	url: "input#url",
	error: "div#error",
	defaultValue: "http://www",
	errorMax: "Max antal l\u00E4nkar har uppn\u00E5tts (" + FormValidation.MAX_COUNT + ")",
	errorUrl: "Var v\u00E4nlig ange en giltig url (ex. http://www.doman.se)!",
	errorEmpty: "Det finns inga l\u00E4nkar att ta bort f\u00F6r tillf\u00E4llet!",
	errorSelect: "Var god markera vilken/vilka l\u00E4nkar som skall tas bort!",
	defaultLinkText: "Inga l\u00E4nkar",
	/**
	 *	Adds a link written in a input element to
	 *	a select multiple box. 
	 */
	addLink: function() {
		var linksElement = Settings.scope.select(this.links)[0];
		var formUrlElement = Settings.scope.select(this.url)[0];
		FormValidation.hideAllErrorMessages("", true);
		if(linksElement.length >= FormValidation.MAX_COUNT){
			FormValidation.showErrorMessage(formUrlElement.id, this.errorMax, false);
			FormValidation.showErrorMessage(FormValidation.errorDiv, FormValidation.ERROR_HEADER.replace("count", "1"), true);
			formUrlElement.value = this.defaultValue;
			formUrlElement.focus();
			return;
		}
		else if (! FormValidation.isUrl(formUrlElement.value)){
			FormValidation.showErrorMessage(formUrlElement.id, this.errorUrl, false);
			FormValidation.showErrorMessage(FormValidation.errorDiv, FormValidation.ERROR_HEADER.replace("count", "1"), true);
			formUrlElement.value = this.defaultValue;
			formUrlElement.focus();
			return;
			
		}
		else{
			this.addOption(formUrlElement.value, formUrlElement.value);
		}
	},
	/**
	 *	Adds a new option to the select multiple box.
	 *		@param optionText
	 *			The option text
	 *		@param optionValue
	 *			The option value
	 */
	addOption: function(optionText, optionValue){
		var linksElement = Settings.scope.select(this.links)[0];
		var linksElement = Settings.scope.select(this.links)[0];
		var index = linksElement.length;
		var formUrlElement = Settings.scope.select(this.url)[0];
		FormValidation.hideErrorMessage(formUrlElement.id, false);
		FormValidation.hideErrorMessage(FormValidation.errorDiv, true);
		var oOption = new Option(optionText,optionValue);
		linksElement.options[index] = oOption;
		formUrlElement.value = this.defaultValue;
		formUrlElement.focus();
		if(linksElement.length > 1)
			FormValidation.deleteDefaultValue(linksElement);
	},	
	/**
	 *	Removes all options form the select multiple box.
	 *
	 */
	removeAllLinks: function(){
		var linksElement = Settings.scope.select(this.links)[0];
		FormValidation.hideAllErrorMessages(linksElement.id, false);
		
		if(linksElement.length == 0){
			FormValidation.showErrorMessage(linksElement.id, this.errorEmpty, false);
			FormValidation.showErrorMessage(FormValidation.errorDiv, FormValidation.ERROR_HEADER.replace("count", "1"), true);
			return;
			
		}
		else{
			linksElement.length = 0;
			FormValidation.hideErrorMessage(linksElement.id, false);
			FormValidation.hideErrorMessage(FormValidation.errorDiv, true);
			this.addOption(this.defaultLinkText , "");
		}
	},
	/**
	 *	Removes the selected options in the multiple select box.
	 */
	removeSelectedLinks: function(){
		var linksElement = Settings.scope.select(this.links)[0];
		FormValidation.hideAllErrorMessages(linksElement.id, false);
		var selCount = 0;
		
		for (i = linksElement.length - 1; i>=0; i--) {
	    	if (linksElement.options[i].selected) {
	    		selCount++;
	      		linksElement.remove(i);
	   	 	}
  		}
  	
  		if(selCount == 0){
			FormValidation.showErrorMessage(linksElement.id, this.errorSelect, false);
			FormValidation.showErrorMessage(FormValidation.errorDiv, FormValidation.ERROR_HEADER.replace("count", "1"), true);
			return;
			
		}
		else{
			FormValidation.hideErrorMessage(linksElement.id, false);
			FormValidation.hideErrorMessage(FormValidation.errorDiv, true);
		}
		
		if(linksElement.length == 0)
			this.addOption(this.defaultLinkText, "");
	
	},
	prepareBtnARemoveSelectedLink : function(){
		Settings.scope.select("input#btnRemove").each(function(item){
			item.onclick = function(){
				MyPageUtil.removeSelectedLinks(this);
			}
		});
	},
	prepareBtnRemoveAllLinks : function(){
		Settings.scope.select("input#btnRemoveAll").each(function(item){
			item.onclick = function(){
				MyPageUtil.removeAllLinks();
			}
		});
	},
	prepareBtnAddLink : function(){
		Settings.scope.select("input#btnAdd").each(function(item){
			item.onclick = function(){
				MyPageUtil.addLink();
			}
		});
	}
}

/**
 * Invoke method. Inits MyPageUtil functions by hooking to several links.
 */
function prepareMyPageUtil() {
	if ( !Settings.isEnabled('MyPageUtil') ) return;
	
	MyPageUtil.prepareBtnARemoveSelectedLink();
	MyPageUtil.prepareBtnRemoveAllLinks();
	MyPageUtil.prepareBtnAddLink();
}

/* *** End MyPageUtil *** */

function prepareForumMyPage() {
//	var wrap = $('forum_mypage');
	var wrap = $('mainPadding');
	if (wrap) {
		var t = wrap.select('.showMoreMyPage a');
		if (t.length > 0) {
			var c = wrap.select('.contact_information')[0];
			if (!c.hasClassName(Toggler.classnames.hidden)) {
				c.addClassName(Toggler.classnames.hidden);
			}
			var a = wrap.select('.additional_information')[0];
			if (!a.hasClassName(Toggler.classnames.hidden)) {
				a.addClassName(Toggler.classnames.hidden);
			}
			t.each(function(item){
				Event.observe(item, 'click', function(e){
					Toggler.toggle(c);
					Toggler.toggle(a);
					Toggler.toggle(item);
					var siblings = item.up().childElements();
					if (siblings[0] == this) {
						Toggler.toggle(siblings[1]);
					}
					else {
						Toggler.toggle(siblings[0]);
					}
					ModalWindow.reposition();
					Event.stop(e);
				})
			});
		}
	}
}/* *** Top User Toolbar *** */

function initTopUserToolbar() {
	if (typeof topUserToolbarContentURL != 'undefined') {
		new Ajax.Updater('topUserToolbar', CacheUtil.noCache(topUserToolbarContentURL), {
			method: 'get',
			asynchronous:true
		});
	}
}

var UserForm = {
	scope : null,
	cn : {
		wrp : 'form.formComposed'
	},
	wrapper : null,
	exists : function() {
		this.wrapper = Settings.scope.select(this.cn.wrp);
		return this.wrapper.length > 0;
	},
	init : function() {
		if(Settings.scope.id == 'modalWindowInner') {
			Form.iframe.init(this.wrapper[0]);
		}
	}
}

function prepareUserForm() {
	if(UserForm.exists()){
		UserForm.init();
		return true;
	}
	return false;
}

/************************************************************
 * TVGuide, by Fleecelabs @ T10.11
 * 
 */
var TVGuide = {
  init: function() {
    if (this.exists()) this.install();
  },
  exists: function() {
    return this.findForm() != null;
  },
  install: function() {
    var form = this.findForm();
    Event.observe(form, 'submit', function(ev) {
      var checkboxes = ev.target.select('input[type=checkbox]');
      if (!checkboxes.any(function(cb) { return cb.checked; })) {
        $('errorTvGuideSettings')
          .update('<p>V\u00E4nligen v\u00E4lj minst en kanal!</p>')
          .addClassName('error')
          .removeClassName('errorHidden')
          .scrollTo();
        Event.stop(ev);
      }
    });
  },
  findForm: function() {
    var a = Settings.scope.select('.tvGuideSettings form');
    return a.length > 0 ? a.first() : null;
  }
}/** ===/TVGuide=== **/

 
/***************************** 3. DEPRECATED  / OBSOLETE *******************************/ 
 
/**
 * !!! These functions and objects is not recommended for production use any more. !!!
 */

/**
 * decode Email text body.
 * 
 * @param {String} coded
 */
function decodeEmail (coded)
{
	cipher = "aZbYcXdWeVfUgThSiRjQkPlOmNnMoLpKqJrIsHtGuFvEwDxCyBzA1234567890"
	shift=coded.length
	link=""
	for (i=0; i<coded.length; i++)
	{
		if (cipher.indexOf(coded.charAt(i))==-1)
		{
			ltr=coded.charAt(i)
			link+=(ltr)
		}
		else 
		{     
			ltr = (cipher.indexOf(coded.charAt(i))-shift+cipher.length) % cipher.length
			link+=(cipher.charAt(ltr))
		}				
    	
	}
	
	return link;
}

/**
 * Decodes and send email.
 * 
 * @param {String} coded
 */
function decodeAndMail (coded)
{
	document.location="mailto:" + decodeEmail(coded);
}

/**
 * Get custom date string from standard date.
 */
function getMyDateString ()
{
	var weekDays = new Array(7);
	weekDays[0] = "Söndag";
	weekDays[1] = "Måndag";
	weekDays[2] = "Tisdag";
	weekDays[3] = "Onsdag";
	weekDays[4] = "Torsdag";
	weekDays[5] = "Fredag";
	weekDays[6] = "Lördag";
	
	var months = new Array (12);
	months[0] = "januari";
	months[1] = "februari";	
	months[2] = "mars";
	months[3] = "april";
	months[4] = "maj";
	months[5] = "juni";
	months[6] = "juli";
	months[7] = "augusti";
	months[8] = "september";
	months[9] = "oktober";
	months[10] = "november";
	months[11] = "december";
	
	var myDate = new Date();
				
	var dateYear = myDate.getFullYear();
	var dateMonth = myDate.getMonth();
	var dateDay = myDate.getDay();
	var dateNum = myDate.getDate();
									
	var myDateString = weekDays[dateDay] + " " + dateNum + " " + months[dateMonth] + " " + dateYear;

	return myDateString;
}

/**
 * Simple function that toggles the visibility (by changing element
 * classnames) of the supplied element's children. All children with
 * the classnames 'hiddenAfterToggle' and 'visibleAfterToggle' simply
 * gets switched.
 *
 * @param parent
 * 			The parent container
 */
function toggleMyChildren(parent) {
	// Get all children that are to be toggled visible
	var hiddenChildren = getElementsByClassName("visibleAfterToggle", "*", parent);
	// Get all children that are to be toggled hidden
	var visibleChildren = getElementsByClassName("hiddenAfterToggle", "*", parent);
	
	// Iterate and toggle children to hidden
	for(var i=0; i < hiddenChildren.length; i++) {
		replaceClassName(hiddenChildren[i], "visibleAfterToggle", "hiddenAfterToggle");
	}

	// Iterate and toggle children to hidden
	for(var i=0; i < visibleChildren.length; i++) {
		replaceClassName(visibleChildren[i], "hiddenAfterToggle", "visibleAfterToggle");
	}
}


/**
 * Looks up the parent object by supplied id and
 * call toggleMyChildren(...) with that object as
 * it's parameter
 *
 * @param objId
 * 			The string Id of parent object
 */
function toggleChildrenByParentId(objId) {
	var parent = document.getElementById(objId);
	if(parent)
		toggleMyChildren(parent);
}

/**
 * Replaces a className for supplied element.
 *
 * Simply replaces a className with another.
 * If object does not implement the classname
 * to replace, nothing is added.
 * 
 * @param obj
 * 			The element to affect
 * @param oldClassName
 * 			The classname to replace
 * @param newClassName
 * 			The classname to replace with
 * 
 * @author EmilO
 */
function replaceClassName(obj, fromClassName, toClassName) {
	Element.extend(obj);
	if(obj.hasClassName(fromClassName)) {
		obj.removeClassName(fromClassName);
		obj.addClassName(toClassName);
	}
}

/**
 * Calls 'toggleMyChildren' with it's parent as parameter.
 *
 * @param element
 * 			The calling element
 * 
 * @author EmilO
 * 
 * TODO: Fix lookup of parent.
 * 
 * function toggleMySiblings(element) {
 * 	var parent = getElementParent(element);
 * 	toggleMyChildren(parent);
 * }
 */


/**
 * getElementsByClassName, by robertNyman.com
 * !!! Please consider using $$(".foo") instead!
 * 
 * @param {Object} className
 * @param {Object} tag
 * @param {Object} elm
 */ 
function getElementsByClassName(className, tag, elm){
	var testClass = new RegExp("(^|\\s)" + className + "(\\s|$)");
	var tag = tag || "*";
	var elm = elm || document;
	var elements = (tag == "*" && elm.all)? elm.all : elm.getElementsByTagName(tag);
	var returnElements = [];
	var current;
	var length = elements.length;
	for(var i=0; i<length; i++){
		current = elements[i];
		if(testClass.test(current.className)){
			returnElements.push(current);
		}	
	}
	return returnElements;
}

/**
 * Set properties of a iFrame by javascript.
 * PLEASE DO NOT USE THIS! USE HTML ATTRIBUTES INSTEAD!
 * 
 * @param {Element} iframe
 * @param {src} src
 * @param {int} width
 * @param {int} height
 * @param {boolean} scrolling
 */
function setIframeProperties(iframe, src, width, height, scrolling) {
	if(iframe) {
		iframe.setAttribute("src", src);
		iframe.setAttribute("width", width);
		iframe.setAttribute("height", height);
		iframe.setAttribute("frameBorder", "0");
		iframe.setAttribute("scrolling", scrolling);
	}
}

/**
 * Submits a form.
 * 
 * @param {HTMLElement} f	the form element
 */
function submitLoginForm(f) {
	// Just a basic check to avoid fake submits
	if(f.userId.value.length < 3 || f.userPassword.length < 3) {
		return false;
	}
	
	// Set the referer url before posting
	f.postReferer.value = document.location.href;
	
	return true;
}

//var advancedSearchMode = false;

/**
 * Enables and disables the advanced search mode on search forms.
 */
function toggleAdvancedSearch()
{
	if (advancedSearchMode)
	{
		$('searchAdvanced').className = "off";
		$('advancedForm').style.display='none';
	}
	else
	{
		$('searchAdvanced').className = "on";
		$('advancedForm').style.display='block';
	}

	advancedSearchMode = !advancedSearchMode;
}

