![]() |
Lutz Eymers
|
|
| |
| E-Mail: | |
|---|---|
| Homepage-URL: |
Bei Fragen zu diesem Beitrag bitte den Autor des Beitrags kontaktieren!
Hierarchische Ordnerstruktur mit Javascript
Wenn man tief verzweigte hierarchische Verzeichnisstrukturen auf übersichtliche Weise darstellen möchte, kommt einem schnell die Darstellungsweise der Desktop Window Manager (Macintosh Finder, Irix 4Dwm, CDE, KDE) oder der MS-Explorer in den Sinn: Ordner werden per Mausklick auf- und zugeklappt, die Verzeichnisstruktur und Verzweigungen werden durch Einrücken dargestellt.
Wir haben ein Javascript Programm entwickelt, das die Darstellungsweise eines Desktop Window Managers oder eines Explorers nachahmt und per Mausklick die Verzeichnisstruktur aufklappt. Dieses Javascript Programm findet unserer Meinung nach die ideale Anwendung als Sitemap.
Voraussetzung für eine einwandfreie Funktionsweise sind Javascript 1.2 und CSS/Layers, also Netscape 4.0 oder höher bzw. MSIE 4.0 oder höher.
Das Script sollte im Kopf der HTML-Datei notiert werden, welche die Sitemap darstellt.
<SCRIPT language="JavaScript1.2">
<!--
/*
* sitemap.js 1.31 05/02/2000
* - Opera 5
*
* sitemap.js 1.3 27/11/2000
* - Netscape 6
*
* sitemap.js 1.2 20/05/2000
* - split array tree into arrays for each element old tree
* - no mory type flag, an folder is an entry which has sons
* - a folder can have an link
* - while initing an default layers is shown
*
* sitemap.js 1.1 20/10/1999
* - showTree only updates and init layers new which have been really changed
* - add deep to knot entry
* - substitute knotDeep[ id ] w/ tree[ id2treeIndex[ id ] ].deep
* - add alignment to img and a at the beginning of eyery line
* - add a fake img for bookmarks on top panel
*
* sitemap.js 1.02 14/10/1999
* - fix bug in initStyles
*
* sitemap.js 1.01 06/10/1999
* - fix bug in knotDeep for Netscape 4.00-4.0.5
*
* sitemap.js 1.0 20/09/1999
*
* Javascript function for displaying hierarchic directory structures with
* the ability to collapse and expand directories.
*
* Copyright (c) 1999 Polzin GmbH, Duesseldorf. All Rights Reserved.
* Author: Lutz Eymers <ixtab@polzin.com>
* Download: http://www.polzin.com/inet/fset_inet.phtml?w=goodies
*
* Permission to use, copy, modify, and distribute this software
* and its documentation for any purposes and without fee
* is hereby granted provided that this copyright notice
* appears in all copies.
*
* Of course, this software is provided "as is" without express or implied
* warranty of any kind.
*
*/
window.onError=null;
var idx=0
var treeId = new Array();
var treeP_id = new Array();
var treeIsOn = new Array();
var treeTyp = new Array();
var treeName = new Array();
var treeUrl = new Array();
var treeWasOn = new Array();
var treeDeep = new Array();
var treeLastY = new Array();
var treeIsShown = new Array();
function Note( id,p_id,name,url ) {
treeId[ idx ] = id
treeP_id[ idx ] = p_id
treeIsOn[ idx ] = false
treeTyp[ idx ] = 'f'
treeName[ idx ] = name
treeUrl[ idx ] = url
treeWasOn[ idx ] = false
treeDeep[ idx ] = 0
treeLastY[ idx ] = 0
treeIsShown[ idx ] = false
idx++
}
function initDiv ( )
{
if ( isDOM || isDomIE )
{
divPrefix='<DIV CLASS="sitemap" style="position:absolute; left:0; top:0; visibility:hidden;" ID="sitemap'
divInfo='<DIV CLASS="sitemap" style="position:absolute; visibility:visible" ID="sitemap'
}
else
{
divPrefix='<DIV CLASS="sitemap" ID="sitemap'
divInfo='<DIV CLASS="sitemap" ID="sitemap'
}
document.writeln( divInfo + 'info">Bitte haben Sie etwas Geduld.<BR> <BR>Es werden die Einträge aus<BR> <BR>der Datenbank initialisiert.</DIV> ' );
for ( var i=1; i<idx; i++ )
{
// linked Name ?
if ( treeUrl[i] != '' )
linkedName = '<A HREF="' + treeUrl[i] + '" TARGET="' + defaultTarget + '"><IMG SRC="1w.gif" BORDER="0" WIDTH="3">' + treeName[i] + '</A>'
else
linkedName = '<IMG SRC="1w.gif" BORDER="0" WIDTH="3">' + treeName[i]
// don't link folder icon if node has no sons
if ( i == idx-1 || treeP_id[i+1] != treeId[i] ) {
if ( treeDeep[ i ] == 0 )
folderImg = '<IMG ALIGN="BOTTOM" SRC="file_empty.gif" BORDER="0" HEIGHT="16" WIDTH="1" HSPACE="0">'
else
folderImg = ''
} else {
folderImg = '<A HREF="javascript:sitemapClick(' + treeId[i] + ')"><IMG ALIGN="BOTTOM" SRC="folder_off.gif" BORDER="0" NAME="folder' + treeId[i] + '" HEIGHT="16" WIDTH="30" HSPACE="0"></A>'
}
// which type of file icon should be displayed?
if ( treeP_id[i] != 0 )
{
if ( lastEntryInFolder( treeId[i] ) )
fileImg = '<IMG ALIGN="BOTTOM" SRC="file_last.gif" BORDER="0" NAME="file'
+ treeId[i] + '" HEIGHT="16" WIDTH="30" HSPACE="0">'
else
fileImg = '<IMG ALIGN="BOTTOM" SRC="file.gif" BORDER="0" NAME="file'
+ treeId[i] + '" HEIGHT="16" WIDTH="30" HSPACE="0">'
}
else
fileImg = ''
// traverse parents up to root and show vertical lines if parent
// is not the last entry on this layer
verticales = ''
for( var act_id=treeId[i] ; treeDeep[ id2treeIndex[ act_id ] ] > 1; )
{
act_id = treeP_id[ id2treeIndex[ act_id ]]
if ( lastEntryInFolder( act_id ) )
{
verticales = '<IMG ALIGN="BOTTOM" SRC="file_empty.gif" BORDER="0" HEIGHT="16" WIDTH="30" HSPACE="0">' + verticales
}
else
{
verticales = '<IMG ALIGN="BOTTOM" SRC="file_vert.gif" BORDER="0" HEIGHT="16" WIDTH="30" HSPACE="0">' + verticales
}
}
document.writeln( divPrefix + treeId[i] + '"><NOBR> ' + verticales + fileImg + folderImg + linkedName + '</NOBR></DIV><BR>'
)
}
}
function initStyles ( )
{
document.writeln( '<STYLE TYPE="text/css">' + "\n" + '<!--' )
for ( var i=1,y=y0; i<idx; i++ )
{
document.writeln( '#sitemap' + treeId[i] + ' {POSITION: absolute; VISIBILITY: hidden;}' )
if ( treeIsOn[ id2treeIndex[ treeP_id[i] ] ] )
y += deltaY
}
document.writeln( '#sitemapinfo {POSITION: absolute; VISIBILITY: visible;}' )
document.writeln( '//-->' + "\n" + '</STYLE>' )
}
function sitemapClick( id )
{
var i = id2treeIndex[ id ]
if ( treeIsOn[ i ] )
// close directory
{
// mark node as invisible
treeIsOn[ i ]=false
// mark all sons as invisible
actDeep = treeDeep[ i ]
for( var j=i+1; j<idx && treeDeep[j] > actDeep; j++ )
{
treeWasOn[ j ] = treeIsOn[ j ]
treeIsOn[ j ]=false
}
gif_off( id )
}
else
// open directory
{
treeIsOn[ i ]=true
// remember and restore old status
actDeep = treeDeep[ i ]
for( var j=i+1; j<idx && treeDeep[j] > actDeep; j++ )
{
treeIsOn[ j ] = treeWasOn[ j ]
}
gif_on( id )
}
showTree()
}
function knotDeep( id )
{
var deep=0
while ( true )
if ( treeP_id[ id2treeIndex[id] ] == 0 )
return deep
else
{
++deep
id = treeP_id[ id2treeIndex[id] ]
}
return deep
}
function initTree( id )
{
treeIsOn[ id2treeIndex[id] ] = true
if ( treeTyp[ id2treeIndex[id] ] != 'b' )
gif_on( id )
while ( treeP_id[ id2treeIndex[id] ] != 0 )
{
id = treeP_id[ id2treeIndex[id] ]
treeIsOn[ id2treeIndex[id] ] = true
if ( treeTyp[ id2treeIndex[id] ] != 'b' )
gif_on( id )
}
}
function lastEntryInFolder( id )
{
var i = id2treeIndex[id]
if ( i == idx-1 )
return true
if ( treeTyp[i] == 'b' )
{
if ( treeP_id[i+1] != treeP_id[i] )
return true
else
return false
}
else
{
var actDeep = treeDeep[i]
for( var j=i+1; j<idx && treeDeep[j] > actDeep ; j++ )
;
if ( j<idx && treeDeep[j] == actDeep )
return false
else
return true
}
}
function showTree()
{
for( var i=1, y=y0, x=x0; i<idx; i++ )
{
if ( treeIsOn[ id2treeIndex[ treeP_id[i] ] ] )
{
// show current node
if ( !(y == treeLastY[i] && treeIsShown[i] ) )
{
showLayer( "sitemap"+ treeId[i] )
setyLayer( "sitemap"+ treeId[i], y )
treeIsShown[i] = true
}
treeLastY[i] = y
y += deltaY
}
else
{
// hide current node and all sons
if ( treeIsShown[ i ] )
{
hideLayer( "sitemap"+ treeId[i] )
treeIsShown[i] = false
}
}
}
}
function initIndex() {
for( var i=0; i<idx; i++ )
id2treeIndex[ treeId[i] ] = i
}
function gif_name (name, width, height) {
this.on = new Image (width, height);
this.on.src = name + "_on.gif"
this.off = new Image (width, height);
this.off.src = name + "_off.gif"
}
function load_gif (name, width, height) {
gif_name [name] = new gif_name (name,width,height);
}
function load_all () {
load_gif ('folder',30,16)
file_last = new Image( 30,16 )
file_last.src = "file_last.gif"
file_middle = new Image( 30,16 )
file_middle.src = "file.gif"
file_vert = new Image( 30,16 )
file_vert.src = "file_vert.gif"
file_empty = new Image( 30,16 )
file_empty = "file_empty.gif"
}
function gif_on ( id ) {
eval("document['folder" + id + "'].src = gif_name['folder'].on.src")
}
function gif_off ( id ) {
eval("document['folder" + id + "'].src = gif_name['folder'].off.src")
}
// global configuration
var deltaX = 30
var deltaY = 16
var x0 = 5
var y0 = 5
var defaultTarget = 'examplemain'
var browserName = navigator.appName;
var browserVersion = parseInt(navigator.appVersion);
var isIE = false;
var isNN = false;
var isDOM = false;
var isDomIE = false;
var isDomNN = false;
var layerok = false;
var isIE = browserName.indexOf("Microsoft Internet Explorer" )==-1?false:true;
var isNN = browserName.indexOf("Netscape")==-1?false:true;
var isOpera = browserName.indexOf("Opera")==-1?false:true;
var isDOM = document.getElementById?true:false;
var isDomNN = document.layers?true:false;
var isDomIE = document.all?true:false;
if ( isNN && browserVersion>=4 ) layerok=true;
if ( isIE && browserVersion>=4 ) layerok=true;
if ( isOpera && browserVersion>=5 ) layerok=true;
function hideLayer(layerName) {
if (isDOM)
document.getElementById(layerName).style.visibility="hidden"
else if (isDomIE)
document.all[layerName].style.visibility="hidden";
else if (isDomNN)
document.layers[layerName].visibility="hidden";
}
function showLayer(layerName) {
if (isDOM)
document.getElementById(layerName).style.visibility="visible"
else if (isDomIE)
document.all[layerName].style.visibility="visible";
else if (isDomNN)
document.layers[layerName].visibility="visible";
}
function setyLayer(layerName, y) {
if (isDOM)
document.getElementById(layerName).style.top=y
else if (isDomIE)
document.all[layerName].style.top=y;
else if (isDomNN)
document.layers[layerName].top=y;
}
var id2treeIndex = new Array()
// the structure is easy to understand with a simple example
// p_id is the id of the parent
// E0 ( id=0,p_id=-1 )
// E11 ( id=1,p_id=0)
// E111 ( id=2,p_id=1 )
// E112 ( id=3,p_id=1 )
// E12 ( id=4,p_id=0 )
// E121 ( id=5,p_id=4 )
// E13 ( id=6,p_id=0 )
// E131 ( id=7,p_id=6 )
// E1311 ( id=8,p_id=7 )
// E132 ( id=9,p_id=6 )
// this is a multinary tree structure which is easy to
// populate with database data :)
function initArray()
{
Note(0,-1,'','')
Note(1,0,'Tutorials','')
Note(8,1,'HTML','')
Note(10,8,'SelfHtml','http://de.selfhtml.org/')
Note(3,1,'JavaScript','')
Note(4,3, 'Netscape Guide 1.3','http://developer.netscape.com/docs/manuals/js/client/jsguide/index.htm')
Note(7,3, 'Introduction to Javascript','http://rummelplatz.uni-mannheim.de/~skoch/js/script.htm')
Note(12,1, 'Perl','')
Note(14,12, 'Perl Tutorial','http://www.awu.id.ethz.ch/~didi/perl/perl_start.html')
Note(13,1,'SQL','')
Note(15,13, 'Introduction to SQL','http://w3.one.net/~jhoffman/sqltut.htm')
Note(2,0, 'Reference Manuals','http://www.cls-online.de/htmlref/index.html')
Note(11,2, 'HTML Version 3.2 Referenz','http://www.cls-online.de/htmlref/index.htm')
Note(6,2,'Netscape Reference 1.3','http://developer.netscape.com/docs/manuals/js/client/jsref/index.htm')
Note(17,2,'PHP Manual','http://www.php.net/manual/html/')
treeTyp[0] = 'f'
treeIsOn[0] = true
treeWasOn[0] = true
}
var idx=0
initArray()
initIndex()
load_all()
for( i=1; i<idx; i++ )
{
treeDeep[i] = knotDeep( treeId[i] )
if ( treeDeep[i] == 0 )
treeIsShown[i] = true
}
if ( isDomNN )
initStyles();
//--></SCRIPT>
Die JavaScript Funktion muß innerhalb derselben Datei im Body-Tag initialisiert werden.
<BODY VLINK="#000000" LINK="#000000" BGCOLOR="#ffffff" TEXT="#000000"
onLoad="if (layerok) showTree();">
<SCRIPT language="JavaScript1.2">
<!--
initDiv()
hideLayer("sitemapinfo")
//--></SCRIPT>
</BODY>
Wenn die Sitemap in einem eigenen Fenster geöffnet werden soll, kann man das Fenster mit folgender Funktion referenzieren. Die Funktion kann wahlweise im Body-Tag über onLoad oder innerhalb des Bodies als Link eingesetzt werden.
<SCRIPT LANGUAGE="Javascript">
<!--
var lastopen = "quot;"quot;;
var sitemapwin;
var bver = "quot;nn2"quot;;
var browserName = navigator.appName;
var browserVersion = parseInt(navigator.appVersion);
var isIE = browserName.indexOf("quot;Microsoft Internet Explorer"quot; )==-1?false:true;
var isNN = browserName.indexOf("quot;Netscape"quot;)==-1?false:true;
var isOpera = browserName.indexOf("quot;Opera"quot;)==-1?false:true;
var isDOM = document.getElementById?true:false;
var isDomNN = document.layers?true:false;
var isDomIE = document.all?true:false;
if ( isNN && browserVersion >gt;= 3) bver = "quot;nn3"quot;;
if ( isNN && browserVersion >gt;= 4) bver = "quot;nn4"quot;;
if ( isNN && browserVersion >gt;= 5) bver = "quot;nn5"quot;;
if ( isIE && browserVersion >gt;= 3) bver = "quot;ms3"quot;;
if ( isIE && browserVersion >gt;= 4) bver = "quot;ms4"quot;;
if ( isIE && browserVersion >gt;= 5) bver = "quot;ms5"quot;;
if ( isOpera && browserVersion >gt;= 5) bver = "quot;op5"quot;;
function openmap(startpage) {
if (bver == "quot;nn4"quot; || bver == "quot;nn5"quot; || bver == "quot;op5"quot;) {
sitemapwin=window.open(startpage,'polzinsitemap','resizable=no,scrolling=no,status=no,location=no,menubar=no,toolbar=no,width=300,height=400');
sitemapwin.focus();
}
if (bver == "quot;ms4"quot; || bver == "quot;ms5"quot; ) {
sitemapwin=window.open(startpage,'polzinsitemap','resizable=no,scrolling=no,status=no,location=no,menubar=no,toolbar=no,width=300,height=388');
setTimeout('sitemapwin.focus()',200);
}
}
function openorfocus ( startpage ) {
if ( typeof( sitemapwin ) != 'undefined' ) {
if ( ! sitemapwin.closed && startpage==lastopen ) sitemapwin.focus();
else openmap( startpage );
}
else openmap( startpage );
lastopen = startpage
}
function closesitemap() {
if ( typeof( sitemapwin ) != 'undefined' )
if ( ! sitemapwin.closed )
sitemapwin.close()
}
//-->
</SCRIPT>
<A HREF="javascript:openorfocus()">Sitemap öffnen</A>
Es folgt eine kurze Übersicht über die definierten Funktionen
Note( id,p_id,isOn,typ,name,url ) : Initialisieren eines einzelnen KnotensinitDiv ( ) : erzeugt mittels document.write die <DIV> UmgebungeninitStyles ( ) : erzeugt mittels document.write die <STYLE> UmgebungensitemapClick( id ) : behandelt das Öffnen und Schließen eines VerzeichnissesknotDeep( id ) : liefert die Knotentiefe zurücklastEntryInFolder( id ) : wahr, wenn der zur ID gehöhrende Knote der letzte Sohn seines Vaters ist, ansonsten falschshowTree() : stellt die Sitemap dar, indem sie alle Knoten anzeigt, deren Väter sichtbar sindinitIndex() : initialisiert das Referenzarray id2treeIndex[], welches für eine ID den entsprechenden Index i zurückliefert gif_name (name, width, height) : initialisiert Imageobjekte load_gif (name, width, height) : Abspeichern der initialisierten Imageobjekte in einem Arrayload_all () : alle Images in den Cache ladengif_on ( id ) : das Bild für ein geöffnetes Verzeichnis im entsprechenden Layer einblendengif_off : das Bild für ein geschlossenes Verzeichnis im entsprechenden Layer einblendenshowLayer( name ) : Layer einblendenhideLayer( name ) : Layer ausblendensetyLayer( name, y ) : Layer positionierenopenmap(startpage) : ein neues Windowobject für die Sitemap öffnen openorfocus () : wenn das Windowobject Sitemap noch existiert, wird es in den Vordergrund geholt, andernfalls neu geöffnetclosesitemap () : schliessen der SitemapDer Inhalt für die Sitemap wird in dem linearen Array tree[] gespeichert und implementiert eine q-näre Baumstruktur. Jeder Knoten dieses Baums kann beliebig viele Söhne haben. Der oberste Knoten ist der mit dem Index 0. Beim Auffüllen dieses Array ist zu beachten, das eine festgelegte Reihenfolge beachtet werden muß. Man könnte die zu erwartende Struktur durch eine zusätzliche JavaScriptfunktion ein wenig verallgemeinern. Allerdings stellt die vorliegende Struktur keine inhaltliche Einschränkung dar. Idealerweise werden die zu ladenden Daten nicht manuell eingetragen, sondern mit einer serverseitigen rekursiven Funktion sortiert, z.B. wenn man das Array mit Werten aus einer Datenbank auffüllt.
Man trägt einfach von oben nach unten Zeile für Zeile einer vollaufgeklappten Sitemap Knoten für Knoten nacheinander in das Array ein, wie es im Beispiel auch getan wird. Wenn man für den Index immer den Wert i++ verwendet, läßt sich auf diese Weise elegant und ohne zusätzlichen Aufwand ein neuer Folder oder Bookmark an einer beliebigen Stelle nachträglich hinzufügen.
Die Sitemap im Explorer- bzw. Streifenlayout öffnen.
(JavaScript-Verweise - bitte normal mit linker Maustaste anklicken!)
sitemap.zip downloaden
(enthält alle erforderlichen Dateien)