Created
October 19, 2009 19:56
-
-
Save tow8ie/213677 to your computer and use it in GitHub Desktop.
Some JS code I wrote back in 2005 to create a sliding menu. Animation timing and “cross-browser” functionality was all done “by hand”. Despite of bad coding style it still shows how jQuery & Co. and a culture of widespread JS knowledge totally changed the
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* SlideMenu | |
* ~~~~~~~~~ | |
* | |
* Version: 1.0.0 | |
* Datum: 29.12.2005 | |
* Autor: Tobias Adam | |
* | |
* Getestet auf: Win IE 6.0 | |
* Win IE 5.5 | |
* Win IE 5.0 | |
* Win Firefox 1.07 | |
* Win Opera 8.5 | |
* | |
* WICHTIG !!! | |
* Leerzeichen und Umbrüche im Quelltext können u.U. dazu führen, dass das Script nicht | |
* funktioniert. Deshalb bei Erweiterungen unbedingt an die Vorlage des XHTML-Quelltextes halten. | |
* | |
*/ | |
/*** VARIABLEN-DEKLARATIONEN ***/ | |
/*** Parameter zum Feintunen des Auffahreffekts ****/ | |
/**/ | |
/**/ var iterationen= 10; | |
/**/ var verzoegerung= 5; | |
/**/ var auffahreffektAn= true; | |
/**/ | |
/*******************************************************/ | |
/* Globale Variablen zur logischen Steuerung des Menüs*/ | |
var zuletztGeoeffneteMenueNummer= -1; | |
var ersterProzessGestartet= false; | |
var prozess2An= false; | |
var zeitSchritte= 0; | |
/* Bietet Zugriff auf die oberste Ebene der geschachtelten ul-Listen */ | |
var ebene1= document.getElementById("ersteListe"); | |
/* Nach dem Durchlauf von initEbene2() bietet ebene2 Zugriff auf alle ul-Listen der 2. Ebene | |
Dabei enspricht ebene2[0] dem Untermenü der ersten Kategorie, ebene[2] dem der zweiten usw. */ | |
var ebene2= new Array(); | |
/* Nach dem Durchlauf von hoehenErmitteln() hat dieses Array die Höhen aller Unter-Menüs | |
gespeichert */ | |
var hoehen= new Array(); | |
/* Nach dem ersten Aufruf von ersteEbeneFunktionalisieren() enthält diese Variable die Anzahl | |
der Menü-Punkte */ | |
var anzahlMenuePunkte= 0; | |
/*** PROGRAMM ***/ | |
init(); | |
/*** FUNKTIONEN ***/ | |
function init() { | |
ersteEbeneFunktionalisieren(); | |
initEbene2(); | |
hoehenErmitteln(); | |
zweiteEbeneFunktionalisieren(); | |
adaptWidths(); | |
unterMenuesVerstecken(); | |
/* | |
* Der IE zickt rum: erst beim 2. Aufruf der Funktion menuePunktAktion() funktioniert diese. | |
* Deshalb werden die Menüs "initialisiert" indem sie zunächst einmal ohne Grund aufgerufen | |
* werden | |
*/ | |
for (i= 0; i < hoehen.length; i++) { | |
unterMenueAuffahren(i,0); | |
} | |
} | |
/* | |
* Speichert die Höhen aller Untermenüs im Array hoehen. | |
* WICHTIG: Kann erst NACH der Funktion initEbene2() aufgerufen werden ! | |
* Durch Zuweisen eines Strings mit Textcharakter an jedes Element des hoehen-Arrays kann man auf | |
* bequeme Weise den Auffahreffekt abschalten. Gesteuert wird der Effekt über den Parameter | |
* "auffahreffektAn" | |
*/ | |
function hoehenErmitteln() { | |
for (i= 0; i < ebene2.length; i++) { | |
hoehen[i]= ebene2[i].offsetHeight; | |
} | |
if (!auffahreffektAn) { | |
for (j= 0; j < hoehen.length; j++) { | |
hoehen[j]= "Tobias Adam"; | |
} | |
} | |
} // end of hoehenErmitteln() | |
/* | |
* Diese Funktion trägt in die a-Tags der obersten Ebene zusätzlich folgende Attribute ein: | |
* onMouseOver="menuePunktAktion(menuePunktNummer)" | |
* onMouseOut="unterMenueAktionOut()" | |
* mit der entsprechenden Menüpunkt-Nummer | |
* Dabei hat der erste Eintrag die Menüpunkt-Nummer 0, der zweite die Nummer 1 usw. | |
*/ | |
function ersteEbeneFunktionalisieren() { | |
menuePunktZaehler= 0; | |
for (i= 0; i < ebene1.childNodes.length; i++) { | |
if (ebene1.childNodes[i].nodeName == "LI") { | |
for (j= 0; j < ebene1.childNodes[i].childNodes.length; j++) { | |
if (ebene1.childNodes[i].childNodes[j].nodeName == "A") { | |
// a-Node merken | |
aNode= ebene1.childNodes[i].childNodes[j]; | |
// a-Href-Attribut merken | |
aNodeHrefAttribute= aNode.getAttribute("href"); | |
// a-Id-Attribut merken | |
aNodeIdAttribute= aNode.getAttribute("id"); | |
// Text im a-Node merken | |
aNodeText= aNode.firstChild.data; | |
// ul-Node merken | |
var ulNode; | |
for (l= 0; l < ebene1.childNodes[i].childNodes.length; l++) { | |
if (ebene1.childNodes[i].childNodes[l].nodeName == "UL") { | |
ulNode= ebene1.childNodes[i].childNodes[l]; | |
} | |
} | |
// class-Attribute des UL-Node merken | |
ulNodeClassAttribute= ulNode.getAttribute("class"); | |
/* | |
* Der IE kann das Class-Attribut nur mit dem Bezeichner "className" auslesen, deshalb diese Abfrage | |
*/ | |
if (!ulNodeClassAttribute) ulNodeClassAttribute= ulNode.getAttribute("className"); | |
//Daten im UL-Node merken | |
ulNodeData= ulNode.innerHTML; | |
ebene1.childNodes[i].removeChild(aNode); | |
ebene1.childNodes[i].innerHTML= "<a href=\"" + aNodeHrefAttribute + "\" id=\"" + aNodeIdAttribute + "\" onMouseover=\"menuePunktAktion(" + menuePunktZaehler + ")\" onMouseout=\"unterMenueAktionOut()\">" + aNodeText + "</a><ul class=\"" + ulNodeClassAttribute + "\">" + ulNodeData + "</ul>"; | |
menuePunktZaehler++; | |
} | |
} | |
} | |
} | |
anzahlMenuePunkte= menuePunktZaehler; | |
} // end of ersteEbeneFunktionalisieren() | |
/* | |
* Diese Funktion liest in das Array ebene2 alle ul-Listen der 2. Ebene ein | |
*/ | |
function initEbene2() { | |
var arrayZaehler= 0; | |
for (i= 0; i < ebene1.childNodes.length; i++) { | |
if (ebene1.childNodes[i].nodeName == "LI") { | |
for (j= 0; j < ebene1.childNodes[i].childNodes.length; j++) { | |
if (ebene1.childNodes[i].childNodes[j].nodeName == "UL") { | |
ebene2[arrayZaehler]= ebene1.childNodes[i].childNodes[j]; | |
arrayZaehler++; | |
} | |
} | |
} | |
} | |
} // end of initEbene2() | |
/* | |
* Diese Funktion trägt in die a-Tags der zweiten Menü-Ebene zusätzlich folgende Attribute ein: | |
* onMouseOver="unterMenueAktionOver()" | |
* onMouseOut="unterMenueAktionOut()" | |
*/ | |
function zweiteEbeneFunktionalisieren() { | |
for (k= 0; k < ebene2.length; k++) { | |
for (i= 0; i < ebene2[k].childNodes.length; i++) { | |
if (ebene2[k].childNodes[i].nodeName == "LI") { | |
for (j= 0; j < ebene2[k].childNodes[i].childNodes.length; j++) { | |
if (ebene2[k].childNodes[i].childNodes[j].nodeName == "A") { | |
// a-Node merken | |
aNode= ebene2[k].childNodes[i].childNodes[j]; | |
// a-Href-Attribut merken | |
aNodeHrefAttribute= aNode.getAttribute("href"); | |
// a-Id-Attribut merken | |
aNodeIdAttribute= aNode.getAttribute("id"); | |
// Text im a-Node merken | |
aNodeText= aNode.firstChild.data; | |
ebene2[k].childNodes[i].removeChild(aNode); | |
ebene2[k].childNodes[i].innerHTML= "<a href=\"" + aNodeHrefAttribute + "\" id=\"" + aNodeIdAttribute + "\" onMouseover=\"unterMenueAktionOver()\" onMouseout=\"unterMenueAktionOut()\">" + aNodeText + "</a>"; | |
} | |
} | |
} | |
} | |
} | |
} // end of zweiteEbeneFunktionalisieren() | |
function unterMenuesVerstecken() { | |
for (i= 0; i < ebene2.length; i++) { | |
ebene2[i].style.visibility= "hidden"; | |
} | |
} // end of unterMenuesVerstecken | |
function unterMenueAufdecken(menueNummer) { | |
ebene2[menueNummer].style.visibility= "visible"; | |
} // end of unterMenueAufdecken | |
function menuePunktAktion(menueNummer) { | |
if (ersterProzessGestartet) { | |
clearTimeout(prozess); | |
} | |
// if-Abfrage notwendig um mehrfaches Öffnen beim Überfahren des gleichen Menüpunkts zu vermeiden | |
if (menueNummer != zuletztGeoeffneteMenueNummer) { | |
zuletztGeoeffneteMenueNummer= menueNummer; | |
unterMenuesVerstecken(); | |
startPosition= - hoehen[menueNummer]; | |
hoehe= hoehen[menueNummer]; | |
unterMenueAufdecken(menueNummer); | |
zeitSchritte= 1; //reset der Zeitschritte | |
unterMenueAuffahren(menueNummer,startPosition); | |
} | |
} // end of function menuePunktAktion() | |
function unterMenueAuffahren(menueNummer,anfangsPosition) { | |
if (anfangsPosition <= 0) { | |
if (prozess2An) clearTimeout(prozess2); | |
/* Original: unterMenuePositionieren(menueNummer,anfangsPosition); */ | |
/* angepasst */ | |
unterMenuePositionieren(menueNummer,anfangsPosition + 3); | |
/* angepasst */ | |
neuePosition= Math.round(- hoehen[menueNummer]*Math.exp(-(zeitSchritte/iterationen))); | |
zeitSchritte++; | |
prozess2= setTimeout("unterMenueAuffahren(" + menueNummer + "," + neuePosition + ")",verzoegerung); | |
prozess2An= true; | |
} | |
} // end of function unterMenueAuffahren | |
/* | |
* Die Position wird relativ zur "normalen" Position angegeben (die Position, die per CSS angegeben | |
* wurde) | |
*/ | |
function unterMenuePositionieren(menueNummer,position) { | |
stil= ebene2[menueNummer].style; | |
stil.position= "relative"; | |
stil.top= position + "px"; | |
} // end of unterMenuePositionieren | |
function unterMenueAktionOver() { | |
if (ersterProzessGestartet) { | |
clearTimeout(prozess); | |
} | |
} | |
function unterMenueAktionOut() { | |
prozess= setTimeout("tatsaechlichSchliessen()",500); | |
ersterProzessGestartet= true; | |
} | |
function tatsaechlichSchliessen() { | |
unterMenuesVerstecken(); | |
zuletztGeoeffneteMenueNummer= -1; | |
} | |
function getChildsNamed(node,tagName) { | |
var childs= new Array(); | |
var arrayCount= 0; | |
for (i= 0; i < node.childNodes.length; i++) { | |
//alert(node.childNodes[i].nodeName); | |
if (node.childNodes[i].nodeName == tagName) { | |
childs[arrayCount]= node.childNodes[i]; | |
//alert(arrayCount); | |
arrayCount++; | |
} | |
} | |
return childs; | |
} | |
function getFirstChildNamed(node,tagName) { | |
for (i= 0; i < node.childNodes.length; i++) { | |
if (node.childNodes[i].nodeName == tagName) { | |
return node.childNodes[i]; | |
} | |
} | |
return false; | |
} | |
/* | |
* Diese Funktion passt die Breite der einzelnen Untermenüs an die Breite des jeweils größten Eintrags an. | |
* Um eine Browser-übergreifende Kompatibilität zu erreichen werden nicht direkt die offsetWidths ausgelesen, da diese vom | |
* FF nicht richtig verstanden werden, wenn Textelemente das sie umgebende Element verlassen; der IE streckt dagegegen das | |
* ihn umgebende Element | |
* Zur Lösunmg des Problems wird die Anzahl der Buchstaben der einzelnen Einträge ausgelesen und diese Anzahl dann mit einer | |
* mittleren Buchstabenbreite multipliziert, um eine annähernd angepasste Breite zu bekommen. | |
*/ | |
function adaptWidths() { | |
var ulTag1= document.getElementById("ersteListe"); | |
liTags1= getChildsNamed(ulTag1,"LI"); | |
// jedes liChild hat genau ein ul-Child, deshalb wird ein gleichgroßes Array ulTags2 erstellt | |
var ulTags2= new Array(); | |
for (j= 0; j < liTags1.length; j++) { | |
ulTags2[j]= getFirstChildNamed(liTags1[j],"UL"); | |
} | |
// jedes ulTag hat mehrere liTags, deshalb gibt es jeweils ein Array aus liTags | |
var liTags2= new Array(); | |
for (j= 0; j < ulTags2.length; j++) { | |
liTags2[j]= getChildsNamed(ulTags2[j],"LI"); | |
} | |
// jedes dieser liTags hat ein aTag | |
// der IE kann daraus bereits die richtige Offset-Width berechnen | |
var aTags= new Array(liTags2.length); | |
for (i= 0; i < liTags2.length; i++) { | |
aTags[i]= new Array(liTags2[i].length); | |
} | |
for (j= 0; j < liTags2.length; j++) { | |
for (k= 0; k < liTags2[j].length; k++) { | |
aTags[j][k]= getFirstChildNamed(liTags2[j][k],"A"); | |
} | |
} | |
// die entsprechenden OffsetWidths abspeichern im Array offsetWidths | |
var offsetWidths= new Array(aTags.length); | |
for (i= 0; i < aTags.length; i++) { | |
offsetWidths[i]= new Array(aTags[i].length); | |
} | |
for (j= 0; j < aTags.length; j++) { | |
for (k= 0; k < aTags[j].length; k++) { | |
offsetWidths[j][k]= parseInt(aTags[j][k].offsetWidth); | |
} | |
} | |
/* Diese hier ausgeklammerte Lösung funktioniert ausschließlich für den IE und auch nur dann, wenn umgebenden ul-Tags eine | |
* sehr kleine width bekommen, so dass der IE das umgebende ul auf die richtige Größe streckt | |
*/ | |
/* | |
var biggestWidths= new Array(offsetWidths.length); | |
for (i= 0; i < biggestWidths.length; i++) { | |
biggestWidths[i]= -1; | |
} | |
for (i= 0; i < offsetWidths.length; i++) { | |
for (j= 0; j < offsetWidths[i].length; j++) { | |
if (offsetWidths[i][j] > biggestWidths[i]) { | |
biggestWidths[i]= offsetWidths[i][j]; | |
} | |
} | |
} | |
for (i= 0; i < aTags.length; i++) { | |
for (j= 0; j < aTags[i].length; j++) { | |
aTags[i][j].style.width= biggestWidths[i]; | |
} | |
} | |
*/ | |
/* Dies ist die oben angesprochene weniger exakte, dafür aber allgemeingültige Lösung, die mit dem FF und dem IE | |
* funktioniert | |
*/ | |
// hier werden die textNodes referenziert und im 2-dim. Array textNodes gespeichert | |
var textNodes= new Array(aTags.length); | |
for (i= 0; i < aTags.length; i++) { | |
textNodes[i]= new Array(aTags[i].length); | |
} | |
for (j= 0; j < aTags.length; j++) { | |
for (k= 0; k < aTags[j].length; k++) { | |
textNodes[j][k]= aTags[j][k].firstChild; | |
} | |
} | |
// die entsprechenden Buchstabenanzehlen der textNodes werden im 2-dim. Array textLengths gespeichert | |
var textLengths= new Array(textNodes.length); | |
for (i= 0; i < textNodes.length; i++) { | |
textLengths[i]= new Array(textNodes[i].length); | |
} | |
for (i= 0; i < textLengths.length; i++) { | |
for (j= 0; j < textLengths[i].length; j++) { | |
textLengths[i][j]= textNodes[i][j].nodeValue.length; | |
} | |
} | |
// die jeweils größte Buchstabenanzahl einer Kategorie wird im Array biggestTLength gespeichert | |
var biggestTLength= new Array(textLengths.length); | |
for (i= 0; i < biggestTLength.length; i++) { | |
biggestTLength[i]= 0; | |
} | |
for (i= 0; i < textLengths.length; i++) { | |
for (j= 0; j < textLengths[i].length; j++) { | |
if (textLengths[i][j] > biggestTLength[i]) { | |
biggestTLength[i]= textLengths[i][j]; | |
} | |
} | |
} | |
// es wird eine durchschnittliche Buchstabenbreite von 8 Pixeln angenommen | |
var averageLetterWidth= 8; | |
/* den ulTags der Unterkategorien und den in Ihnen beinhalteten a-Tags werden die maximalen Breiten ihrer jeweiligen | |
* Kategorie zugewiesen | |
*/ | |
for (i= 0; i < ulTags2.length; i++) { | |
ulTags2[i].style.width= ((biggestTLength[i] * averageLetterWidth) + 6) + "px"; | |
} | |
for (i= 0; i < aTags.length; i++) { | |
for (j= 0; j < aTags[i].length; j++) { | |
aTags[i][j].style.width= biggestTLength[i] * averageLetterWidth + "px"; | |
} | |
} | |
// hier wird noch die Position des letzten Menüpunktes so korrigiert, dass er nicht nach rechts über den Rand hinausgeht | |
// Breite des letzten Kategoriepunkts ermitteln | |
var letzterMenuePunkt= getFirstChildNamed(liTags1[liTags1.length - 1],"A"); | |
var letzterMenuePunktWidth= letzterMenuePunkt.offsetWidth; | |
var diff= letzterMenuePunktWidth - (biggestTLength[biggestTLength.length - 1] * 8); | |
ulTags2[ulTags2.length - 1].style.left= (diff - 20) + "px"; | |
} // end of adaptWidths() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment