| E-Mail: |
|---|
Bei Fragen zu diesem Beitrag bitte den Autor des Beitrags kontaktieren!
Nach jahrelangem Ausbeuten der Quelle "Münz & SELFHTML" soll mit diesem Artikel etwas zurückfließen. Die JavaScript-Codes auf dieser Seite sind frei verfügbar und erweiterbar. Qualifizierte Beiträge und/oder gutgemeinte Hinweise zu diesem Artikel werden gerne entgegengenommen und beantwortet.
Zum Schreiben eines eigenen table-Objektes kam ich, nachdem ich sehr oft dynamischen Inhalt auf der Clientseite generieren musste. Die Tabelle ist für mich in HTML noch immer das Gestaltungsmittel Nummer 1 für Webseiten, und da es auf Dauer nicht sehr komfortabel war, für die unterschiedlichsten Layouts die komplexen Scripts zum Erzeugen eines HTML-Codes immer wieder umzuschreiben, wuchs der Wunsch, diesem Mißstand endlich mit einem gut manipulierbaren table-Objekt abzuhelfen. Diesen Komfort sollte mir das Objekt mindestens bieten:
Das hier vorgestellte table-Objekt besteht aus verschiedenen Methoden und einer Konstruktorfunktion. Das folgende Einführungsbeispiel zeigt eine HTML-Datei, in der eine kleine Tabelle mit Hilfe des table-Objekts erzeugt wird.
Anzeigebeispiel: So sieht's aus
<html>
<head>
<title>tableClass</title>
<script language = "JavaScript" type="text/javascript">
<!--
// *********** hier sollte der JavaScript-Code des table-Objekts notiert werden ***********
// *********** wird hier der Uebersichtlichkeit halber weggelassen ***********
var meineTabelle = new table('cols="2"','rows="2"','border="1"','bgcolor="#FFFFCC"');
meineTabelle.contentArraysToArguments();
meineTabelle.content[0][0].value = "<b>Berlin</b>";
meineTabelle.content[0][1].value = "<b>Hamburg</b>";
meineTabelle.content[1][0].value = "3 Millionen";
meineTabelle.content[1][1].value = "2 Millionen";
//-->
</script>
</head>
<body>
<script language="JavaScript" type="text/javascript">
<!--
meineTabelle.contentArgumentsToArrays();
document.write(meineTabelle.draw());
//-->
</script>
</body>
</html>
Es wird eine kleine Tabelle mit zwei Zeilen und zwei Spalten erzeugt. In Statements wie meineTabelle.content[0][0].value = "<b>Berlin</b>"; wird ersichtlich, daß das Errichten der Tabelle gar nicht so schwer ist. Innerhalb des body-Bereichs der HTML-Datei ist ein zweiter JavaScript-Bereich notiert, in dem die erzeugte Tabelle an der gewünschten Stelle mit dem Statement document.write(meineTabelle.draw()) eingefügt wird.
In den beiden folgenden Abschnitten wird beschrieben, wie das table-Objekt aus Programmierersicht verwendet wird. Im Anschluß daran werden zum besseren Verständnis die einzelnen Funktionen beschrieben, die zum table-Objekt gehören. Am Ende dieser Seite finden Sie den
vollständigen Code des table-Objekts zum Kopieren. Diesen Code müssen Sie in Ihr eigenes JavaScript an die Stelle so kopieren wie oben im Beispiel markiert.
Der Konstruktor ist in der objektorientierten Programmierung eine Funktion, die bei einem Aufruf mit dem Operator new ein neues Objekt eines bestimmten Typs erzeugt. Bei unserem table-Objekt handelt es sich dabei um die Funktion table().
var meineTabelle01 = new table();
var meineTabelle02 = new table('cols="7"','rows="3"');
var meineTabelle03 = new table('cols="9"','rows="7"','width="300"','height="100"',
'border="1"','bgcolor="#FF9900"',
'name="testTable03"','id="tab03"');
var meineTabelle04 = new table('cols="6"','rows="10"','cellspacing="0"','cellpadding="1"'
'border="0"','bgcolor="#ffcc00"',
'name="testTable04"','id="tab04"');
Alle Objekte des Typs table werden durch Aufruf der Konstruktor-Funktion new table() erzeugt. Das erste der Beispiele zeigt, wie die Funktion ohne Parameter aufgerufen wird. In diesem Fall erhält die Tabelle keine weiteren Eigenschaften. Das table-Objekt bietet jedoch wesentlich mehr und erlaubt es, gleich beim Erzeugen der Tabelle verschiedene Angaben zu deren Eigenschaften zu machen, und zwar in Form von String-Parametern, die der Konstruktor-Funktion übergeben werden. Denn das Angenehme an dem Konstruktor ist, daß sich alle Eigenschaften einer Tabelle in Anzahl und Reihenfolge völlig frei wählen lassen. Die weiteren Aufrufbeispiele oben zeigen dies.
Unter Verwendung von Zeilen- und Spaltenparametern läßt sich direkt auf die Zellen einer zuvor erzeugten Tabelle zugreifen. Auf diese Weise läßt sich die Tabelle exakt formatieren und mit Inhalt füllen.
meineTabelle.content[0][0][1] = "<b>Variable</b>"; meineTabelle.content[0][1][1] = "<b>Wert</b>"; meineTabelle.content[1][0][1] = "Browser"; meineTabelle.content[1][1][1] = navigator.appName; meineTabelle.content[2][0][1] = "Name dieser Tabelle"; meineTabelle.content[2][1][1] = meineTabelle.name; meineTabelle.content[0][0][0] = 'align="center" bgcolor="#EEEEEE"'; meineTabelle.content[0][1][0] = 'align="center" bgcolor="#EEEEEE"'; meineTabelle.content[1][0][0] = 'bgcolor="#FFFFCC"'; meineTabelle.content[1][1][0] = 'bgcolor="#CCFFFF"'; meineTabelle.content[2][0][0] = 'bgcolor="#FFFFCC"'; meineTabelle.content[2][1][0] = 'bgcolor="#CCFFFF"';
Die Indizes x, y, z im Array Tabellenvariable.content[x][y][z] stehen für folgende Zelleneigenschaften:
x: Nummer der Zeile, bei 0 für 1. Zeile beginnendy: Nummer der Spalte, bei 0 für 1. Spalte beginnendz: Flag für Zelleneigenschaften:
0 steht für die Attribute der ausgewählten Zelle (also für <td ...></td>)1 steht für die Inhalte der ausgewählten Zelle (der Inhalt zwischen <td>...</td>)Der zugewiesene Inhalt kann beliebige Zeichenketten enthalten, in denen auch HTML-Code notiert sein kann. Auch Zeichenketten, die von JavaScript-Methoden oder -Eigenschaften zurückgeliefert werden, sind als Inhalt möglich, ebenso zusammengesetzte Zeichenketten.
Bei den Attributzuweisungen sind alle Attribute erlaubt, die ein <td>-Tag enthalten kann.
Anstelle der dritten Zahl, die darüber entscheidet, ob der zugewiesene Wert ein Attribut-Inhalt (0) oder der Inhalt der Zelle (1) ist, können Sie auch die Eigenschaften props und value verwenden. Dann wird alles wie folgt notiert:
meineTabelle.contentArraysToArguments(); meineTabelle.content[0][0].value = "<b>Variable</b>"; meineTabelle.content[0][1].value = "<b>Wert</b>"; meineTabelle.content[1][0].value = "Browser"; meineTabelle.content[1][1].value = navigator.appName; meineTabelle.content[2][0].value = "Name dieser Tabelle"; meineTabelle.content[2][1].value = meineTabelle.name; meineTabelle.content[0][0].props = 'align="center" bgcolor="#EEEEEE"'; meineTabelle.content[0][1].props = 'align="center" bgcolor="#EEEEEE"'; meineTabelle.content[1][0].props = 'bgcolor="#FFFFCC"'; meineTabelle.content[1][1].props = 'bgcolor="#CCFFFF"'; meineTabelle.content[2][0].props = 'bgcolor="#FFFFCC"'; meineTabelle.content[2][1].props = 'bgcolor="#CCFFFF"';
Zunächst muß dazu wie im Beispiel gezeigt das Statement Tabellenname.contentArraysToArguments() notiert werden. Anschließend kann der dritte Index durch die Objekteigenschaften value oder props ersetzt werden. props steht für die Attribute der ausgewählten Zelle (also für <td ...></td>), und value für die Inhalte der ausgewählten Zelle (der Inhalt zwischen <td>...</td>).
Wenn Sie diese Variante verwenden, müssen Sie, bevor Sie die Tabelle am Ende mit draw() ausgeben, das Umkehr-Statement Tabellenname.contentArgumentsToArrays() notieren. Beispiel:
meineTabelle.contentArgumentsToArrays();
document.write(meineTabelle.draw());
Das Verwenden der Objekteigenschaften value und props ist ein gewisser Luxus, der damit erkauft wird, daß im Arbeitsspeicher zwei Kopien der erzeugten Tabelle gehalten werden. Bei sehr umfangreichen Tabellen kann es daher je nach den Arbeitsspeicher-Kapazitäten, die dem Browser bzw. JavaScript-Interpreter zur Verfügung stehen, eher zu Problemen kommen, als wenn mit Indizes gearbeitet wird. Im Zweifelsfall ist also die Arbeit mit den Indizes ressourcen-schonender und unkritischer.
Der folgende Code gehört zum table-Objekt und wird hier für Experten zum tieferen Verständnis erläutert.
function table()
{ var propsDefaultLength = 2;
this.cols = 1;
this.rows = 1;
for (var i=1;i<=table.arguments.length;i++)
{if (table.arguments[(i-1)].indexOf("cols") >= 0) {propsDefaultLength--;}
if (table.arguments[(i-1)].indexOf("rows") >= 0) {propsDefaultLength--;}
eval("this."+table.arguments[(i-1)]);
}
this.propsLengthPublic = (table.arguments.length + propsDefaultLength);
this.propsLengthPrivat = 7;
this.content = tableContent(this.cols,this.rows);
this.span = tableSpan;
this.draw = tableDraw;
this.contentArraysToArguments = tableContentArraysToArguments;
this.contentArgumentsToArrays = tableContentArgumentsToArrays;
}
Diese Funktion erzeugt das eigentliche table-Objekt. Standardmäßig erhält eine Tabelle die Argumente cols= und rows=, deren Parameter auf 1 gesetzt werden - wenn beim Aufruf von table() nichts weiter angegeben wird, wird also eine Tabelle mit genau einer Zelle erzeugt. Eine Initialisierung wäre ansonsten unmöglich, denn die Funktion
Methode tableContent() griffe voll ins Leere.
Die weiteren Eigenschaften holt sich der table-Konstruktor aus der übergebenen Argumenten-/Parameterliste. Dabei wird in dieser Liste noch einmal nach den Parametern cols= und rows= gesucht, um die angegebenen Werte für die Tabelle zu übernehmen. Fehlen diese Parameter, greift der Default (cols="1" rows="1"), wobei allerdings die Erzeugung einer Tabelle mit den Default-Werten angesichts des Umfangs des gesamten table-Objekt-Codes nicht gerade sinnvoll ist.
Zum weiteren Komfort sind die Argumente propsLengthPublic und propsLengthPrivat eingeführt worden. Sie erlauben den Überblick, wieviele Argumente der Funktion beim Aufruf übergeben (oder an die bestehenden 2 angehängt) wurden, und wieviele "hauseigene" Argumente zur Verfügung stehen.
Schließlich werden noch die die vier Methoden des table-Objekts initialisiert: span(), draw(), contentArraysToArguments() und contentArgumentsToArrays().
Der folgende Code gehört zum table-Objekt und wird hier für Experten zum tieferen Verständnis erläutert.
/*
zur erinnerung:
function table()
{...
this.content = tableContent(this.cols,this.rows);
...
}
*/
function tableContent(dummyCols,dummyRows)
{var dummyContent = "[";
for (var i=1;i<=dummyRows;i++)
{dummyContent = dummyContent+"["
for (var k=1;k<=dummyCols;k++)
{dummyContent = dummyContent+"[['align="+'"left"'+" valign="+'"top"'+"'],[' '],['false']],";}
dummyContent = dummyContent.substring(0,((dummyContent.length)-1));
dummyContent = dummyContent+"],"
}
dummyContent = dummyContent.substring(0,((dummyContent.length)-1));
dummyContent = dummyContent+"]";
return eval(dummyContent);
}
Wird ein neues table-Objekt mit new table(); erzeugt, generiert die Methode tableContent([spalten],[zeilen]) einen Array, in welchem diese Tabelle abgebildet wird. Dabei erhalten alle Zellen die oben angesprochenen Eigenschaften:
props aller Zellen erhalten als default die werte [align="left" valign="top"]values dieser Zellen werden standardmäßig auf [ ] gesetzt,spans-default einer jeden Zelle lautet ["false"], denn noch existieren keine "col/rowspan"Der Rückgabewert dieser Methode beim Initialisieren einer Tabelle ist der komplette Array.
Der folgende Code gehört zum table-Objekt und wird hier für Experten zum tieferen Verständnis erläutert.
/*
zur erinnerung:
function table()
{...
this.span = tableSpan;
...
}
*/
function tableSpan()
{var dummyRows = this.content.length;
var dummyCols = this.content[0].length;
for (var i=1;i<=dummyRows;i++)
{var rowspan = 0;var colspan = 0;
var fromHere = 0;var tillThere = 0;
var myString = "";
for (var k=1;k<=dummyCols;k++)
{rowspan = 0;colspan = 0;
if (this.content[(i-1)][(k-1)][2] == "false")
{myString = (this.content[(i-1)][(k-1)][0]) + "";
if (myString.indexOf("colspan") >= 0)
{fromHere = (myString.indexOf("colspan"))+9;
tillThere = (myString.indexOf('"',fromHere))-1;
if ((fromHere-tillThere) == 0)
{colspan = myString.charAt(fromHere);}
else
{colspan = myString.substring(fromHere,tillThere);}
colspan = parseInt(colspan);
}
if (myString.indexOf("rowspan") >= 0)
{fromHere = (myString.indexOf("rowspan"))+9;
tillThere = (myString.indexOf('"',fromHere))-1;
if ((fromHere-tillThere) == 0)
{rowspan = myString.charAt(fromHere);}
else
{rowspan = myString.substring(fromHere,tillThere);}
rowspan = parseInt(rowspan);
}
if ((colspan >= 2) && (rowspan <= 1))
{for (var m=2;m<=colspan;m++)
{this.content[(i-1)][((k-1)+(m-1))][2] = "true";}
}
if ((rowspan >= 2) && (colspan <= 1))
{for (var m=2;m<=rowspan;m++)
{this.content[((i-1)+(m-1))][(k-1)][2] = "true";}
}
if ((rowspan >= 2) && (colspan >= 2))
{for (var m=1;m<=rowspan;m++)
{for (var p=1;p<=colspan;p++)
{this.content[((i-1)+(m-1))][((k-1)+(p-1))][2] = "true";}
}
this.content[(i-1)][(k-1)][2] = "false";
} } } } }
Diese Methode wird nur von der Funktion
tableDraw() (= Tabellenname.draw()) aufgerufen, damit jene die HTML-Syntax einer Tabelle genau berechnen kann. Die Methode table.span() durchsucht die value-Felder des
Arrays 'content' systematisch nach den Ausdrücken "colspan" und/oder "rowspan" und schreibt in alle spans-Felder die Ausdruecke "true" oder "false" in Abhängigkeit davon, ob die entsprechenden Tabellenzellen später in der HTML-Struktur auftauchen dürfen oder nicht. Die spans-Felder werden automatisch dem content-Array hinzugefügt. Dort dient neben den Indizes 0 und 1 bzw. den Eigenschaften props und value, die der Programmierer selbst verwalten kann, der Index 2 als Flag für das dritte mögliche Argument einer Tabellenzelle - diese Eigenschaft spans wird intern vom table-Objekt vergeben und verwaltet.
Der folgende Code gehört zum table-Objekt und wird hier für Experten zum tieferen Verständnis erläutert.
function tableDraw()
{this.span();
var props = "";
var i = 0;
var dummyRows = this.content.length;
var dummyCols = this.content[0].length;
var dummyCode = '<table';
for (prop in this)
{if (i >= this.propsLengthPublic) {break;}
dummyCode = dummyCode+' '+prop+'="'+this[prop]+'"';i++;
}
dummyCode = dummyCode+'>\n';
for (var i=1;i<=dummyRows;i++)
{dummyCode = dummyCode+'<tr>\n';
for (var k=1;k<=dummyCols;k++)
{if (this.content[(i-1)][(k-1)][2] == "false")
{dummyCode = dummyCode+' <td '+this.content[(i-1)][(k-1)][0]+'>'+this.content[(i-1)][(k-1)][1]+'</td>\n';}
}
dummyCode = dummyCode+'</tr>\n';
}
dummyCode = dummyCode+'</table>\n';
return dummyCode;
}
Diese Methode erzeugt in der Variablen dummyCode den kompletten Code der Tabelle und gibt diese Variable am Ende zurück. So läßt sie sich z.B. mit document.write(Tabellenname.draw()) nutzen, um die Tabelle im Browserfenster auszugeben. Innerhalb der Methode wird zunächst die Methode
span() aufgerufen, denn ohne diese Hilfsmethode ist es nicht möglich, die HTML-Syntax der Tabelle korrekt zu berechnen. Anschließend können die Werte aus Tabellenname[zeile][spalte][2] abgefragt werden. draw() durchläuft dazu alle Zeilen von oben nach unten und alle Spalten von links nach rechts. Stößt die Methode dabei im entsprechenden spans-Feld des Arrays auf den Wert "false", wird eine weitere Zelle (inclusive props und value) in den HTML-Code eingefügt. Muß die Zelle "überspannt" werden (spans ist "true"), wird auf das Einfügen der entsprechenden Zelle verzichtet.
Der folgende Code gehört zum table-Objekt und wird hier für Experten zum tieferen Verständnis erläutert.
function tableContentArraysToArguments()
{var dummyRows = this.content.length;
var dummyCols = this.content[0].length;
for (var i=1;i<=dummyRows;i++)
{for (var k=1;k<=dummyCols;k++)
{this.content[(i-1)][(k-1)].props = this.content[(i-1)][(k-1)][0];
this.content[(i-1)][(k-1)].value = this.content[(i-1)][(k-1)][1];
this.content[(i-1)][(k-1)].spans = this.content[(i-1)][(k-1)][2];
} } }
function tableContentArgumentsToArrays()
{var dummyRows = this.content.length;
var dummyCols = this.content[0].length;
for (var i=1;i<=dummyRows;i++)
{for (var k=1;k<=dummyCols;k++)
{this.content[(i-1)][(k-1)][0] = this.content[(i-1)][(k-1)].props;
this.content[(i-1)][(k-1)][1] = this.content[(i-1)][(k-1)].value;
this.content[(i-1)][(k-1)][2] = this.content[(i-1)][(k-1)].spans;
} } }
Diese beiden Methoden dienen dazu, die Notation des des
Arrays 'content' zu beeinflussen. Beide Funktionen arbeiten nach dem gleichen Prinzip: sie arbeiten der Reihe nach alle vorhandenen Einträge des Arrays ab und "ersetzen" die Objekteigenschaften props, value und spans durch Indizes 0, 1 und 2 (contentArgumentsToArrays()) oder die Indizes 0, 1 und 2 durch die Objekteigenschaften props, value und spans (contentArraysToArguments()).
Das table-Objekt eröffnet weitere Möglichkeiten, dynamisch komplexe Tabellen-Layouts in JavaScript zu generieren:
screen-Objekt von JavaScript).Kopieren Sie den folgenden Code in Ihr JavaScript, um das table-Objekt zu verwenden.
/********* Start JavaScript-Code des table-Objekts **********/
function tableDraw()
{this.span();
var props = "";
var i = 0;
var dummyRows = this.content.length;
var dummyCols = this.content[0].length;
var dummyCode = '<table';
for (prop in this)
{if (i >= this.propsLengthPublic) {break;}
dummyCode = dummyCode+' '+prop+'="'+this[prop]+'"';i++;
}
dummyCode = dummyCode+'>\n';
for (var i=1;i<=dummyRows;i++)
{dummyCode = dummyCode+'<tr>\n';
for (var k=1;k<=dummyCols;k++)
{if (this.content[(i-1)][(k-1)][2] == "false")
{dummyCode = dummyCode+' <td '+this.content[(i-1)][(k-1)][0]+'>'+this.content[(i-1)][(k-1)][1]+'</td>\n';}
}
dummyCode = dummyCode+'</tr>\n';
}
dummyCode = dummyCode+'</table>\n';
return dummyCode;
}
function tableSpan()
{var dummyRows = this.content.length;
var dummyCols = this.content[0].length;
for (var i=1;i<=dummyRows;i++)
{var rowspan = 0;var colspan = 0;
var fromHere = 0;var tillThere = 0;
var myString = "";
for (var k=1;k<=dummyCols;k++)
{rowspan = 0;colspan = 0;
if (this.content[(i-1)][(k-1)][2] == "false")
{myString = (this.content[(i-1)][(k-1)][0]) + "";
if (myString.indexOf("colspan") >= 0)
{fromHere = (myString.indexOf("colspan"))+9;
tillThere = (myString.indexOf('"',fromHere))-1;
if ((fromHere-tillThere) == 0)
{colspan = myString.charAt(fromHere);}
else
{colspan = myString.substring(fromHere,tillThere);}
colspan = parseInt(colspan);
}
if (myString.indexOf("rowspan") >= 0)
{fromHere = (myString.indexOf("rowspan"))+9;
tillThere = (myString.indexOf('"',fromHere))-1;
if ((fromHere-tillThere) == 0)
{rowspan = myString.charAt(fromHere);}
else
{rowspan = myString.substring(fromHere,tillThere);}
rowspan = parseInt(rowspan);
}
if ((colspan >= 2) && (rowspan <= 1))
{for (var m=2;m<=colspan;m++)
{this.content[(i-1)][((k-1)+(m-1))][2] = "true";}
}
if ((rowspan >= 2) && (colspan <= 1))
{for (var m=2;m<=rowspan;m++)
{this.content[((i-1)+(m-1))][(k-1)][2] = "true";}
}
if ((rowspan >= 2) && (colspan >= 2))
{for (var m=1;m<=rowspan;m++)
{for (var p=1;p<=colspan;p++)
{this.content[((i-1)+(m-1))][((k-1)+(p-1))][2] = "true";}
}
this.content[(i-1)][(k-1)][2] = "false";
} } } } }
function tableContent(dummyCols,dummyRows)
{var dummyContent = "[";
for (var i=1;i<=dummyRows;i++)
{dummyContent = dummyContent+"["
for (var k=1;k<=dummyCols;k++)
{dummyContent = dummyContent+"[['align="+'"left"'+" valign="+'"top"'+"'],[' '],['false']],";}
dummyContent = dummyContent.substring(0,((dummyContent.length)-1));
dummyContent = dummyContent+"],"
}
dummyContent = dummyContent.substring(0,((dummyContent.length)-1));
dummyContent = dummyContent+"]";
return eval(dummyContent);
}
function tableContentArraysToArguments()
{var dummyRows = this.content.length;
var dummyCols = this.content[0].length;
for (var i=1;i<=dummyRows;i++)
{for (var k=1;k<=dummyCols;k++)
{this.content[(i-1)][(k-1)].props = this.content[(i-1)][(k-1)][0];
this.content[(i-1)][(k-1)].value = this.content[(i-1)][(k-1)][1];
this.content[(i-1)][(k-1)].spans = this.content[(i-1)][(k-1)][2];
} } }
function tableContentArgumentsToArrays()
{var dummyRows = this.content.length;
var dummyCols = this.content[0].length;
for (var i=1;i<=dummyRows;i++)
{for (var k=1;k<=dummyCols;k++)
{this.content[(i-1)][(k-1)][0] = this.content[(i-1)][(k-1)].props;
this.content[(i-1)][(k-1)][1] = this.content[(i-1)][(k-1)].value;
this.content[(i-1)][(k-1)][2] = this.content[(i-1)][(k-1)].spans;
} } }
function table()
{var propsDefaultLength = 2;
this.cols = 1;
this.rows = 1;
for (var i=1;i<=table.arguments.length;i++)
{if (table.arguments[(i-1)].indexOf("cols") >= 0) {propsDefaultLength--;}
if (table.arguments[(i-1)].indexOf("rows") >= 0) {propsDefaultLength--;}
eval("this."+table.arguments[(i-1)]);
}
this.propsLengthPublic = (table.arguments.length + propsDefaultLength);
this.propsLengthPrivat = 7;
this.content = tableContent(this.cols,this.rows);
this.span = tableSpan;
this.draw = tableDraw;
this.contentArraysToArguments = tableContentArraysToArguments;
this.contentArgumentsToArrays = tableContentArgumentsToArrays;
}
/********* Ende JavaScript-Code des table-Objekts **********/