/************************************
/************************************
* Explorer-Verhalten von HTML-<ul>-Listen
*************************************
*
* V 0.5 (2006-12-02)
*
* Dieses Script reagiert nur auf <ul>-Elemente,
* die eine bestimmte CSS-Klasse haben,
* sowie auf deren Nachfahren <ul>-Elemente.
*
*
* Felix Riesterer (Felix.Riesterer@gmx.net)
*/

var Explorer = {

	triggerClass : "explorer-baum",	/* Variable, in die ein frei wählbarer CSS-Klassenname eingetragen werden kann,
		auf den das Script dann reagieren wird. Entsprechend muss auch der Klassenname in der CSS-Datei verwendet werden! */

	highlightClass : "explorer-highlight", // CSS-Klasse für das Ziel-Highlighting

	cssFileClass : "file", // CSS-Klasse, die eine Datei als solche auszeichnet

	alle_uls : false, /* enthält nach dem Initialisieren Objekte mit Explorer-<ul>-Elementen und deren Nachfahren-<ul>s
		in der Form ({ 'stamm' : null, 'ordner' : 'null' }, {'stamm' : null, 'ordner' : null}) */

	baseURL : false, // enthält später den Pfad zu diesem Script

	dragNDropEnabled : false, // kann mit true für Drag&Drop-Funktionalität überschrieben werden

	dragMode : false, // entscheidet, ob ein Element bei onmousedown gezogen werden soll, oder nicht

	platzHalter : null, // hier steht später eine Referenz auf das geklonte HTML-Element

	dragElm : null, // hier steht später eine Referenz auf das HTML-LI-Element in dem der mousedown stattfand

	highlightElm : null, // hier steht später eine Referenz auf das HTML-LI-Element, welches gerade als potenzielles Ziel anvisiert wird

	mouseLastCoords : {
		// wird später mit den Mauskoordinaten überschrieben werden
		left : 0,
		top : 0
	},

	visibilityCountDefault : 1, // Anzahl mouseover-Events, bei denen das Drag-Element nicht unsichtbar geschaltet wird (reduziert das Flimmern beim Draggen)

	visibilityCount : 0, // Hier findet später der Countdown statt, um das Drag-Element nicht bei jedem mouseover-Event unsichtbar zu schalten

	visibilityTimeOut : 1, // Anzahl "Milisekunden", die das Drag-Element unsichtbar bleiben muss, damit das onmouseover-Event des darunterliegenden Elements feuert

	// Platzhalter für Eventhandler
	oldWinOnLoad : "leer",
	oldDocOnMouseMove : "leer",

	initOnLoad : function () {
		if (Explorer.oldDocOnMouseMove == "leer") {
			Explorer.oldDocOnMouseMove = window.document.onmousemove;
			window.document.onmousemove = function (e) {
				if (typeof (Explorer.oldDocOnMouseMove) == "function")
					Explorer.oldDocOnMouseMove(e);

				Explorer.whileDrag(e);
			}
		}

		// OnLoad-Handler nur einmal eintragen
		if (Explorer.oldWinOnLoad == "leer") {
			Explorer.oldWinOnLoad = window.onload;
			window.onload = function () {
				if (typeof (Explorer.oldWinOnLoad) == "function")
					Explorer.oldWinOnLoad();

				Explorer.init();
			}
		}
	},

	init : function () {
		// baseURL herausfinden
		var i, scripts;
		scripts = document.getElementsByTagName("script");
		for (i = 0; i< scripts.length; i++)
			if (scripts[i].src && scripts[i].src.match(/\/explorer.js$/))
				Explorer.baseURL = scripts[i].src.substr(0, scripts[i].src.lastIndexOf("/") + 1);

		// CSS für den Dateibaum einbinden
		var css = document.createElement("link");
		css.rel = "stylesheet";
		css.type = "text/css";
		css.media = "all";
		css.href = Explorer.baseURL + "css/explorer.css";
		document.getElementsByTagName("head")[0].appendChild(css);

		// Initialisierung der browserspezifischen Werte für das Timing bei Drag&Drop
		if (navigator.appName.match(/netscape/i)) {
			Explorer.visibilityCountDefault = 6;
			Explorer.visibilityTimeout = 1;
		}

		if (navigator.appName.match(/opera/i)) {
			Explorer.visibilityCountDefault = 1;
			Explorer.visibilityTimeout = 0;
		}

		if (navigator.appName.match(/microsoft/i)) {
			Explorer.visibilityCountDefault = 5;
			Explorer.visibilityTimeout = 1;
		}

		var func = function () {
			// Initialisierung der <ul>-Elemente
			var i, c, alle_uls, ordner, unter_ordner, alle_ordner;
			alle_ordner = new Array();
			alle_uls = document.getElementsByTagName("ul");
			for (i = 0; i < alle_uls.length; i++) {
				if (alle_uls[i].className) {
					if (alle_uls[i].className == Explorer.triggerClass) {
						ordner = alle_uls[i].getElementsByTagName("ul");
						alle_ordner[alle_ordner.length] = { 'stamm' : alle_uls[i], 'ordner' : ordner};

					// Eventhandler einrichten
					alle_uls[i].onmousedown = function (e) { Explorer.startDrag(e); };
					alle_uls[i].onmouseover = function (e) { Explorer.highlight(e); };
					alle_uls[i].onmouseup = function (e) { Explorer.stopDrag(e); };
					alle_uls[i].ondblclick = function (e) { Explorer.direkteAuswahl(e); };
					}
				}
			}

			// alle Explorer-<ul>s abspeichern
			Explorer.alle_uls = alle_ordner;
	        // und schließen
			Explorer.alle_zu();

			// jeweils oberstes Element öffnen, wenn es ein einzelner Ordner ist
			for (i = 0; i < alle_ordner.length; i++) {
				var liElements = new Array();
				for (c = 0; c < alle_ordner[i].stamm.childNodes.length; c++) {
					if (alle_ordner[i].stamm.childNodes[c].tagName &&
						alle_ordner[i].stamm.childNodes[c].tagName.toLowerCase() == "li")

						liElements[liElements.length] = alle_ordner[i].stamm.childNodes[c];
				}

				if (liElements.length == 1)
					if (liElements[0].getElementsByTagName("ul").length > 0)
						Explorer.aufzu(liElements[0]);
			}
		};

		// IE braucht einen Timeout, andere Browser nicht
		if (navigator.appName.match(/microsoft/i)) {
			window.setTimeout(func, 100);
		} else
			func();
	},

	alle_zu : function () { // klappt alle Ordner zu
		var i, u, alle_ordner, icon_src;
		if (!Explorer.alle_uls)
			Explorer.init();

		for (u = 0; u < Explorer.alle_uls.length; u++) {

			alle_ordner = Explorer.alle_uls[u].ordner;

			for (i = 0; i < alle_ordner.length; i++) {
				alle_ordner[i].parentNode.className = "zu";

				icon_src = alle_ordner[i].parentNode.getElementsByTagName("img");
				icon_src = icon_src[0].src.substring(icon_src[0].src.lastIndexOf("/") + 1, icon_src[0].src.lastIndexOf("."));
				if (icon_src.substr(icon_src.length - 4, 4) == "open")
					icon_src = icon_src.substr(0, icon_src.lastIndexOf("open"));

				alle_ordner[i].parentNode.childNodes[0].childNodes[0].src = Explorer.baseURL + "images/" + icon_src + ".gif";
			}
		}
		return false;
	},

	alle_auf : function () { // klappt alle Ordner auf
		var i, u, alle_ordner, icon_src;

		if (!Explorer.alle_uls)
			Explorer.init();

		for (u = 0; u < Explorer.alle_uls.length; u++) {
			alle_ordner = Explorer.alle_uls[u].ordner;

			for (i = 0; i < alle_ordner.length; i++) {
				alle_ordner[i].parentNode.className = "auf";

				icon_src = alle_ordner[i].parentNode.getElementsByTagName("img");
				icon_src = icon_src[0].src.substring(icon_src[0].src.lastIndexOf("/")+1, icon_src[0].src.lastIndexOf("."));

				if (icon_src.substr(icon_src.length -4, 4) != "open")
					icon_src = icon_src + "open";

				alle_ordner[i].parentNode.childNodes[0].childNodes[0].src = Explorer.baseURL + "images/" + icon_src + ".gif";
			}
		}

		return false;
	},

	// wechselt den Zustand eines Ordners - erwartet ein LI-Element
	aufzu : function (element) {
		if (!Explorer.baseURL)
			Explorer.init();

		var icon, icon_src;

		icon = element.getElementsByTagName("a")[0].getElementsByTagName("img")[0];
		icon_src = icon.src;
		icon_src = icon_src.substring(icon_src.lastIndexOf("/") + 1, icon_src.lastIndexOf("."));

		if (element.className == "auf" && !Explorer.dragMode) {
			element.className = "zu";
			icon_src  = icon_src.substring(0, icon_src.lastIndexOf("open"));
		} else {
			if (element.className == "zu") {
				element.className = "auf";
				icon_src = icon_src + "open";
			}
		}

		icon.src = Explorer.baseURL + "images/" + icon_src + ".gif";

		return false;
	},

	auswahl : function (element, ziel) {
		if (!Explorer.baseURL)
			Explorer.init();

		if (ziel) {
			// Drag&Drop hat stattgefunden!
			var zielURL = ziel.href;
			var zielTyp = (ziel.parentNode.className == Explorer.cssFileClass) ? "datei" : "ordner";
			var elmURL = element.getElementsByTagName("a")[0].href;
			var elmTyp = (element.className == Explorer.cssFileClass) ? "datei" : "ordner";
			alert("Es soll " + elmTyp.toUpperCase() +"\n\"" + elmURL + "\"\nnach " + zielTyp.toUpperCase() + "\n\"" + zielURL + "\"\n verschoben werden...?");
		}

		// User-Eingabe war nur ein simpler Klick...
		if (element.className && element.className == Explorer.cssFileClass)
			// ... auf eine Datei
			return false;

		// ... auf einen Ordner -> Link nicht ausführen!
		element.getElementsByTagName("a")[0].onclick = function () { return false; };

		// Hier könnte man jetzt bei großen Verzeichnis-Listings ein dynmaisches Nachladen der Unterordner-Struktur per AJAX implementieren...
		return Explorer.aufzu(element);
	},

	direkteAuswahl : function (e) {
		alert("Doppelclick!");
		return false; // kann von anderen Javascripten überschrieben werden, um erweiterte Funktionalitäten zu bieten
	},

	startDrag : function (e) {
		if (!e)
			e = window.event;

		if (e.target)
			Explorer.dragElm = e.target; // W3C DOM

		if (e.srcElement) {
			Explorer.dragElm = e.srcElement; // IE
		}

		// Nur bei Klick auf das Link-Element Drag&Drop-Verhalten zeigen (nicht bei Klick auf das Pluszeichen vor dem Ordner)
		Explorer.dragMode = !(Explorer.dragElm.tagName && Explorer.dragElm.tagName.toLowerCase() == "li");

		while (Explorer.dragElm && Explorer.dragElm.tagName.toLowerCase() != "li" && Explorer.dragElm.tagName.toLowerCase() != "body")
			Explorer.dragElm = Explorer.dragElm.parentNode;
    },

	whileDrag : function (e) {
		var top, left, dx, dy, width, height, img;

		if (!e)
			e = window.event;

		left = e.clientX,
		top = e.clientY

		Explorer.IE = (window.document.compatMode && window.document.compatMode == "CSS1Compat") ?
			window.document.documentElement : window.document.body || null;

		if (Explorer.IE && typeof (Explorer.IE.scrollLeft) == "number") {
			left += Explorer.IE.scrollLeft;
			top +=  Explorer.IE.scrollTop;
		}

		// Abstand zu den letzten Mauskoordinaten berechnen
		dx = Explorer.mouseLastCoords.left - left;
		dy = Explorer.mouseLastCoords.top - top;

		// Mauskoordinaten speichern
		Explorer.mouseLastCoords.left = left;
		Explorer.mouseLastCoords.top = top;

		// falls gerade kein Element gezogen wird, hier beenden
		if (!Explorer.dragElm || !Explorer.dragNDropEnabled || !Explorer.dragMode)
			return true;

		// falls das zu ziehende Element noch nicht "losgelöst" wurde, dieses beweglich machen
		if (!Explorer.platzHalter && Explorer.dragElm) {
			Explorer.platzHalter = Explorer.dragElm.cloneNode(true);

			Explorer.dragElm.style.top = Explorer.dragElm.offsetTop + "px";
			Explorer.dragElm.style.left = Explorer.dragElm.offsetLeft + "px";

			// Korrekturen an der Position des Drag-Elementes für IE
			if (document.attachEvent && typeof (Explorer.IE.scrollLeft) == "number") {
				Explorer.dragElm.style.top = Explorer.dragElm.offsetTop + 15 + "px";
				Explorer.dragElm.style.left = Explorer.dragElm.offsetLeft + 15 + "px";
			}

			Explorer.dragElm.style.display = "block";
			Explorer.dragElm.style.position = "absolute";
			Explorer.dragElm.id = "drag-element";

			// Ersatz-Element einfügen (das Original wird für die Mouse-Events benötigt!)
			Explorer.dragElm.parentNode.insertBefore(Explorer.platzHalter, Explorer.dragElm);
		}

		if (Explorer.visibilityCount < 1)
			// Durchscheinen, damit ein mouseover-Event des unterhalb liegenden Elementes möglich wird
			Explorer.dragElm.style.display = "none";

		// zu ziehendes Element bewegen
		left = parseInt(Explorer.dragElm.style.left);
		top = parseInt(Explorer.dragElm.style.top);
		Explorer.dragElm.style.left = left - dx + "px";
		Explorer.dragElm.style.top = top - dy + "px";
		Explorer.dragged = true;

		if (Explorer.visibilityCount < 1) {
			// durchscheinen beenden - mit Zeitverzögerung
			window.setTimeout("Explorer.dragElm.style.display = '';", Explorer.visibilityTimeOut);
			Explorer.visibilityCount = Math.ceil(Explorer.visibilityCountDefault);
		} else
			Explorer.visibilityCount--;
	},

	// drag & drop beenden
	stopDrag : function (e) {
		var returnVal;

		if (Explorer.platzHalter) {
			// das bewegte Element entfernen
			Explorer.dragElm.parentNode.removeChild(Explorer.dragElm);
		}

		// Rückgabewert bereitstellen
		returnVal = Explorer.dragged ?
			// für Drag&Drop
			Explorer.auswahl(Explorer.dragElm, Explorer.highlightElm) :
			// für einen simplen Klick (zweiter Parameter false!)
			Explorer.auswahl(Explorer.dragElm, false);

		// Variablen wieder löschen
		Explorer.dragElm = null;
		Explorer.platzHalter = null;
		Explorer.dragged = false;
		Explorer.dragMode = false;

		// gehighlightetes Element wieder abstellen
		if (Explorer.highlightElm) {
			var muster = new RegExp(" ?" + Explorer.highlightClass, "i")
			Explorer.highlightElm.className = Explorer.highlightElm.className.replace(muster, "");
			Explorer.highlightElm = null;
		}

		return returnVal;
	},

	highlight : function (e) {
		var old = Explorer.highlightElm;
		var test, original;

		if (!Explorer.dragNDropEnabled || !Explorer.dragMode)
			return false;

		if (!e)
			e = window.event;

		if (e.target)
			original = e.target; // W3C DOM

		if (e.srcElement)
			original = e.srcElement; // IE

		// Nur den kompletten Link highlighten lassen -> Link-Element in parentNodes suchen
		if (!original.tagName || original.tagName != "a") {
			test = original;
			while (test.tagName && test.tagName.toLowerCase() != "a" && test.tagName.toLowerCase() != "body")
				test = test.parentNode;
			// <body> erwischt? -> in den ChildNodes suchen
			if (test.tagName.toLowerCase() == "body") {
				if (original.getElementsByTagName("a").length > 0)
					test = original.getElementsByTagName("a")[0];
				else
					test = null;
			}
		}

		Explorer.highlightElm = (test && test.parentNode != Explorer.dragElm) ? test : Explorer.highlightElm;

		// Highlighten!
		if (Explorer.highlightElm != Explorer.dragElm) {
			// altes Highlight entfernen, falls vorhanden
			if (old) {
				var oldClassName = old.className;
				var hover = new RegExp(" ?" + Explorer.highlightClass, "i");
				oldClassName = oldClassName.replace(hover, "");
				old.className = oldClassName;
			}

			// neues Element highlighten
			var newClassName = Explorer.highlightElm.className;
			if (newClassName != "")
				newClassName += " ";
			newClassName += Explorer.highlightClass;
			Explorer.highlightElm.className = newClassName;
		}
    }
};

// initialisieren
Explorer.initOnLoad();