/***********************************************************************
*                         MyLittleJavaScript                           *
************************************************************************
* Created by Michael Loesler <http://derletztekick.com>                *
*                                                                      *
* This script is part of my little forum <http://mylittleforum.net>    *
*                                                                      *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 3 of the License, or    *
* (at your option) any later version.                                  *
*                                                                      *
* This program is distributed in the hope that it will be useful,      *
* but WITHOUT ANY WARRANTY; without even the implied warranty of       *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        *
* GNU General Public License for more details.                         *
*                                                                      *
* You should have received a copy of the GNU General Public License    *
* along with this program; if not, write to the                        *
* Free Software Foundation, Inc.,                                      *
* 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.            *
***********************************************************************/

/***********************************************************************
* NOTICE: In order to reduce bandwidth usage, a minimized version of   *
* this script is used by default (main.min.js). Changes in this file   *
* do not have any effect unless it is loaded by the template           *
* (themes/[THEME FOLDER]/main.tpl).                                    *
* The minimized version was created with the YUI Compressor            *
* <http://developer.yahoo.com/yui/compressor/>.                        *
***********************************************************************/

/**
 * Liefert die CSS-Eigenschaften eines Elements
 *
 * @param el
 * @param cssProp
 * @return cssValue
 */
document.getStyle = function(el,styleProp) {
	if (el.currentStyle)
		return el.currentStyle[styleProp];
	else if (window.getComputedStyle)
		return document.defaultView.getComputedStyle(el,null).getPropertyValue(styleProp);
	return false;
};

/**
 * Liefert eine Liste mit Elementen, die die
 * selbe CSS-Klasse haben
 *
 * @param class_name
 * @return node_list
 */
if(typeof document.getElementsByClassName != 'function') {  
 document.getElementsByClassName = function (class_name) {
  var all_obj,ret_obj=new Array(),j=0,teststr;
  if(this.all)
   all_obj=this.all;
  else if(this.getElementsByTagName && !this.all)
   all_obj=this.getElementsByTagName("*");
  var len=all_obj.length;
  for(var i=0;i<len;i++) {
   if(all_obj[i].className.indexOf(class_name)!=-1) {
    teststr=","+all_obj[i].className.split(" ").join(",")+",";
    if(teststr.indexOf(","+class_name+",")!=-1) {
     ret_obj[j]=all_obj[i];
     j++;
    }
   } 
  }
  return ret_obj;
 };
}

/**
 * Funktion zum Vorladen von Bildern
 * Sollte am Ende eines ONLOAD aufgerufen werden,
 * sodass das Bildladen das Script nicht blockiert
 *
 * @param images
 * @param path
 */
document.preloadImages = function(images, path) {
	if (typeof images != "object")
		images = [images];
	path = path || "";
	var img = [];
	for(var i = 0; i<images.length; i++) {
		img[i] = new Image();
		img[i].src = path + images[i];
	}
};

/**
 * Liefert das Element, auf dem das Event ausgeloest wurde
 * @return tar
 */
document.getTarget = function(e) {
	e = e || window.event;
	return e.target || e.srcElement || false;
};

/**
 * Prueft, ob ein Element in einem anderen
 * enthalten ist
 * @return conatinsElement
 * @see http://forum.de.selfhtml.org/archiv/2010/2/t195270/#m1306879
 */
if (window.Node && Node.prototype && !Node.prototype.contains) {
	Node.prototype.contains = function (arg) {
		try {
			return !!(this.compareDocumentPosition(arg) & 16);
		}
		catch(e) {
			return false;
		}
	};
}

/**
 * Erzeugt ein INPUT-Element mit zusaetzlichen Attributen
 * Attribute werden als einfaches Array uebergeben
 * [[key1, value1], [key2, value2], ...]
 * Optional kann das Elternelement angegeben werden,
 * um neues Element einzuhaengen
 * Funktion ist notwendig, da der IE (korrekterweise) 
 * das TYPE-Attribut bei diesen Elementen nicht setzt.
 *
 * @param tagName
 * @param att
 * @param par
 * @return el 
 * @see http://forum.de.selfhtml.org/archiv/2007/4/t151146/#m982711
 */
document.createInputElementWithAttributes = function(tagName, att, par) {
	if (tagName.toLowerCase() != "input" && tagName.toLowerCase() != "button") 
		return;

	var type = false;
	var el = false;
	for (var i=0; i<att.length; i++) {
		if (att[i][0].toLowerCase() == "type") {
			type = att[i][1];
			break;
		}
	}
	
	if (type) {
		try {
			el = document.createElement(tagName);
			el.type = type;
		}
		catch(err) {
			el = document.createElement('<'+tagName+' type="'+type+'">');
		}
	}
	el = el || document.createElement(tagName);

	for (var i=0; i<att.length; i++) {
		if (att[i][0].toLowerCase() != "type")
			el[att[i][0]] = att[i][1];
	}
	if (par)
		par.appendChild(el);
	return el;
};

/**
 * Erzeugt ein Element mit zusaetzlichen Attributen
 * Attribute werden als einfaches Array uebergeben
 * [[key1, value1], [key2, value2], ...]
 * Optional kann das Elternelement angegeben werden,
 * um neues Element einzuhaengen
 *
 * @param tagName
 * @param att
 * @param par
 * @return el 
 */
document.createElementWithAttributes = function(tagName, att, par) {
	if (tagName.toLowerCase() == "input" || tagName.toLowerCase() == "button") 
		return document.createInputElementWithAttributes(tagName, att, par);
	
	var el = document.createElement(tagName);
	for (var i=0; i<att.length; i++) 
		el[att[i][0]] = att[i][1];
	if (par) {
		par.appendChild(el);
	}
	return el;
};

/**
 * Liefert die Scroll-Position des aktuellen
 * Fensters
 * @return scrollPos
 * @see http://forum.de.selfhtml.org/archiv/2005/4/t106392/#m659379
 */
document.getScrollPosition = function() {
	var l = 0, t = 0;
	if( typeof window.pageYOffset == "number" ) {
		t = window.pageYOffset;
		l = window.pageXOffset;
	} 
	// else if( document.documentElement && typeof document.documentElement.scrollLeft == "number" && typeof document.documentElement.scrollTop  == "number" ) 
	else if (document.compatMode && document.compatMode == "CSS1Compat") {
		t = document.documentElement.scrollTop;
		l = document.documentElement.scrollLeft;
	} 
	else if( document.body && typeof document.body.scrollLeft == "number" && typeof document.body.scrollTop == "number" ) {
		t = document.body.scrollTop;
		l = document.body.scrollLeft;
	}
	return {
		left: l,
		top: t
	};
};

/**
 * Liefert die Groesse des Dokuments
 * @return docSize
 * @see http://forum.de.selfhtml.org/archiv/2009/1/t181640/
 */
document.getWindowSize = function() {
	var l, t, windowWidth, windowHeight;
	if (window.innerHeight && window.scrollMaxY) {
		l = document.body.scrollWidth;
		t = window.innerHeight + window.scrollMaxY;
	} 
	else if (document.body.scrollHeight > document.body.offsetHeight){
		l = document.body.scrollWidth;
		t = document.body.scrollHeight;
	} 
	else {
		l = document.getElementsByTagName("html").item(0).offsetWidth;
		t = document.getElementsByTagName("html").item(0).offsetHeight;
		l = (l < document.body.offsetWidth) ? document.body.offsetWidth : l;
		t = (t < document.body.offsetHeight) ? document.body.offsetHeight : t;
	}
	if (window.innerHeight) {
		windowWidth  = window.innerWidth;
		windowHeight = window.innerHeight;
	} 
	//else if (document.documentElement && document.documentElement.clientHeight) {
	else if (document.compatMode && document.compatMode == "CSS1Compat") {
		windowWidth  = document.documentElement.clientWidth;
		windowHeight = document.documentElement.clientHeight;
	} 
	else if (document.body) {
		windowWidth  = document.getElementsByTagName("html").item(0).clientWidth;
		windowHeight = document.getElementsByTagName("html").item(0).clientHeight;
		windowWidth  = (windowWidth == 0) ? document.body.clientWidth : windowWidth;
		windowHeight = (windowHeight == 0) ? document.body.clientHeight : windowHeight;
	}
	var pageHeight = (t < windowHeight) ? windowHeight : t;
	var pageWidth = (l < windowWidth) ? windowWidth : l;
	
	return {
		pageWidth: pageWidth,
		pageHeight: pageHeight,
		windowWidth: windowWidth,
		windowHeight: windowHeight
	};
};

/**
 * Liefert den zum Tastedruck gehoerenden Event-Key
 * return keyCode
 */
document.getKeyCode = function(ev) {
	ev = ev || window.event;
	if ((typeof ev.which == "undefined" || (typeof ev.which == "number" && ev.which == 0)) && typeof ev.keyCode  == "number")
		return ev.keyCode;
	else	
		return ev.which;
};

/**
 * Liefert die Position und Groesse eines Elements im Dokument
 * @param el
 * @return elPositionAndSize
 * @see http://www.quirksmode.org/js/findpos.html
 */
document.getElementPoSi = function(el){
    var r = { top:0, left:0, width:0, height:0 };
 
    if(!el || typeof(el) != 'object') 
		return r;
 
    if(typeof(el.offsetTop) != 'undefined')    {
         r.height = el.offsetHeight;
         r.width  = el.offsetWidth;
         r.left   = r.top = 0;
         while(el && el.tagName != 'BODY') {
            r.top  += parseInt( el.offsetTop );
            r.left += parseInt( el.offsetLeft );
			
            el = el.offsetParent;
         }
    }
    return r;
};

/**
 * Liefert das erste direkte Kindelement eines Elternknotens,
 * welches optionale eine bestimmte CSS-Klasse haben muss
 *
 * @param par
 * @param tagName
 * @param cssClasses
 * return el
 */
document.getFirstChildByElement = function(par, tagName, cssClasses) {
	if (cssClasses && typeof(cssClasses) != "object")
		cssClasses = [cssClasses];	
	if (par && par.hasChildNodes()) {
		var childNodeFromPar = par.firstChild;
		while (childNodeFromPar != null) {
			if (childNodeFromPar.nodeName.toLowerCase() == tagName) {
				if (!cssClasses)
					return childNodeFromPar;
				else {
					var teststr = ","+childNodeFromPar.className.split(" ").join(",")+",";
					for (var i=0; i<cssClasses.length; i++)
						if (teststr.indexOf(","+cssClasses[i]+",") != -1)
							return childNodeFromPar;
				}
			}
			childNodeFromPar = childNodeFromPar.nextSibling;
		}
	}
	return null;
};

/**
 * Liefert die Koordinaten 
 * des letzten Maus-Klicks
 * @param e
 * @return pos
 * @see http://forum.de.selfhtml.org/archiv/2006/1/t121722/#m782727
 */
document.getMousePos = function(e) {
	e =  e || window.event;
	var body = (window.document.compatMode && window.document.compatMode == "CSS1Compat") ? 
	window.document.documentElement : window.document.body;
	return {
		top: e.pageY ? e.pageY : e.clientY + body.scrollTop - body.clientTop,
		left: e.pageX ? e.pageX : e.clientX + body.scrollLeft  - body.clientLeft
	};
};

/**
 * Entfernt White-Spaces am Anfang und Ende eines Strings
 * (ist im FF schon drin, daher die Bedingung)
 */
if(typeof String.prototype.trim != "function") { 
	String.prototype.trim = function() {
		return this.replace(/^\s+|\s+$/g,"");
	};
}

/**
 * Liefert true, wenn der String mind. einen Zeilenumbruch enthaelt
 * @return lineBreak
 */
String.prototype.containsLineBreak = function() {
	var newLineRegExp = new RegExp(/(\n|\r|\r\n)./);
	return newLineRegExp.test(this);
}

/**
 * Entfernt Slashes in eimem String vgl. gleichnamige PHP-Funktion
 * @return str
 */
String.prototype.stripslashes = function() {
	var str = this;
	str=str.replace(/\\'/g,'\'');
	str=str.replace(/\\"/g,'"');
	str=str.replace(/\\0/g,'\0');
	str=str.replace(/\\\\/g,'\\');
	return str;
};

/**
 *
 * Author: Torben Brodt
 * Summary: Cross-browser wrapper for DOMContentLoaded
 * Updated: 07/09/2009
 * License: MIT / GPL
 * Version: 1.1
 *
 * URL:
 * @see http://www.easy-coding.de
 * @see http://jquery.com/dev/svn/trunk/jquery/MIT-LICENSE.txt
 * @see http://jquery.com/dev/svn/trunk/jquery/GPL-LICENSE.txt
 *
 * A page has loaded after all external resources like images have been loaded.
 * Should all scripts wait for that? a better bevaviour is to wait for the dom content being ready.
 *
 * This script has workarounds for all the big browsers meaning the major versions of firefox, internet explorer, opera, safari and chrome.
 * You can use it without risk, since the normal "onload" behavior is the fallback solution.
 *
 * Most of the source is lended from jquery
 */
var ready = new (function () {
	var readyBound = 0, d = document, w = window, t = this, x;
	t.isReady = 0;
	t.readyList = [];
 
	function bindReady() {
		if ( readyBound ) return;
		readyBound = 1;
 
		// Mozilla, Opera and webkit nightlies currently support this event
		if ( d.addEventListener ) {
			// Use the handy event callback
			x = "DOMContentLoaded";
			d.addEventListener( x, function(){
				d.removeEventListener( x, arguments.callee, false );
				ready.ready();
			}, false );
 
		// If IE event model is used
		} else if ( d.attachEvent ) {
			// ensure firing before onload,
			// maybe late but safe also for iframes
			x = "onreadystatechange";
			d.attachEvent(x, function(){
				if ( d.readyState === "complete" ) {
					d.detachEvent( x, arguments.callee );
					ready.ready();
				}
			});
 
			// If IE and not an iframe
			// continually check to see if the document is ready
			if ( d.documentElement.doScroll && w == w.top ) (function(){
				if ( t.isReady ) return;
 
				try {
					// If IE is used, use the trick by Diego Perini
					// [url]http://javascript.nwbox.com/IEContentLoaded/[/url]
					d.documentElement.doScroll("left");
				} catch( error ) {
					setTimeout( arguments.callee, 0 );
					return;
				}
 
				// and execute any waiting functions
				ready.ready();
			})();
		}
 
		// A fallback to window.onload, that will always work
		w.onload = ready.ready; // TODO: compliant? t.event.add( window, "load", t.ready );
	};
 
	// Handle when the DOM is ready
	t.ready = function() {
		// Make sure that the DOM is not already loaded
		if ( !t.isReady ) {
			// Remember that the DOM is ready
			t.isReady = 1;
 
			// If there are functions bound, to execute
			if ( t.readyList ) {
				// Execute all of them
				for(var i=0; i<t.readyList.length; i++) {
					t.readyList[i].call( w, t );
				};
 
				// Reset the list of functions
				t.readyList = null;
			}
 
			// Trigger any bound ready events
			d.loaded = true; // TODO: compliant? this(document).triggerHandler("ready");
		}
	};
 
	// adds funtion to readyList if not ready yet, otherwise call immediately
	t.push = function(fn) {
		// Attach the listeners
		bindReady();
 
		// If the DOM is already ready
		if ( t.isReady )
			// Execute the function immediately
			fn.call( w, t );
 
		// Otherwise, remember the function for later
		else
			// Add the function to the wait list
			t.readyList.push( fn );
 
		return t;
	};
})();	

/************************ MyLittleForum-Objekte *************************************/

	/**
	 *	Erzeugt einen Query als Schluessel-Wert-Paar
	 *	@param k
	 *	@param v
	 */
	function Query(k, v){
		v = v || "";
		var key = k.trim();
		var value = encodeURIComponent(v.toString().trim());
		
		this.toString = function(){
			return key + "=" + value + "&";
		};
	}	

	/**
	 * Erzeugt eine Anfrage und uebergibt die Antwort an eine Funktion
	 * als XML oder String
	 *
	 * @param uri
	 * @param m
	 * @param obj
	 * @param func
	 * @param resXML
	 * @param mimeType
	 *
	 */
	function Request(uri,m,q,obj,func,args,resXML,mimeType){
		args = args?(typeof args == "object"||typeof args == "function"?args:[args]):[];
		resXML  = resXML || false;
		mimeType = mimeType?mimeType:resXML?"text/xml":"text/plain";
		obj = obj || null;
		var httpRequest = false;
		try{
			if (window.XMLHttpRequest) 
				httpRequest = new XMLHttpRequest();
				if (httpRequest.overrideMimeType)
					httpRequest.overrideMimeType(mimeType);
			else if (window.ActiveXObject) {
				try {
					httpRequest = new ActiveXObject("Msxml2.XMLHTTP");
				} catch (e) {
					try {
						httpRequest = new ActiveXObject("Microsoft.XMLHTTP");
					} catch (er) {
						httpRequest = false;
					}
				}
			}
		}
		catch(err) {
			httpRequest = false;
		}	
		if (!httpRequest) {
			if (obj && typeof obj[func] == "function") 
				obj[func](false, args);
			return;
		}
		var qStr = "";	
		if (q instanceof Query)
			qStr = q.toString();
		else if((typeof q == "object"||typeof q == "function") && q.length > 0)
			for (var i=0; i<q.length; i++)
				qStr += q[i].toString();
		qStr +=	new Date().getTime();
		httpRequest.abort();
		httpRequest.onreadystatechange = function() {
			if (httpRequest.readyState == 4) { 
				if (obj && typeof obj[func] == "function") {
					obj[func]( (resXML?httpRequest.responseXML:httpRequest.responseText), args);				
				}
				httpRequest = false;
			}
		};
		if (m.toLowerCase() == "post"){
			httpRequest.open("POST", uri, true);
			httpRequest.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
			httpRequest.send( qStr );
		}
		else {
			httpRequest.open("GET", uri+"?"+qStr, true);
			httpRequest.send(null);
		}
	}
	
	/**
	 * Sidebar-Objekt
	 * @param templatePath
	 */
	function Sidebar(templatePath) {
		templatePath = templatePath || "";
		var main    = document.getElementById("sidebar") || document.getElementById("bottombar") || false;
		var content = document.getElementById("sidebarcontent");
		var icon    = document.getElementById("sidebartoggle");
		var self    = this;
		if (!main || !content || !icon)
			return;
			
		this.setVisible = function(enable) {
			if (enable) {
				content.style.display = "";
				icon.src = templatePath + settings["hide_sidebar_image"];
				icon.className = "hide-sidebar";
			}
			else {
				content.style.display = "none";
				icon.src = templatePath + settings["show_sidebar_image"];
				icon.className = "show-sidebar";
			}
		};
		
		this.isVisible = function() {
			return content.style.display != "none";
		};
		
		var links = main.getElementsByTagName("a");
		for (var i=0; i<links.length; i++) {
			if (links[i].href.search(/toggle_sidebar/) != -1) {
				links[i].onclick = function(e) {
					self.setVisible(!self.isVisible());
					new Request("index.php", "POST", new Query("toggle_sidebar", true));
					return false;
				}
			}
		}
	}
		
	/**
	 * Erzeugt aus einem UL oder dessen ID ein Thread-Objekt,
	 * welches zum Ein- und Ausklappen des Baums
	 * aufgerufen werden kann
	 * @param ul (UL-Element oder UL-ID)
	 * @param templatePath
	 */
	function Thread(ul, templatePath) {
		var tid = false;
		if (!isNaN( parseInt(ul) )) {
			tid = ul;
			ul = document.getElementById("thread-"+tid);
		}
		else {
			var tidRegExp = new RegExp(/thread-([0-9])+/);
			var q = tidRegExp.exec(ul.id);
			if (!q)
				return;
			tid = q&&q.length>1?q[1]:0;
		}
		var lis = ul.getElementsByTagName("li");
		var uls = ul.getElementsByTagName("ul");
		var self = this;
		var icon = new Image();
		var repliesInfo = null;

		if (ul.parentNode.nodeName != "TD") {
			var tail = document.getFirstChildByElement(lis[0], "span", ["tail"]);
			if (tail && lis.length > 1) {
				repliesInfo = document.getFirstChildByElement(tail, "span", ["replies"]);
				if (!repliesInfo) {
					repliesInfo = document.createElementWithAttributes("span", [["className", "replies"]], tail);
					repliesInfo.appendChild( document.createTextNode( " (" + (lis.length-1) + ")" ) );
				}
			}
		}
		
		this.isFold = function() {
			return uls.length>0&&uls[0].style.display=="none";
		};
		
		this.setFold = function(fold, changeCSS) {
			changeCSS = changeCSS || false;
			if (fold) {
				icon.src = templatePath + settings["expand_thread_image"];
				icon.className = "expand-thread";
				icon.alt = "";
				icon.onerror = function(e) { this.alt = "[+]"; };
				icon.title = lang["expand_fold_thread_linktitle"]; 
				
				if (repliesInfo)
					repliesInfo.style.display = "";

				if (changeCSS)
					ul.className = ul.className.replace("expanded", "folded");
			}
			else {
				icon.src = templatePath + settings["fold_thread_image"];
				icon.className = "fold-thread";
				icon.alt = "";
				icon.onerror = function(e) { this.alt = "[-]"; };
				icon.title = lang["expand_fold_thread_linktitle"]; 
				
				if (repliesInfo)
					repliesInfo.style.display = "none";
				
				if (changeCSS)
					ul.className = ul.className.replace("folded", "expanded");
			}
			var cssVal = fold?"none":"";
			for (var i=0; i<uls.length; i++) {
				uls[i].style.display = cssVal;
			}
		};	
		
		var setIcon = function(el) {
			if (!el)
				return;
			if (lis.length > 0 && lis[0].firstChild) 
				lis[0].insertBefore(el, lis[0].firstChild);
			else
				lis[0].appendChild(el);
		};
		
		var foldExpandWrapper = document.createElementWithAttributes("span", [["className", "fold-expand"]], null);
		
		if (lis.length == 1) {
			var inactiveFoldExpandImg = document.createElementWithAttributes("img", [["src", templatePath + settings["expand_thread_inactive_image"]], ["className", "expand-thread-inactive"], ["alt", ""], ["onerror", function(e) { this.alt = "[]"; }]], foldExpandWrapper)
			setIcon(foldExpandWrapper);  
		}
		else {
			var link = document.createElementWithAttributes("a", [["href", "#"], ["onclick", function(e) {self.setFold(!self.isFold()); this.blur(); return false;}]], foldExpandWrapper);
			this.setFold(this.isFold());
			link.appendChild(icon);
			setIcon(foldExpandWrapper);
		}
	}
	
	/**
	 * Erzeugt aus einer ID ein Posting, welches ein- und ausgeklappt werden kann
	 * @param pid
	 */
	function Posting(pid) {
		if (!pid) 
			return;
		var pHeadline = document.getElementById("headline-" + pid);
		var pContent = document.getElementById("posting-" + pid);
		var pAvatar = document.getElementById("avatar-" + pid) || new Image();
		if (!pHeadline || !pContent)
			return;
			
		var self = this;
		try { pHeadline.style.cursor = "pointer"; } catch(e){ pHeadline.style.cursor = "hand"; }
		pHeadline.title = lang["fold_posting_title"];
		pHeadline.onclick = function(e) {
			self.setFold(!self.isFold());
		};
		
		this.isFold = function() {
			return pContent.style.display == "none";
		};
		
		this.setFold = function(fold) {
			var cssValue = fold?"none":"";
			pContent.style.display = cssValue;
			pAvatar.style.display  = cssValue;
			//pHeadline.title = fold?"Posting ausklappen":"Posting einklappen";
		};
		
		this.setFold(this.isFold());
	}
	
	
	function FullSizeImage(els) {
		if (!els) return;
		els = (typeof els == "object" || typeof els == "function") && typeof els.length == "number"?els:[els];
		var hashTrigger = null;
		var body = document.body;
		// http://aktuell.de.selfhtml.org/weblog/kompatibilitaetsmodus-im-internet-explorer-8
		var isIELower8 = /*@cc_on!@*/false && !(document.documentMode && document.documentMode >= 8);
   		var imageCanvas = document.getElementById("image-canvas") || document.createElementWithAttributes("div", [["id", "image-canvas"]], body);	
   		imageCanvas.setVisible = function(enable) {
			this.style.display = enable?"block":"none";
		};
		var stopTrigger = function() {
			if (hashTrigger) {
				window.clearInterval(hashTrigger);
				var scrollPos = document.getScrollPosition();
				if (!isIELower8)
					window.history.back();
				else
					window.location.hash="GET_OPERA";
				// Fuer den Fall, dass man bei eingeblendeten Bild gescrollt hat
				window.scrollTo(scrollPos.left, scrollPos.top);	
			}
		};
		
		var oldOnKeyPressFunc = window.document.onkeypress;
		window.document.onkeypress = function(e) { 
			var keyCode = document.getKeyCode(e);
			if (keyCode == 27) {
				imageCanvas.setVisible(false);
				stopTrigger();
			}
			if (typeof oldOnKeyPressFunc == "function")
				oldOnKeyPressFunc(e);
		};
		imageCanvas.onclick = function(e) {
			imageCanvas.setVisible(false);
			stopTrigger();
		}; 
		imageCanvas.setVisible(false);			
		var fullSizeImage = document.getElementById("fullSizeImage") || document.createElementWithAttributes("img", [["id", "fullSizeImage"]], imageCanvas);
		for (var i=0; i<els.length; i++) {
			var links = els[i].getElementsByTagName("a");
			for (var j=0; j<links.length; j++) {
				if(links[j].rel.search(/thumbnail/) != -1) {
					links[j].onclick = function(e) {
						window.location.hash="image";
   						var currentHash = window.location.hash;
						fullSizeImage.src = this.href;
						imageCanvas.setVisible(true);
						var imgPoSi = document.getElementPoSi(fullSizeImage);
						var scrollPos = document.getScrollPosition();
						var winSize = document.getWindowSize();							
						imageCanvas.style.height=winSize.pageHeight+"px";
						//fullSizeImage.style.left = ((winSize.windowWidth-imgPoSi.width)/2)  + "px";
						//fullSizeImage.style.left = ((winSize.windowWidth-fullSizeImage.width)/2)  + "px";  
						//fullSizeImage.style.top = (scrollPos.top+(winSize.windowHeight-imgPoSi.height)/2) + "px"; 
						fullSizeImage.style.marginTop = (scrollPos.top+(winSize.windowHeight-imgPoSi.height)/2) + "px"; 
						
						hashTrigger = window.setInterval( 
							function() {
								if ( this.location.hash != currentHash ) {
									imageCanvas.setVisible(false);
								}
							},50 
						);
						return false;
					};				
				}
			}
		}
	}
		
	/**
	 * Erzeugt anhand eines HTML-Strings ein Geruest fuer
	 * ein Vorschaufenster und haengt dieses im Dokument
	 * ein
	 * @param structure
	 * @param templatePath
	 */
	function AjaxPreviewWindow(structure, templatePath) { 
		var templatePath = templatePath?templatePath:"";
		var hideURI = false;
		var win = document.getElementById('ajax-preview');
		var self = this;
		if (!win) {
			win = document.createElementWithAttributes("div", [["id", "ajax-preview"]], null);	
			win.style.display = "none";
			document.body.appendChild( win );
		}
		win.innerHTML = structure.stripslashes().trim();
		var opEl = null;
		var xShift = 0;
		
		var closeEl = document.getElementById("ajax-preview-close");
		var contentEl = document.getElementById("ajax-preview-content");
		var mainEl    = document.getElementById("ajax-preview-main");		
		
		if (!closeEl || !contentEl || !mainEl)
			window.alert("fail");
		
		
		var oldOnMouseDownFunc = window.document.onmousedown;
		window.document.onmousedown = function(e) { 
			self.closeByOutSideClick(e);	
			if (typeof oldOnMouseDownFunc == "function")
				oldOnMouseDownFunc(e);
		};

		var oldOnKeyPressFunc = window.document.onkeypress;
		window.document.onkeypress = function(e) { 
			var keyCode = document.getKeyCode(e);
			if (keyCode == 27) {
				self.setVisible(false);	
			}
			if (typeof oldOnKeyPressFunc == "function")
				oldOnKeyPressFunc(e);
		};
		closeEl.onclick = function() { self.setVisible(false); return false; };
		var throbberIcon = document.createElementWithAttributes("img", [["id", "ajax-preview-throbber"], ["src", templatePath + settings["ajax_preview_throbber_image"]], ["alt", "[*]"]], contentEl);
		var replylinkWrapper = document.createElementWithAttributes("p", [["id", "ajax-preview-replylink-wrapper"]], contentEl);
		var replylinkLink = document.createElementWithAttributes("a", [["id", "ajax-preview-replylink"], ["href", "#"]], null);
		replylinkLink.appendChild( document.createTextNode( lang["reply_link"] ));
		replylinkWrapper.style.display = "none";
		this.closeByOutSideClick = function(e) {
			var imgCanvas = document.getElementById("image-canvas");
			if (self.isVisible() && imgCanvas && imgCanvas.style.display=="none") {
				var obj = document.getTarget(e);
				if (obj && obj != self.getOpener().firstChild) {
					var evtPos = document.getMousePos(e);
					var posX = evtPos.left;
					var posY = evtPos.top;
					var boxX = self.getDocumentPosition().left; 
					var boxY = self.getDocumentPosition().top; 
					var boxWidth  = self.getWidth();  
					var boxHeight = self.getHeight(); 
					if ((posX < boxX || posX > (boxX+boxWidth) || posY < boxY || posY > (boxY+boxHeight)) && obj.className!='ap') {
						self.setVisible(false);
					}
				}
			}
		}
		
		this.hideURI = function(hide) {
			hideURI = hide;
		};
		
		this.setPosition = function(x, y) {
			win.style.left = x + "px";
			win.style.top  = y + "px";
			var winWidth = this.getWidth();	
			var documentWidth = document.getWindowSize().windowWidth;
			if ((x+winWidth) >= documentWidth) {
				this.moveHorizontal( documentWidth-25-(x+winWidth) );			
			}
			else {
				this.moveHorizontal( 0 );	
			}
		};
		
		this.getWidth = function() {
			return mainEl.offsetWidth;
		};
		
		this.getHeight = function() {
			return win.offsetHeight + mainEl.offsetHeight;
		};
		
		this.setOpener = function(op) {
			opEl = op;
		};
		
		this.getOpener = function() {
			return opEl;
		};
		
		this.isVisible = function() {
			return win.style.display != "none";
		};
		
		this.getDocumentPosition = function() {
			var left = win.offsetLeft;
			var top  = win.offsetTop;
			return {
				top: top,
				left: left + xShift
			};
		};
		
		this.moveHorizontal = function(val) {
			xShift = val;
			mainEl.style.left = val + "px";
		};

		this.setVisible = function(visible) {
			if (visible) {
				win.style.display = "block";
			}
			else {
				win.style.display = "none";
			}
		};
		
		this.setText = function(str) {
			contentEl.innerHTML = str;
			if (str != "") {
				if (!replylinkLink.firstChild)
					replylinkLink.appendChild( document.createTextNode( lang["reply_link"] ));
				if (!hideURI) {
					replylinkWrapper.appendChild( replylinkLink );
					contentEl.appendChild( replylinkWrapper );
				}
				new FullSizeImage(contentEl);
			}
			else {
				contentEl.appendChild( throbberIcon );
			}
		};
		
		this.setURI = function(uri) {
			if (!uri) {
				replylinkLink.href = "#";
				replylinkWrapper.style.display = "none";
			}
			else {
				replylinkWrapper.style.display = "block";
				replylinkLink.href = uri;
			}
		};
	}	
	
	/**
	 * Hauptfunktion des Forums
	 */
	function MyLittleJavaScript() {
		var templatePath      = null;
		var ajaxPreviewWindow = null;
		var sidebar           = null;
		var strURL = 'index.php';
		var threads = [];
		var postings = [];
		var regExpFID = new RegExp(/[?|&]id=([0-9]+)(#p([0-9]+))?/);
		var self = this;
		
		/**
		 * Ermittelt die Posting ID aus einer URI
		 * @param link
		 * @return id
		 */
		var getPostingId = function(link) {
			if (link && regExpFID.test(link.href)) {
				var q = regExpFID.exec(link.href);
				return q[3]?q[3]:q[1];
			}
			return false;
		}
		
		/**
		 * Liefert den Pfad zum gewaehlten Template,
		 * welcher aus einem LINK-Element ermittelt wird.
		 * @return path
		 */
		this.getTemplatePath = function() {
			if (templatePath != null)
				return templatePath;
			var el = document.getElementsByTagName("link");
			for (var i=0; i<el.length; i++) {
				if (el[i].rel == "stylesheet") {
					return el[i].href.substring(0, el[i].href.lastIndexOf("/")+1);
				}
			}
			return "";
		};
		
		/**
		 * Erstellt einen Link (mit Bild), der, wenn er geklickt wird,
		 * oeffnet das Vorschaufenster
		 * @param id
		 * @return link
		 */
		var createAjaxPreviewLink = function(id) {
			var link = document.createElementWithAttributes("a", [["pid", id], ["title", lang["ajax_preview_title"]], ["href", strURL+"?id="+id], ["onclick", function(e) {self.showAjaxPreviewWindow(this); this.blur(); return false; }]], null);
			var img  = document.createElementWithAttributes("img", [["src", templatePath + settings["ajax_preview_image"]], ["title", lang["ajax_preview_title"]], ["alt",""], ["onload", function(e) { this.alt = "[…]"; }], ["onerror", function(e) { this.alt = "[…]"; }]], link);
			return link;
		};
		
		/**
		 * Erzeugt den Link zum Vorschaufenster
		 * im Nutzerprofil einem Element hinzu
		 * @param el
		 */
		var setPreviewBoxToProfil = function(el) {
			if (!el || !ajaxPreviewWindow)
				return;		
			var pid = getPostingId(el);
			if (pid && el.parentNode) {
				el.parentNode.appendChild( document.createTextNode( String.fromCharCode(160) ) );
				el.parentNode.appendChild( createAjaxPreviewLink(pid) );	
			}
		};
		
		/**
		 * Erzeugt den Link zum Vorschaufenster
		 * auf der Antwortseite, welches einem Element hinzugefuegt wird
		 * @param el
		 */
		var setPreviewBoxToReplyPage = function(el) {
			if (!el || !ajaxPreviewWindow)
				return;
			ajaxPreviewWindow.hideURI( true );
			var f = document.getElementById("postingform");
			var pid = false;
			if (f && f.elements["id"]) {
				pid = parseInt(f.elements["id"].value);
			}
			if (pid) {
				el.appendChild( document.createTextNode( String.fromCharCode(160) ) );
				el.appendChild( createAjaxPreviewLink(pid)  );	
			}
		};
		
		/**
		 * Markiert ein Posting ADMIN-Funktion
		 * @param param1 id || xml
		 * @param param2 null || args
		 */
		this.selectPosting = function(par1, par2) {
			var isResponse = par2 && (typeof par2 == "object" || typeof par2 == "function") && par2.length > 0;
			var pid = isResponse?par2[0]:par1;
			var xml = isResponse?par1:false;
			var imgEl = null;
			if (!pid || !(imgEl = document.getElementById('markimg_'+pid)))
				return;
				
			imgEl.src = templatePath + settings["mark_process_image"];
			imgEl.alt = '[ ]';

			var querys = [
				new Query("mode", "posting"),
				new Query("mark", pid),
				new Query("method", "ajax")
			];
			if (!isResponse)
				new Request(strURL, "POST", querys, this, "selectPosting", pid, true);
			else if (isResponse && xml && document.getElementById('marklink_'+pid)) {
				var linkEl = document.getElementById('marklink_'+pid);
				var selectPosting = xml.getElementsByTagName('action') && xml.getElementsByTagName('action')[0].firstChild.data == "1";
				if(selectPosting) {
					imgEl.src = templatePath + settings["marked_image"];
					imgEl.alt = '[●]';
					linkEl.title = lang["unmark_linktitle"];
					imgEl.title  = lang["unmark_linktitle"];
				}
				else {
					imgEl.src = templatePath + settings["unmarked_image"];
					imgEl.alt = '[○]';
					linkEl.title = lang["mark_linktitle"];
					imgEl.title  = lang["mark_linktitle"];
				}
			}
		};

		/**
		 * Oeffnet/Schliesst alle Threads
		 * @param expand
		 */
		var expandAllThreads = function(expand) {
			expand = expand || false;
			for (var i=0; i<threads.length; i++) {
				threads[i].setFold(!expand, true);
			}
 
			var querys = [
					new Query("fold_threads", expand),
					new Query("ajax", "true")
			];

			new Request(strURL, "GET", querys);
		};
		
		var initThreadFoldingInSubMenu = function() {
			if (!document.getElementById("subnavmenu"))
				return;
			var menuLinks = document.getElementById("subnavmenu").getElementsByTagName("a");
			var foldingLink = null;
			var foldRegExp = new RegExp(/fold-([0-9])+/);
			for (var i=0; i<menuLinks.length; i++) {
				if (menuLinks[i].className.search( foldRegExp ) != -1) {
					foldingLink = menuLinks[i];
					break;
				}
			}
			
			if (foldingLink) {
				var q = foldRegExp.exec(foldingLink.className);
				var isExpand = q.length>1&&q[1]=="1";

				foldingLink.onclick = function(e) {
					expandAllThreads( !isExpand );
					this.className = this.className.replace(foldRegExp, "fold-" + (isExpand?2:1) );
					this.firstChild.replaceData(0, this.firstChild.nodeValue.length, (isExpand?lang["expand_threads"]:lang["fold_threads"]) );
					this.title = isExpand?lang["expand_threads_linktitle"]:lang["fold_threads_linktitle"];
					isExpand = !isExpand;
					this.blur();
					return false;
				}
			}
		};
		
		/**
		 * Erzeugt die Links zum Vorschaufenster
		 * auf der Forenhauptseite an den gewuenschten Elementen
		 * @param els
		 */
		var setPreviewBoxToMainPage = function(els) {
			if (!els)
				return;
			
			initThreadFoldingInSubMenu();
				
			for (var i=0; i<els.length; i++) {
				var el = els[i];
				var li = el.parentNode;
				var pLink = document.getFirstChildByElement(li, "a", ["ap", "reply", "thread", "replynew", "threadnew", "thread-sticky", "threadnew-sticky", "reply-search", "thread-search"]);
				var pid = parseInt( el.id.substring(1) );
				if (!pid) 
					continue;
				
				var links = el.getElementsByTagName("a");
				if (links.length >= 2) {
					for (var j=0; j<links.length; j++) {
						if (links[j].href.search(/mark/) != -1) {
							links[j].pid = pid;
							links[j].onclick = function(e) {
								self.selectPosting( this.pid );
								this.blur();
								return false;
							};							
						}
						else if (links[j].href.search(/delete_posting/) != -1) {
							links[j].onclick = function(e) {
								var confirmed = window.confirm( lang["delete_posting_confirm"] );
								if (confirmed) 
									this.href += '&delete_posting_confirm=true';
								this.blur();
								return confirmed;	
							};
						}				
					}			
				}
				if (pLink && ajaxPreviewWindow) {
					if (links.length >= 1) {
						var link = links[0];
						el.insertBefore(createAjaxPreviewLink(pid), link);
						el.insertBefore(document.createTextNode( String.fromCharCode(160) ), link);
					}
					else {
						el.appendChild(document.createTextNode( String.fromCharCode(160) ));
						el.appendChild(createAjaxPreviewLink(pid));
					}
				}
				// thread, folded oder expanded - Reicht eigentlich die Suche nach thread?
				if (li.parentNode.className.search(/thread/) != -1 && li.parentNode.className.search(/[folded|expanded]/) != -1) {
					threads.push( new Thread( li.parentNode, templatePath) );
				}
			}
			
			var editAreas = document.getElementsByClassName("options");
			if (editAreas.length > 0) {
				for (var i=0; i<editAreas.length; i++) {
					var links = editAreas[i].getElementsByTagName("a");
					if (links.length > 0) {
						for (var j=0; j<links.length; j++) {
							if (links[j].href.search(/delete_posting/) != -1) {
								links[j].onclick = function(e) {
									var confirmed = window.confirm( lang["delete_posting_confirm"] );
									if (confirmed) 
										this.href += '&delete_posting_confirm=true';
									return confirmed;	
								};
								break;
							}				
						}			
					}
				}
			}

			var pEls = document.getElementsByClassName("posting");
			pEls = pEls.length>0?pEls:document.getElementsByClassName("thread-posting");
			new FullSizeImage(pEls);
		};

		var setDefaultInputValue = function(id) {
			var inp = document.getElementById(id);
			if (!inp) 
				return;
			//var value = inp.value;
			var value = (inp.alt) ? inp.alt : inp.value;
			inp.onfocus = function(e) {
				if (this.value == value) 
					this.value="";
			};
			inp.onblur = function(e) {
				if(this.value.trim() == "") 
					this.value = value;
			};
		};

		/**
		 * Durchsucht Seite nach einem Formular innerhalb von 
		 * >CONTENT< und setzt den Fokus auf das erste INPUT
		 * Trift auf Anmeldung und Antworten zu
		 */
		var setFocusToContentForm = function() {
			if (document.getElementById("content")) {
				var f = document.getElementById("content").getElementsByTagName("form");
				if (f && f.length>0) {
					for (var i=0; i<f[0].elements.length; i++) {
						if (f[0].elements[i].type == "text" && f[0].elements[i].name != "search_user" && f[0].elements[i].name != "smiley_code" && f[0].elements[i].name != "new_category") {
							f[0].elements[i].focus();
							break;
						}
					}
				}
			}
		};
		
		/**
		 * Oeffnet/Schliesst alle Antworten in einem Thread
		 * @param expand
		 */
		var expandAllPostings = function(expand) {
			expand = expand || false;
			for (var i=0; i<postings.length; i++) {
				postings[i].setFold(!expand);
			}
		};
		
		/**
		 * Initialisiert die Option zum Ein/Ausklappen der einzelnen Threads
		 * @param els
		 */
		var initPostingFolding = function(els) {
			// Postings suchen
			if (!els)
				return;
			for (var i=0; i<els.length; i++) {
				var el  = els[i];
				var pid = parseInt( el.id.substring(1) );
				if (!pid) 
					continue;
				postings.push( new Posting(pid) );
			}
			// Menü anpassen
			var menu = null;
			if (postings.length == 0 || !(menu=document.getElementById("subnavmenu")))
				return;
			var listEntry = document.createElementWithAttributes("li", [], menu);
			var link = document.createElementWithAttributes("a", [["isExpand", true], ["title", lang["fold_postings_title"]],["href", "#"],["className", "fold-postings"]], listEntry);
			link.appendChild( document.createTextNode( lang["fold_postings"] ) );
			link.onclick = function(e) {
				//var isExpand = this.className.search(/expand/)!=-1;
				this.isExpand = !this.isExpand;
				expandAllPostings(this.isExpand);  
				this.blur();
				return false;
			}
		};
		
				
		/**
		 * Initialisiert PopUp-Aufrufe 
		 * bei einem Link
		 */
		var initPopUpLinks = function() {
			var els = [[document.getElementById("terms_of_use") || false, settings["terms_of_use_popup_width"],settings["terms_of_use_popup_height"]],
						[document.getElementById("edit_avatar") || false, settings["avatar_popup_width"],settings["avatar_popup_height"]]];
						
			for (var i=0; i<els.length; i++) {
				if (els[i][0]) {
					var docSize = document.getWindowSize();
					var w = els[i][1];
					var h = els[i][2];
					var l = parseInt(0.5*(docSize.windowWidth-w));
					var t = parseInt(0.25*(docSize.windowHeight-h));
					els[i][0].onclick = function(e) {
						window.open(this.href,"MyLittleForum","width="+w+",height="+h+",left="+l+",top="+t+",scrollbars,resizable");
						return false;
					};
				}
			}
		
		};	
		
		/**
		 * Tauscht bzw. aktualisiert den Inhalt des Vorschaufensters
		 * @param xml
		 */
		this.updateAjaxPreviewWindow = function(xml) {
			if (xml === false || !ajaxPreviewWindow)
				return;
			var content = xml.getElementsByTagName('content');
			var isLocked = xml.getElementsByTagName('locked');
			
			isLocked = !isLocked?true:isLocked[0].firstChild.data == "1";
			content = !content?"":content[0].firstChild.data;
				
			if (isLocked) 
				ajaxPreviewWindow.setURI(false);
			else 
				ajaxPreviewWindow.setURI("index.php?mode=posting&id=" + ajaxPreviewWindow.getOpener().pid);
  
			if (content.trim() == "") 
				content = "<p>"+lang["no_text"]+"</p>";
				
			ajaxPreviewWindow.setText( content );	
		};
		
		/**
		 * Zeigt das Vorschaufenster an. Erwartet das Objekt, 
		 * welches den Aufruf hervorgerufen hat (Opener)
		 * Schliesst das Fenster, wenn auf den selben Opener
		 * erneut geklickt wird
		 * @param obj
		 */
		this.showAjaxPreviewWindow = function(obj) {
			if (!obj || !ajaxPreviewWindow)
				return;
			if (obj == ajaxPreviewWindow.getOpener() && ajaxPreviewWindow.isVisible()) {
				ajaxPreviewWindow.setVisible(false);
				ajaxPreviewWindow.setOpener(null);
			}
			else {
				var elPos = document.getElementPoSi(obj);
				ajaxPreviewWindow.setOpener(obj);
				ajaxPreviewWindow.setText("");
				ajaxPreviewWindow.setVisible(true);	
				ajaxPreviewWindow.setPosition( elPos.left, elPos.top );
				var querys = [
								new Query("mode", "entry"),
								new Query("ajax_preview", "true"),
								new Query("id", obj.pid)
				];
				new Request(strURL, "POST", querys, this, "updateAjaxPreviewWindow", null, true);
			}

		};
		
		/**
		 * Liefert das Vorschaufenster
		 * @return win
		 */
		this.getAjaxPreviewWindow = function() {
			return ajaxPreviewWindow;
		}

		/**
		 * Sendet das Formular im Submenue ab, wenn sich der
		 * Wert im Drop-Down-Menue aendert
		 */
		var setAutoSubmitSubNaviForms = function() {
			var subNav = document.getElementById("subnav-2");
			if (subNav) {
				var f = subNav.getElementsByTagName("form");
				for (var i=0; i<f.length; i++) {
					var els = f[i].getElementsByTagName("select");
					for (var j=0; j<els.length; j++) {
						els[j].f = f[i];
						els[j].onchange = function(e) { this.f.submit(); return false; };
					}
				}
			}
		};
		
		/**
		 * Initialisiert MyLittelJavaScript
		 * @param ajaxPreviewStructure
		 */
		this.init = function( ajaxPreviewStructure ) {
			ajaxPreviewStructure = ajaxPreviewStructure || false;
			setFocusToContentForm();
			setDefaultInputValue("search-input");
			setDefaultInputValue("search-user");
			templatePath = this.getTemplatePath();
			if (ajaxPreviewStructure)
				ajaxPreviewWindow = new AjaxPreviewWindow( ajaxPreviewStructure, templatePath );
			setPreviewBoxToProfil( document.getElementById("user-last-posting") );
			setPreviewBoxToReplyPage( document.getElementById("reply-to") );
			setPreviewBoxToMainPage( document.getElementsByClassName("tail") );
			
			initPostingFolding( document.getElementsByClassName("thread-posting") );
			initPopUpLinks();
			setAutoSubmitSubNaviForms();
			sidebar = new Sidebar(templatePath);
			
			if (typeof preload == "object") 
				document.preloadImages(preload, templatePath);		
		};
	
	}
	
	var mlf = null;
	window.ready.push(function() {
		mlf = new MyLittleJavaScript();
		var ajaxPreviewStructure = typeof settings != "undefined" && typeof settings["ajaxPreviewStructure"] == "string"?settings["ajaxPreviewStructure"]:false;
		if (mlf && typeof lang == "object") 
			mlf.init(ajaxPreviewStructure);
	});

