Ermöglicht die wechselweise Manipulation der Darstellung einzelner HTML-Elemente oder ganzer Seitenbereiche wie Absätze oder Tabellen(-zeilen/-spalten).
Benötigt:
JavaScript 1.5 (gesichert, nicht gesichert für JavaScript 1.0)
Mittels CSS können Browser HTML-Elemente unterschiedlich darstellen.
U.a. können sie Elemente/Layer/Ebenen auch verstecken - sowohl mit Platzhalter (Style:
visibility), als auch ohne (Style: display). Manche
Browser können HTML-Elemente sogar durchsichtig darstellen - wie der
Internet Explorer (Style: filter("Alpha")), die auf Mozilla (Style:
-moz-opacity) und KHTML (Style: -khtml-opacity)
basierenden Browser wie Konqueror (Unix - leider nur eingeschränkt)
oder Safari (Macintosh & Windows). Zukünftig sollen es aber alle Browser sein, die
CSS Version 3 unterstützen (Style: opacity - wird ebenfalls in
den aktuellen Versionen einiger Browser unterstützt, z.B. im Firefox oder
Safari). Das "normale" Darstellungsvarianten wie Vorder- (Style: color)
bzw. Hintergrund- (Style: background-color) und Rahmenfarbe
(Style: border-color) gesetzt werden können, versteht
sich ohnehin von selbst.
In Verbindung mit JavaScript kann man dies auch leicht gezielt und interaktiv
nutzen. Eine Möglichkeit dazu: Man kann ein HTML-Element mit einer ID
versehen und es über diese ID ansprechen. Da die ID jedoch eindeutig zu sein
hat (also im Dokument nicht mehrfach vorkommen darf), müsste man nicht nur
alle betreffenden Elemente mit einer einzigartigen ID versehen, sondern diese
auch noch jeweils einzeln mit JavaScript ansprechen. Die hier vorgestellte
Funktion toggle() ermöglicht es hingegen, nicht nur gezielt
einzelne Elemente mittels ID zu manipulieren, darüberhinaus können
auch mehrere Elemente mittels einer frei definierbaren Kennung auf einen Schlag
bearbeitet werden. So können z.B. in einer Tabelle alle Zeilen eines
bestimmten Inhaltes (oder sogar mit mehreren bestimmten Inhalten) mit einer
einzigen Anweisung manipuliert werden. Zusätzlich kann man auch noch Ausnahmen
festlegen, die komplementär, also gegensätzlich, bearbeitet werden. So ist
es z.B. mit nur einer Anweisung möglich, bestimmte Elemente zu falten und die
anderen gleichzeitig zu entfalten.
Der erste Parameter type enthält den gewünschten Befehl, den
toggle() ausführen soll (nicht case-sensitive, also unabhängig
von Groß/Kleinschreibung). Zur Zeit sind dies:
Absolute Aktionen (mit feststehenden Werten):
fold faltet Elemente, d.h. sie werden ohne Platzhalter versteckt.
unfold stellt mit fold versteckte Elemente wieder dar.
hide versteckt Elemente mit einem Platzhalter.
unhide stellt mit hide versteckte Elemente wieder dar.
Mangels Notwendigkeit werden ihnen (im allgemeinen) keine zusätzlichen Werte übergeben.
Bedingte Aktionen (mit optionalen Werten):
trans stellt Elemente halb-transparent dar.
color setzt die Vordergrundfarbe der Elemente auf schwarz.
back setzt die Hintergrundfarbe der Elemente auf weiß.
border setzt die Rahmenfarbe der Elemente auf schwarz.
Hier sind Werte vordefiniert - eigene Werte können aber mit einem :
angehängt werden
Spezielle Aktionen:
test überprüft, ob der Browser geeignet ist.
Man kann auch mehrere (sich nicht widersprechende) Aktionen kombinieren, so daß
z.B. mit "unfold unhide" in einem Durchgang alle Elemente auf jeden Fall
dargestellt werden, egal ob sie vorher gefaltet, oder nur versteckt waren.
Anmerkung zu unfold: Um ein gefaltetes Element wieder sichtbar zu
machen, löscht toggle() den Wert der verwendeten CSS-Eigenschaft
display (display=""). So kann man allerdings nur Elemente
entfalten, wenn sie vorher auch mit JavaScript gefaltet wurden, aber leider nicht,
wenn dies direkt via Style-Angabe geschah (style="display:none").
Zwar sollte man i.d.R. nur mit JavaScript falten, damit sichergestellt ist, daß
Browser ohne JavaScript alles darstellen, während man bei JavaScript-Browsern
davon ausgehen kann, daß sie auch entfalten können, was sie vorher selbst
gefaltet haben, aber die Ausnahme bestätigt bekanntlich die Regel. ;-)
Wurde aber nur mit CSS gefaltet, muß explizit die gewünschte Darstellungsart
übergeben werden, indem man hinter der gewünschten Aktion, durch einen
Doppelpunkt getrennt, auch die gewünschte Darstellungsart übergibt! Diese
Darstellungsarten sind: block, inline, list-item,
marker, run-in bzw. compact, sowie
table, inline-table, table-row,
table-row-group, table-header-group,
table-footer-group, table-column,
table-column-group und table-caption
(für eine Beschreibung dieser Darstellungsarten s. den entsprechenden Eintrag in
selfHTML)
- ein Aufruf sähe also z.B. so aus: toggle("unfold:inline","ID1").
Leider ist dies jedoch nicht mehr so trivial, da der Internet Explorer sich hier
nicht nach dem (vollen) Standard richtet (jedenfalls bis zum IE 7 inkl.)! So ist z.B.
die Darstellungsart einer Tabellenzeile (<tr>) table-row
- der IE kennt diese Art aber erst ab Version 8 und braucht in älteren Versionen block,
was von den anderen Browsern (zurecht) falsch dargestellt wird (die im IE erlaubten
Darstellungsarten sind unter MSDN Library: display
nachzulesen). Um eine Tabellenzeile <tr id="ID1" style="display:none">
zu entfalten, müsste der Aufruf also toggle("unfold:"+((is_ie && agt_ieVersion<8)?"block":"table-row","ID1"))
lauten (IEs bis Version 7 bekommen block, alle anderen Browser table-row),
mit is_ie=true, falls der Browser ein IE ist (s.
Systemvariable - viele im Internet
zu findende JavaScripts zur Browsererkennung arbeiten leider ungenau und meinen
selbst dann einen IE zu erkennen, wenn der Browser ein anderer ist, da oft nur
auf das Vorhandensein von document.all und/oder die Browserkennung
geprüft wird, was beides, selbst in Kombination, nicht ausreichend ist; und
die Browserversion selbst ist so trotzdem nicht definitiv zu ermitteln, da beim IE
JScript- & Browserversion unabhängig voneinander sind)! Aber aufgepaßt: Wenn sich der IE 8 im "Kompatibilitätsmodus" befindet (ist
automatisch der Fall, wenn die Seite im Quirks-Modus
läuft, oder der Browser mittels X-UA-Compatible
dazu angewiesen wird), dann gilt natürlich auch beim IE ab 8: Nur block & inline!
Soll die Darstellung einer bedingten Aktion vom voreingestellten Wert abweichen,
kann man auch eigene Werte anhängen. Für z.B. eine Transparenz von 25%
und eine rote Vordergrundfarbe müsste der Aufruf toggle("trans:25 color:red","ID1")
lauten. Werden Ausnahmen für eine komplementäre Darstellung definiert, so kann
man optional nach einem / einen eigenen Komplementär-Wert
anhängen (bei Komplementär-Darstellung mit 75% Transparenz und
blauer Vordergrundfarbe also trans:25/75 color:red/blue).
Bei der Transparenz sind Werte im Bereich von 0 (keine Transparenz) bis 100
(volle Transparenz - das Element ist unsichtbar) möglich, bei den Farben die
in CSS auch sonst gültigen Werte (also vordefinierten Farbnamen, aber z.B.
auch hexadezimale RGB-Werte wie #FF0000 für rot).
Die Art, wie toggle() die gewünschte Aktion abarbeitet, hängt
dann vom zweiten Parameter ab:
toggle(type,element)
Wenn der zweite Parameter element eine (im Dokument vorhandene) ID ist,
dann wird gezielt dieses Element bearbeitet. Um also z.B. den Text
<p id="Absatz1">Dies ist Absatz 1!</p> ohne Platzhalter
zu verstecken (zu falten), bedarf es der Anweisung toggle("fold","Absatz1");,
was, inkl. Plausibilitätsprüfung, dem JavaScript-Code
if(document.getElementById && document.getElementById("Absatz1")) {
document.getElementById("Absatz1").style.display="none"; }
entspricht. Analog kann man mit toggle("unfold","Absatz1");
den Text wieder erscheinen lassen.
toggle(type,element,toggleID[,xID[,xID[,...[,xSwitch]]]])
Ist der zweite Parameter element keine vorhandene ID, so wird er als
HTML-Tag interpretiert! Also liessen sich z.B. mit "tr" mehrere
Tabellenzeilen, mit "p" mehrere Absätze auf einen Schlag
bearbeiten.
Um festzulegen, welche Elemente bearbeitet werden sollen, dient dann der dritte
Parameter toggleID, der eine vom HTML-Autor zu definierende
Basiskennung enthalten muß. Optional können anschließend beliebig
viele Teilkennungen übergeben werden, um auch Ausnahmen bestimmen zu können.
Dies kann entweder in getrennten Parametern geschehen ("A","B",...),
oder in einer einzigen Zeichenkette, wobei die Restkennungen dann mittels
Pipe-Symbol voneinander getrennt werden müssen ("A|B|...").
Der letzte, ebenfalls optionale Parameter xSwitch definiert dann
noch, wie mit diesen Ausnahmen verfahren werden soll. Voreingestellt ist
false, wobei die Ausnahme-Elemente einfach ignoriert werden.
Ist xSwitch hingegen true, so wird auf die
Ausnahme-Elemente die jeweilige Komplementärfunktion angewendet. D.h.,
wird z.B. bei toggle("fold",...) ein Element gefunden dessen
Toggle-Attribut mit einer passenden Basiskennung beginnt, so wird dieses
Element gefaltet. Wurde aber dessen Restkennung als Ausnahme übergeben,
so wird es nicht gefaltet. Wenn xSwitchtrue ist, so
wird es sogar explizit entfaltet.
Um mehrere Elemente in einem Durchgang bearbeiten zu können (Variante 2), wird
in allen betroffenen Elementen ein HTML-Attribut benötigt, das als Wert
(mindestens) eine Basiskennung hat, die in toggleID übergeben
werden muß. Jedes so ausgezeichnete Element wird also beim Aufruf
von toggle("fold",...) gefaltet. Voreingestellt ist der (erfundene)
Attributname gid (Group-ID), aber man kann sich in der Routine
auch einen anderen Attributnamen definieren (var toggleAttribute="...").
Außerdem kann man auch direkt einen spezifischen Attributnamen übergeben!
Er kann, getrennt durch einen Doppelpunkt, an den Tagnamen gehängt werden
(tr:id bearbeitet z.B. alle Tabellenzeilen anhand des Inhalts des
ID-Attributs).
Anmerkung: Auch wenn die Browser-Hersteller fleissig Tags & Attribute
jenseits der HTML-Standards des W3Cs
erfinden: Ein Standard-konformer HTML-Validator wird die Anwendung des
erfundenen Attributes gid natürlich bemängeln. Erst mit XML ist
es möglich, beliebige eigene Attribute valide zu definieren. Stören muß
dies jedoch nicht, da das HTML-Dokument trotzdem wohlgeformt bleibt (und das ist
das Entscheidende für einen HTML-Browser - s. Know-how).
Die Anwendung bereits vorhandener HTML-Attribute ist nicht unbedingt eine
gute Lösung. Je nach Browser kann es dabei zu Fehlern kommen: Bei Verwendung
von name (ein thematisch zwar passendes, aber laut dem W3C nur
in wenigen Tags erlaubtes Attribut) gibt es Probleme mit Opera-Browsern,
die Verwendung von class (fast überall erlaubt und durch gleichzeitige
CSS-Definitionen für unterschiedliche Inhalte ggf. ohnehin sinnvoll) bereitet
hingegen dem Internet Explorer Probleme (wohlgemerkt stets mit der hier verwendeten
JavaScript-Methode getAttribute()=:-o).
Zumindest die Verwendung von id macht keinerlei Probleme, hat dafür
aber natürlich den Nachteil, daß man nicht gleiche IDs vergeben darf, und somit
ein Teil der Funktionalität von toggle() auf der Strecke bleibt.
Gleichwohl ist id vorzuziehen, wenn man mit der eingeschränkten
Funktionalität auskommt und unbedingt nach den HTML-Standards des W3Cs
coden möchte.
Besonders wenn viele Elemente durchsucht, aber nur wenige wirklich bearbeitet
werden müssen, kommt es zu eigentlich unnötigen Wartezeiten. Um dem ggf.
entgegenzuwirken, kann man dem gewünschten Tagnamen noch einen Arbeitsbereich
mitgeben (in geschweiften Klammen). Hat nämlich eine HTML-Seite beispielsweise
1000 TR-Elemente, so müssen alle diese Elemente auf das passende Attribut
hin durchsucht werden, selbst wenn es sich um unterschiedliche Tabellen handelt.
Wenn aber z.B. nur die Tabelle Nr. 2 interessant ist, deren TR-Elemente in der
Seite die (fortlaufenden) internen Nummern 50-99 besitzen (es wird bei 0 begonnen
zu zählen), so kann man die Suche mit tr{50-99} auf den gewünschten
Bereich beschränken (bei gleichzeitig übergebenem Wunsch-Attribut
"id": tr:id{50-99}). Die Funktion braucht nunmehr, bei gleichem Ergebnis,
nur noch ein Viertel der ursprünglichen Arbeitszeit! Wenn mehr als 200 Elemente
durchsucht werden müssen, wird zudem der aktuelle Stand in der Statuszeile des
Browsers angezeigt (allerdings leider nicht in jedem Browser). Möchte man einen
anderen Schwellenwert für die Anzeige definieren, so kann man dies in der Routine
selbst tun - der Wert wird mit var showStatus=... definiert.
Aber insbesondere bei einer Vielzahl von Elementen stellt hier ggf. das Ändern
nicht der vielen Elemente (mittels toggle()), sondern des CSS selbst
(mittels cssRule())
eine Alternative dar, bei der man mit einer Änderung auf einen Schlag eine
Vielzahl von Elementen beeinflussen kann. Allerdings unterstützt nicht jeder
DOM-Browser diese Möglichkeit (Opera erst ab Version 9).
Der Aufruf toggle("fold","tr:id","Tab1") faltet hier alle Tabellenzeilen,
bis auf die Überschriftszeile (kein Toggle-Attribut) und die Legendenzeile
(Toggle-Attribut hat nicht die Basiskennung "Tab1"). Durch direkten Zugriff auf
die ID (toggle("fold","Tab1B")), kann man auch gezielt einzelne Elemente
bearbeiten.
Die an die Basiskennung ggf. anschließende, beliebige Restkennungen, können
toggle() dann als Ausnahme übergeben werden. Diese Elemente werden
entweder ignoriert (xSwitch ist false oder leer) oder
komplementär bearbeitet (xSwitch ist true)! Beispiel (wegen
gleicher Kennungen wird hier mit dem voreingestellten GID-Attribut gearbeitet):
Das "Verstecken" mit toggle("hide","tr","Tab2","A","C") ersetzt die
Tabellenzeilen 2, 3 und 5 durch einen Platzhalter. Die Zeilen 1 und 4 haben zwar
die korrekte Basiskennung "Tab2", aber deren Restkennungen "A" und "C" wurden
explizit vom Verstecken ausgenommen.
Beim "Versteck-Switch" (gleicher Code mit zusätzlichem Parameter
true) ist das Ergebnis gleich, wenn alle Elemente sichtbar waren.
Wenn aber die Zeilen 1 und 4 vor dem Aufruf bereits versteckt sind (z.B. durch
style="visibility:hidden;"), dann hätte der Switch-Aufruf
sie angezeigt (den Effekt sieht man, wenn man die Buttons in der Reihenfolge der
Ziffern nacheinander aufruft, bzw. wenn man wechselweise den "Versteck-Switch"
und den "Anzeige-Switch" betätigt). Dies ermöglicht es auch, mit einem
einzigen Aufruf gezielt bestimmte Inhalte darzustellen, egal ob sie vorher sichtbar
waren oder nicht (jedenfalls bei geschickter Ausnutzung der Restkennungen). Stets
zwei getrennte Aufrufe, einer zum Verstecken unerwünschter, ein zweiter zum
Anzeigen erwünschter Elemente, würde auch die doppelte Rechenzeit
benötigen - insbesondere bei großen Dateien mit vielen Elementen eine
i.d.R. sinnlose Zeitverschwendung.
Anmerkung: Anstatt die Ausnahme-Restkennungen einzeln zu übergeben,
kann man auch alles in einer einzigen Zeichenkette zusammenfassen! Statt
toggle("hide","tr","Tab2","A","C",true) kann man also auch
toggle("hide","tr","Tab2","A|C",true) schreiben.
Will man nicht Tabellen-Zeilen, sondern -Spalten bearbeiten, so muß
man natürlich jede Zelle der betreffenden Spalte kennzeichnen, da HTML
Tabellen-Spalten nicht kennt:
Zuerst werden, jedenfalls wenn toggle() verfügbar ist, die einzelnen
Zellen mit toggle('back trans','th:id','Tab3'); (Kopf- und Fußzelle)
bzw. toggle('back trans','td:id{41-51}','Tab3'); (Inhaltszellen)
vorbereitet. Da unbearbeitete Tabellen prinzipiell durchsichtig sind, wird die
Hintergrundfarbe auf weiß und die Transparenz auf 50% gesetzt, was einen
Milchglas-Effekt ergibt (der Tabelle selbst eine Hintergrundfarbe zuzuweisen
wäre hier unsinnig, da ja nicht die Tabelle als ganzes, sondern nur einzelne
Zellen mit einem Effekt versehen werden soll). Der eigentliche Toggle-Effekt
wird dann gestartet, wenn man die Maus über die Inhaltszellen bewegt. Im dafür
zuständigen onMouseOver sind folgende Aufrufe enthalten:
toggle('trans:20 back:#FFEEEE border:#FFEEEE','td:id{41-51}','Tab3BodyA');
(aufgerufen mit über jeder linken Tabellen-Zelle) reduziert die
Transparenz von den voreingestellten 50% auf 20% für die komplette
Tabellen-Spalte, also allen Zellen deren ID mit TabBodyA
beginnt (durch das angehängte {41-53} werden nicht alle
Zellen (TD) des gesamten Dokumentes überprüft, sondern
nur die Zellen Nr. 41 bis Nr. 53, jeweils inkl.). Gleichzeitig werden die
Hintergrund- und die (CSS-)Rahmenfarbe dieser Spalte auf hellrot gesetzt,
um auch einen Effekt auf Browsern zu erzielen, die noch keine Transparenz
unterstützen.
toggle('border','Tab3BodyA4'); (aufgerufen über jeder
Tabellen-Zelle - natürlich mit der jeweiligen Zellen-ID) färbt
den (CSS-)Zellenrand schwarz.
Analog werden entsprechende Aufrufe für die rechten Tabellen-Zellen
durchgeführt, und mit onMouseOut der Zustand wieder
zurückgesetzt.
Da die Interaktivität an eine Bedingung geknüpft ist (nämlich der Benutzung
eines DHTML-Browsers mit JavaScript ab Version 1.5), sollten die Steuerelemente
ggf. auch nur bei gegebener Funktionalität anwählbar sein. In den obigen
Beispielen sind deswegen die Aufrufe/Buttons mit if(toggle("test")) { ... }
(oder kürzer: if(toggle()) { ... }) geklammert (alternativ könnte man
auch auf is_w3cxDOM der Systemvariablen
zurückgreifen). toggle() gibt true zurück, wenn das
Falten technisch möglich ist, false wenn nicht. Um Fehler zu vermeiden,
falls das externe Script nicht geladen werden konnte, wurde außerdem im Kopf
der HTML-Datei eine Dummy-Funktion gleichen Namens erstellt (sie gibt stets
false zurück). Erst wenn das externe Script mit der eigentlichen
Funktion toggle() geladen wurde, wird auch diese statt der Dummy-Funktion
angesprungen und der korrekte Rückgabewert ermittelt. Wenn toggle()
ausführbar ist, enthält nach regulärer Ausführung der
Rückgabewert die Anzahl der tatsächlich bearbeiteten Elemente (0,
falls kein passendes Element gefunden wurde).
Kleines Toggle-Beispiel (ein größeres Beispiel wäre die GfA-Befehlsreferenz)
Erweiterung: Proprietärer Transparenz-Code für die Browser mit KTHML-Engine (Konqueror, Safari) eingefügt.
09.06.2004:
Korrektur: Unter bestimmten Umständen konnte der Rückgabewert (Anzahl bearbeiteter Elemente) um 1 zu niedrig ausfallen.
24.04.2004:
Erweiterung: Es kann jetzt auch die Rahmenfarbe (border) eingestellt werden.
17.04.2004:
Erweiterung: Es können nun auch Transparenz (trans), Farbe (color) und Hintergrundfarbe (back) eingestellt werden. Der Schwellenwert für die Fortschrittsanzeige wurde auf 200 Elemente hochgesetzt und kann jetzt leichter eigenen Vorstellungen angepaßt werden.
19.03.2004:
Erweiterung: Bei fold/unfold kann jetzt die Darstellungsart übergeben werden, bei den Tagnamen ein Arbeitsbereich.