﻿/**
  * Beschreibung:
  *     Generische addLoadEvent Funktion.
  *     Mithilfe dieser Funktion ist es möglich beliebig viele Funktionen
  *     beim Laden einer Datei aufzurufen. Dazu wird die jeweilige Funktion
  *     einfach als Parameter übergeben.
  * Parameter:
  *     @func - die beim Laden der Datei aufzurufende Funktion
  **/
function addLoadEvent(func) {
	var oldonload = window.onload;
	if (typeof window.onload != 'function') {
		window.onload = func;
	} else {
		window.onload = function() {
			if (oldonload) {
				oldonload();
			}
			func();
		}
	}
}

/**
  * Beschreibung:
  *     Prüft ob ein bestimmter Wert in einem Array vorhanden ist.
  * Parameter:
  *     @array  - das zu durchsuchende Array
  *     @needle - der zu suchende Wert
  * Rückgabewert:
  *     @found  - true (gefunden) oder false (nicht gefunden)
  **/
function isInArray(array, needle) {
    var i     = 0;
    var found = false;
    while (i < array.length) {
        if (array[i] == needle) {
            found = true;
            i     = array.length;
        }
        i++;
    }
    return(found);
}

/**
  * Beschreibung:
  *     Stoppt ein kaskadierendes Ausführen von Onclick-Events.
  * Parameter:
  *     @e     - das zu stoppende Event
  * Rückgabewert:
  *     @false - unterbindet ein Ausführen weiterer für das Objekt definierter 
  *              Onclick-Events
  **/
function stopCascading(e) {
    // Je nach Browser ist entweder e oder window.event das aufrufende Event.
    var event = window.event || e;
    // Object Detection, IE kennt dieses Object nicht.
    if (event.stopPropagation) {
        event.stopPropagation();
    // Derselbe Effekt für IE.
    } else {
        event.cancelBubble = true;
    }
    // Deaktiviert weitere Onclick-Funktionalitäten.
    return(false);
}

/**
  * Beschreibung:
  *     Setzt für alle relevanten Elemente der Datei einen Onclick-Event.
  *     Zusätzlich wird für jedes dieser Elemente ein neues Attribut ("inspect")
  *     generiert. Dieses dient zur eindeutigen Identifizierung, ohne eventuell
  *     bestehende id-Attribute zu überschreiben.
  **/
function setOnclickEvent() {
    var objects  = document.getElementsByTagName("*");
    var i        = 0;
    var notUsed  = new Array("HTML", "HEAD", "SCRIPT", "STYLE", "META", "TITLE",
                             "LINK");

    for (i = 0; i < objects.length; i++) {
        if (!isInArray(notUsed, objects[i].nodeName)) {
            objects[i].setAttribute("inspect",i);
            objects[i].onclick = function(e) {
                showElementInInspector(this);
                return(stopCascading(e));
            }
        }
    }
}

/**
  * Beschreibung:
  *     Erzeugt das Inspector-DIV das die Anzeige für den DOM-Inspector 
  *     darstellt.
  **/
function createInspectorDiv() {
    var inspectDiv = document.createElement("div");
    inspectDiv.setAttribute("id","inspector");
    document.body.appendChild(inspectDiv);
}

/**
  * Beschreibung:
  *     Löscht alle Child-Knoten eines Elementes.
  * Parameter:
  *     @target - das zu säubernde Element
  **/
function wipeChilds(target) {
    while (target.hasChildNodes()) {
        target.removeChild(target.lastChild);
    }
}

/**
  * Beschreibung:
  *     Zeigt die Elementhistorie des angeklickten Elements im Inspector-DIV an.
  *     Die Elemente der Historie werden mit Onclick-Events versehen, diese
  *     bewirken, dass das jeweilige Element für das das Historienelement steht,
  *     inspiziert wird.
  * Parameter:
  *     @elem - das angeklickte Element
  **/
function showHistory(elem) {
    var inspectDiv = document.getElementById("inspector");
    var history    = "";
    var help       = elem;
    var aHistory   = new Array();
    var i          = 0;
    var newElement1;
    var newElement2;
    var aShow      = new Array();

    // Die Elementhistorie und die generierten "inspect" Attribute ermitteln
    // und in Arrays speichern.
    while (help != null && help.tagName != "BODY") {
        aHistory.push(help.tagName);
        aHistory.push(" > ");
        aShow.push(help.getAttribute("inspect"));
        aShow.push(-1);
        help = help.parentNode;
    }
    aHistory.push("BODY");
    aShow.push(help.getAttribute("inspect"));

    // Die Elementhistorie aufbauen.
    for (i = aHistory.length - 1; i > -1; i--) {
        // Ein neues Textelement innerhalb eines SPAN-Elements für die
        // Elementhistorie erzeugen.
        newElement1 = document.createElement("SPAN");
        newElement2 = document.createTextNode(aHistory[i]);
        newElement1.appendChild(newElement2);
        inspectDiv.appendChild(newElement1);

        // Für alle Elemente die keine Trennzeichen sind, wird ein spezieller
        // Onclick-Event generiert.
        if (aShow[i] != -1) {
            newElement1.setAttribute("show",aShow[i],true);
            // Den Onclick-Event des ursprünglichen Elements ausführen.
            newElement1.onclick = function(e) {
                var objects = document.getElementsByTagName("*");
                var i       = 0;
                var obj;

                while (i < objects.length) {
                    obj = objects[i];
                    if (this.getAttribute("show") == obj.getAttribute("inspect"))
                        i = objects.length;
                    i++
                }
                showElementInInspector(obj);
                return(stopCascading(e));
            }
        }
    }
}

/**
  * Beschreibung:
  *     Zeigt definierte Attribute + deren Werte des angeklickten Elements im
  *     Inspector-DIV an.
  * Parameter:
  *     @elem - das angeklickte Element
  **/
function showAttributes(elem) {
    var inspectDiv  = document.getElementById("inspector");
    var i           = 0;
    var aAttributes = new Array("name", "id", "href", "style", "class", "src", 
                                "alt", "title");
    var attribute   = "";
    var newElement1;
    var newElement2;
    var newValue    = "";
    var aAttrVal    = new Array();

    // Das Überschrifts-DIV für die Attribute erzeugen.
    newElement1 = document.createElement("DIV");
    newElement2 = document.createTextNode("Attribute");
    newElement1.appendChild(newElement2);
    newElement1.className = "attrHeader";
    inspectDiv.appendChild(newElement1);

    // Die Attribut-Werte-DIVs erzeugen.
    for (i = 0; i < aAttributes.length; i++) {
        if (elem.getAttribute(aAttributes[i], 1) != null) {
            attribute  = aAttributes[i] + ": ";
            attribute += elem.getAttribute(aAttributes[i], 1);
            newElement1 = document.createElement("DIV");
            newElement2 = document.createTextNode(attribute);
            newElement1.appendChild(newElement2);
            newElement1.className = "attribute";
            inspectDiv.appendChild(newElement1);

            newElement1.onclick = function(e) {
                // Mittels Prompt kann der Wert des Attributs geändert werden.
                newValue = prompt("neuer Wert: ", "");
                aAttrVal = this.firstChild.data.split(": ");
                elem.setAttribute(aAttrVal[0], newValue, 1);

                // Den Inspector neu generieren.
                showElementInInspector(elem);
                return(stopCascading(e));
            }
        }
    }
}

/**
  * Beschreibung:
  *     Zeigt Informationen zum angeklickten Element im Inspector-DIV an.
  * Parameter:
  *     @elem - das angeklickte Element
  **/
function showElementInInspector(elem) {
    wipeChilds(document.getElementById("inspector"));
    showHistory(elem);
    showAttributes(elem);
}

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

// Object-Detection
// Das Script wird nur ausgeführt, wenn die aufgeführten Funktionen unterstützt 
// werden.
if (document.getElementById && document.getElementsByTagName &&
    document.createElement  && document.createTextNode       &&
    document.hasChildNodes  && document.removeChild)
{
    // Onload-Events setzen.
    addLoadEvent(setOnclickEvent);
    addLoadEvent(createInspectorDiv);
}
