XUL Elemente und Features Die XML basierte Userinterface Language (XUL) enthält alle Basis-Widgets die verwendet werden um eine Benutzerschnittstelle zu einer Applikation zu bauen. Diese Interfaces umfassen Tabs, Textareas, Buttons und Menus aber auch handliche Dinge an die Sie vielleicht garnicht gedacht haben, wie das <stack> Widget oder der <colorpicker>. Kapitel 2 zeigte ein paar XUL Elemente die ein Fenster und eine Basisapplikation darstellen. Dieses Kapitel geht näher auf XUL und dessen Elemente und Fähigkeiten ein, beschreibt die Überlegungen dahinter, das Aussehen und Verhalten und die gängige Anwendung. Obwohl nicht vollkommen komplett, sollte Ihnen dieses Kapitel genügend Informationen geben, um Ihre eigenen Mozilla Applikation erstellen können, vorallem wenn Sie dazu die XUL Referenz in Anhang C konsultieren. Die hier vorgestellten Elemente wie Menus, Buttons, Trees und Boxes werden in fast jeder Applikation verwendet. Die meisten Beispiele sind deshalb generisch gehalten und fügen sich ohne viele Änderungen in Ihre Applikation ein. Dieses Kapitel enthält sehr viele Informationen und wird Ihnen deshalb als Referenz dienen wenn Sie beginnen Ihre eigenen Applikationen zu entwickeln. Das XUL Document Objekt Im Herzen jeder XUL Datei befindet sich das Document Objekt. Wie in HTML, beschreibt document das XUL Dokument selbst -- und nicht das Umgebende Fenster. document stellt verschiedene Methoden zur Verfügung um Elemente in der Dokument-Struktur zu finden, sie zu manipulieren oder ihre Styles anzupassen. Das document Objekt stellt Methoden, wie getElementById, getElementsByTagName, createElement und createTextNode um den DOM zu manipulieren oder abzufragen bereit. Weitere Informationen zum DOM finden Sie in Kapitel 5. Andere Eigenschften des document Objektes enthalten die Breite oder die Höhe des Fensters, ein popupNode Feld welches Zugriff auf das Element bietet das im Moment als Popup angezeigt wird (ein XUL Widget das an einem anderen Widget angehängt ist, und über ihm angezeigt wird), ein tooltipNode Feld, das den Zugriff auf den angezeigten Tooltip erlaubt und documentElement um damit auf den Body des Dokuments zuzugreifen: var docEl = document.documentElement; var secondLevelNodes = new Array( ); for (var I=0; I<docEl.childNodes.length;I++) { secondLevelNodes[I] = docEl.childNodes[I]; } Dieses Beispiel erstellt einen Array aller secondlevel Nodes des Dokuments, und könnte so erweitert werden, dass es den ganzen Baum berücksichtigt. Nodes in dieser Weise anzusprechen gibt Ihnen einen einfachen und schnellen Weg Teile des Dokumentes mit einem Script zu manipulieren. Das document Objekt ist im aktuellen Fenster global. Daraus lässt sich schliessen, dass jedes Fenster, jeder Dialog und jede Page ihr eigenes document Objekt enthält. Um auf die Eigenschaften zuzugreifen, verwenden Sie document als Prefix für den Namen des Feldes das Sie ansprechen wollen: var title = document.getElementById("bookTitle"); Um auf das document Objekt ausserhalb zuzugreifen, wird window.opener verwendet (adü: hiermit wird auf das Dokument des Parent-Fensters zugegriffen) var title = window.opener.document.getElementById("bookTitle"); XUL Parsing und das Document Object Model Mozilla prüft die Struktur jeder XUL Datei mit dem Expat XML Parser. Expat - eine in C geschriebene XML Verarbeitungsbibliothek - wurde bereits zu einem frühen Zeitpunkt in Mozilla integriert, als der Code als OpenSource veröffentlicht wurde. Während dem Parsing wird ein Inhaltsmodell basierend auf dem Document Object Model (DOM) erstellt, das den Zugriff auf die Inhalte erleichtert. Sobald Mozilla festgestellt hat dass alle XML Tags einer korrekten Namespaces zuordnen kann, liest er das Dokument ein zweites Mal um zu prüfen ob auch alle verwendeten Elemente gültig sind. Falls dies fehlschlägt, oder das Dokument anderweitig nicht den syntaktischen Regeln entspricht, wird eine Fehlermeldung ausgegeben die näher auf das Problem hinweist. Die erstellte Baumstruktur kann danach abgefragt, geändert und kopiert werden. Kapitel 5 geht näher darauf ein, wie JavaScript (die Hauptscriptsprache in Mozilla) und der DOM interagieren. Um den Baum anzuschauen k¨nnen Sie den DOM-Inspector benutzen, der mit Mozilla geliefert wird und erlaubt das Document Object Model jeder XUL Datei oder Website anzuschauen und zu manipulieren. Mehr Informationen zum DOM Inspector finden Sie in Anhang B. Applikationsfenster <window> ist nur eines der möglichen Root-Elemente eines XUL Dokuments, weitere sind <overlay>, <dialog>, <page> und <wizard>. Overlays spielen eine wichtige Rolle wenn es darum geht den Quellcode zu modularisieren, deshalb geht der Abschnitt 3.11 später in diesem Kapitel näher darauf ein. Diese Root-Elemente enthalten alle auch die XUL Namespace und die XUL Window Attribute und Methoden. Alle haben ein XUL document Objekt. Dennoch existieren spezielle möglichkeiten für jedes dieser Elemente. Welches Sie für Ihr XUL Dokument wählen hängt davon ab wozu Sie das Fenster benutzen wollen. Ein <window> ist typischerweise ein top-level Fenster, ein <dialog> second-level, der über einem anderen Fenster erscheint, eine <page> ist ein Dokument in einem Frame und <wizard> enthält eine Anzahl Abschnitte, die eine nach der anderen durchlaufen werden können. Dialoge Dialoge haben oft eine bestimmte Aufgabe, wie die Anzeige von Fehlermeldungen oder um Informationen vom Benutzer zu erhalten. Das <dialog> Element wurde ziemlich spät im Entwicklungsprozess definiert und ist auf die speziellen Bedürfnisse von Dialogen ausgerichtet, inklusive seiner relativen Positionierung zu anderen Fenstern (vorallem dem top-level Fenster) und der Existenz spezieller Buttons um eine Operation zu akzeptieren oder zu verwerfen. Ein Dialog sieht in XUL aus wie in Beispiel 3-1 gezeigt. XUL dialog <dialog id="turboDialog" buttons="accept" buttonpack="center" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" title="Empty the Cache" onunload="SetTurboPref( );"> Wie Sie sehen können, enthält der Dialog den XUL Namespace und die Attribute id und title. Andere Attribute wie buttons und buttonpack tauchen im normalen window-Kontext nicht auf. Dialoge werden oft verwendet damit der Benutzer eine Aktion auslösen oder eine Entscheidung treffen kann. Dazu gibt es spezielle Button Attribute. Zusätzlich zu buttons und buttonpack gibt es eigene Eventhandler für das Dialog Element -- ondialogaccept, ondialogcancel und ondialoghelp -- die zu den Buttons gehören, die in einem Dialog typischerweise angezeigt werden und Aktionen ausführen können wenn der Benutzer sie verwendet. Wie bei onunload können Funktionen direkt aus ondialogaccept aufgerufen werden, die Methode, die ausgeführt wird, wenn der 'OK' Button gedrückt wird: <dialog id="flush" buttons="accept" buttonpack="center" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" title="&exitWarningTitle.label;" ondialogaccept="doCacheFlush( );"> Pages / Seiten Das <page> Element ist konzipiert um in Frames eines high-level Dokuments angezeigt zu werden. Alleine sind sie keine top-level Fenster. In Mozilla wird page oft verwendet um in den Preferences/Einstellungen die Panels zu gestalten. Wie der Dialog in Beispiel 3-1, enthält das <page> Element in Beispiel 3-2 das bekannte Namespace Attribut (xmlns) und den load-Eventhandler(onload). Das headertitle Attribut wird benutzt, wenn die Seite in einem anderen Fenster mit eigenem Titel geladen werden soll. XUL page <page xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" onload="parent.initPanel('chrome://communicator/content/pref/pref-fonts.xul');" headertitle="&lHeader;"> Ein Anwendungsbeispiel für das page Elements finden Sie in den globalen Preferences/Einstellungen der Mozilla Suite. Abbildung 3-1 zeigt das Layout des Panels. In Beispiel 3-2 wird die Entität &lHeader; im Titel zu "Languages" aufgelöst und oberhalb der Eigenschaftspanel Page angezeigt. Das Hauptfenster ist ein XUL Dialog, der Inhalt ist zweigeteilt. Auf der linken Seite wird ein Overlay, das eine Baumstruktur enthält, ausgegeben, auf der rechten Seite eine XUL page, die in einem <iframe> geladen wurde. <iframe id="panelFrame" name="panelFrame" style="width:0px" flex="1"/>
Preferences/Eigenschaften-Dialog als Page.
Wie in Abbildung 3-1 gezeigt, führt die Selektion eines Topics aus dem linken Panel dazu, dass die Ansicht auf der rechten Seite wechselt. Obwohl in Realität mehrere Scripts verwendet werden, würde es reichen, das src Attribut des Frames zu ändern: document.getElementById("panelFrame").setAttribute("src", "chrome://communicator/content/pref/pref-navigator.xul" );
Wizards Auch dieser Window-Typ wurde für eine bestimmte Funktionalität entwickelt -- um den Benutzer durch einen Schritt-für-Schritt Prozess zu leiten. Einfach ein window nach dem anderen zu benutzen würde zu einer inkonsistenten Benutzerschnittstelle führen, weil die Fenster verschiedene Grössen hätten und die Performance tief wäre. Dies kann stöhren, vorallem wenn Sie einen Benutzer durch einen unbekannten Prozess, wie das einrichten eines neuen Benuterkontos führen wollen. Deshalb wurde das bekannte Wizard-Prinzip mit dem wizard Element ermöglicht. Beispiel 3-3 zeigt wie Mozilla Wizard Dialoge verarbeitet. Ein XUL Wizard <wizard id="NewAccount" title="Account Set-up" onwizardcancel="return Cancel( );" onwizardfinish="return Finish( );" onload="onLoad( );" width="44em" height="30em" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" xmlns:nc="http://home.netscape.com/NC-rdf#"> <wizardpage id="wPage1" pageid="page-1" label="New Account" onpageshow="return acctNamePageInit( );" onpageadvanced="nextPage(this)"> <vbox flex="1"> <description>Welcome and enjoy the wizardry</description> <image src="page1.png"/> </vbox> </wizardpage> <wizardpage id="wPage2"/> <wizardpage id="wPage3"/> </wizard> Eine wizardpage ist ähnlich wie eine page, da auch sie in ein Fenster geladen wird. Der Unterschied, wie in Beispiel 3-3 ersichtlich, ist, dass sich die page innerhalb des <wizard> Elements befindet. Sie können Wizardpages in der Reihenfolge anordnen in der sie aufgerufen werden. Wenn ein Benutzer eine Seite akzeptiert, wird automatisch die nächste geladen. In Beispiel 3-3, ist der Inhalt der ersten Page ein Text und ein Bild und die anderen Seiten definieren nur id Attribute (dies ist genau wie wenn Sie die Pages zur Laufzeit als Overlay laden möchten). Sie können den Wizard-Code aus Beispiel 3-3 anschauen, wenn Sie die <?xml version="1.0"?> Präambel am Anfang des Dokuments notieren, den Pages zwei und drei ein label Attribut geben, und danach mit den Navigationsbuttons im Wizard vor- und zurück springen nachdem Sie die Datei in Mozilla geladen haben.
Applikations-Widgets Wie die meisten Applikation, könnte auch Ihre Menus und Toolbars als Teil der Grundschnittstelle enthalten. Menus und Toolbars sind gebräuchliche mehrzweck Widgets welche den meisten Benutzern bekannt sein sollten. Menus werden oft als Teil der Menuleiste angezeigt, die alle Funktionalitäten der Applikation anbietet, oder als einfaches Menu um eine Auswahl aus mehreren Elementen zu treffen. Buttons erlauben den schnellen Zugriff auf die meistgebrauchten Funktionalitäten und geben dem Benutzer eine Möglichkeit auf die Applikation einzuwirken. Nebst diesen einfachen Dingen, bietet XUL aber auch Widgets um fast alle Interfaces zu kreieren (und dank Mozillas Flexibilität steht es Ihnen frei selbst die nüchtersten Menus so zu stylen wie sie es wünschen. Die Toolbox Wenn Ihre Applikationen wachsen und an Komplexität gewinnen, ist die Toolbox ein netter Weg um Menus, Toolbars und andere Widgets zu plazieren. Eine <toolbox> ist ein spezieller Container, der eine oder mehrere Tool- und/oder Menubars enthält. Eine Mozilla Toolbar implementiert ein toolbargrippy und eine Box, die die Kind-Elemente enthält. Das toolbargrippy ist eine Markierung auf der linken Seite der Toolbar und erlaubt dem Benutzer die Toolbar ein- beziehungsweise wieder auszurollen. Dies hilft ihm den Raum auf seinem Bildschirm besser Auszunutzen. Toolbars Das <toolbar> Element in Beispiel 3-4 enthält Buttons um verschiedene Applikationsfunktionen auszuführen. Buttons sind die gewöhnlichsten Kind-Elemente einer Toolbar, jedoch bei weitem nicht die einzigen. Toolbar mit Buttons und Spacing <toolbox> <toolbar id="fixed-toolbar" class="toolbar-primary" tbautostretch="always" persist="collapsed"> <toolbarbutton id="newfileBtn" label="New" oncommand="doNew( );" /> <toolbarseparator /> <toolbarbutton id="openfileBtn" label="Open" oncommand="doOpen( );" /> <spacer flex="1" /> </toolbar> </toolbox> Um einen Leerraum zwischen zwei Elementen auszugeben wird das <spacer> Element verwendet. In Beispiel 3-4wird der ganze Leerraum der nach dem Zeichnen der Buttons übrig bleibt, nach den Buttons ausgegeben. Dies ist weil der Spacer an dieser Stelle flexibel definiert wurde, während die Buttons eine feste Grösse haben. Leerräume die an anderen Stellen eingefügt werden, teilen sich den Platz anhand der Flexibilität die über das flex Attribut zugewiesen wird. Sie können die Toolbar aus Beispiel 3-4 so erweitern, dass ein Buttons für die Druckfunktion ganz rechts ausgegeben wird: <toolbarbutton id="newfileBtn" label="New" oncommand="doNew( );" /> <toolbarseparator /> <toolbarbutton id="openfileBtn" label="Open" oncommand="doOpen( );" /> <spacer flex="1" /> <toolbarbutton id="printBtn" label="Print" oncommand="doPrint( );" /> Das <toolbarseparator> Element erzeugt keine neuen Leerräume zwischen den ersten beiden toolbarbuttons. Die angezeigten Leerräume zwischen den Buttons und dem Button für die Druckfunktion sind auf die Definition des flex Attributes der spacer-Elemente als 1 zurückzuführen. Menubar Unter den anderen eingebetteten Elemente in einer Toolbox ist auch die XUL <menubar>. <menubar> selbst ist wiederum ein Container der ein oder mehrere Child-Elemente enthalten kann. <menubar id="fixed-menubar"> <menu label="Quantity" /> <menu label="Color" /> </menubar> Es gibt einen Vorbehalt bei der Verwendung von menubar den Sie kennen sollten. Auf Mac OS wird die Menubar an der Oberkante des Bildschrims angezeigt. Falls Ihre Menubar Elemente enthält die keine Menu-Elemente sind, werden diese nicht ausgegeben, da das Betriebssystem nicht weiss wie die Widgets ausgegeben werden müssten. Wie Beispiel 3-5 zeigt, ist es sehr einfach eine kleine Applikation mit einer typischen Menubar zu erstellen: Menubar einer Applikation <?xml version="1.0"?> <window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> <menubar id="appbar"> <menu label="File"> <menupopup> <menuitem label="New"/> <menuitem label="Open"/> </menupopup> </menu> <menu label="Edit" /> </menubar> </window> Die komplette XUL Datei aus Beispiel 3-5 erzeugt die Menubar die in Abbildung 3-2 angezeigt wird.
Menubar einer Applikation
Auswahllisten Es gibt verschiedene Wege um in Mozilla Listen zu erstellen. Dieser Abschnitt zeigt anhand eines Beispiels drei Varianten um einem Benutzer eine Auswahlliste anzuzeigen. Die Optionen werden in Abbildung 3-3 gezeigt. Alle drei Representationsformen -- Menus, Popups und Menulisten -- haben eine Gemeinsamkeit: sie alle verwenden Menuitems um die Auswahl anzuzeigen. <menuitem label="Tachinidae" oncommand="changeF(1)"/> <menuitem label="Tanyderidae" oncommand="changeF(2)"/> <menuitem label="Tipulidae" oncommand="changeF(3)"/> <menuitem label="Syrphidae" oncommand="changeF(4)"/> <menuitem label="Tephritidae" oncommand="changeF(5)"/> Wenn Sie die menuitem Elemente oben in einem Menu, einer Menu List oder einem Popup Window verpacken, ergeben sich die Variationen aus Abbildung 3-3.
Visuelle Unterschiede von Menu Widgets
Menus Menus sind wesentlich flexibler als auf den ersten Blick erwartet wird. Zum Beispiel können sie überall in der Benutzerschnittstelle vorkommen, und müssen nicht an der oberen Kante der Applikation befestigt sein. Sie können in Buttons, Trees oder auch ganz alleine vorkommen. Beispiel 3-6 zeigt die Basisstruktur eines Menus. Ein Menu Beispiel <menu label="Quantity"> <menupopup> <!-- menuitems here --> </menupopup> </menu> Es gibt eine rigide Ordnung der eingebetteten Komponenten in einem Menu. Ein Menu enthält ein <menupopup>, das seinerseits eines oder mehrere Menuitems enthält. Optional können Sie Gruppen von Menuitems mit Hilfe des <menuseparator>, der eine Linie zwischen die Menu Items zeichnet, aufteilen. Popups Ein Popup ist entweder ein <menupopup> oder ein <popup> Element. Letzteres kann auf verschiedene Arten verwendet werden, aber Beispiel 3-7 konzentriert sich auf die Verwendung in Kontextmenus. Kontextmenu mit einem Popup <popup id="FlyContext" onpopupshowing="return doThis( );" onpopuphiding=" return doThat( );"> <!-- menuitems here --> </popup> Um ein Kontextpopup für dessen aktivierung bereit zu machen, sind ein paar Vorkehrungen zu treffen. Als erstes müssen Sie das Popup anhand der id mit einem anderen Element der Benutzerschnittstelle, mit dem selben Kontext verbinden: <toolbar id="main-toolbar" context="FlyContext" /> Wenn die Toolbar angeklickt wird, öffnet sich das verbundene Popup. Sie können Skripts ausführen wenn das Popup angezeigt/geschlossen wird indem Sie die Methoden onpopupshowing und onpopuphiding verwenden, genau wie wenn Sie Einträge in einem dynamischen Menu ändern. Der zweite Schritt zeigt wie mehrere Popups durch ein <popupset> verbunden werden. Obwohl es nicht unbedingt nötig ist, Popup Sets zu verwenden, ist es doch praktisch, da die Organisation dieser frei platzierten Elemente einfacher wird. frei platziert, weil die Position nicht wie bei Menus und Buttons durch den Platz in der XUL Struktur vorgegeben wird. Weiter gibt es uns so die Möglichkeit die Popups einfacher mit einem Overlay zu verwenden. Menulisten Eine andere Art vion Popup ist die Verwendung von Menu Listen. Eine Menu Liste ist eine Auswahl von Optionen von denen nur eine einzige wählbar ist, oft in der Form eine drop-down Menus - wofür XUL das <menulist> Element anbietet. Beispiel 3-8zeigt eine Menuliste mit einer kleinen Auswahl. Wie bei den anderen Popup Beispielen, wird der Code im oncommand Eventhandler ausgeführt, wenn der Benutzer ein Menuitem auswählt. Eine XUL Menuliste <menulist id="FlyInput"> <menupopup> <!-- menuitems here --> </menupopup> </menulist> Das menulist Widget bietet Funktionailität, die über die eines normalen Menus hinausgeht. Die Menuliste kann editiert werden, wenn der Benutzer einen Eintrag hinzufügen will. In diesem Fall müsste die menulist Definition in Beispiel 3-8 wie folgt geändert werden: <menulist id="FlyInput" editable="true" oninput="onInputFly( );" onchange="onChangeFly( );"> Der Wert true des editable Attributs erlaubt Änderungen an der Liste. Änderungen können dabei während der Eingabe dank des oninput Handlers direkt validiert werden. Das Attribut onchange kann benutzt werden, um ein Script auszuführen, wenn die Selektion ändert.
Tabellarische und hierarchische Informationen Es existieren viele Möglichkeiten, tabellarische oder hierarchische Informationen anzuzeigen. Meist werden dazu Baum- oder Tabellenartige Strukturen verwendet, welche beide (Tree/Table) in Mozilla's XPFE als Elemente existieren. In diesem Abschnitt schauen wir uns List Boxes, Trees und Grids an. Mit der Ausnahme von Tree, sind diese Elemente eingeschränkt welche Inhalte sie aufnehmen können. Tree kann im Moment nur Texte und Bilder enthalten und Grids werden vorallem dazu eingesetzt komplexere Inhalte zu gruppieren, wie wir in den folgenden Beispielen erläutern werden. List Boxes <listbox> wird eingesetzt, um tabellarische Informationen anzuzeigen. Beispiel 3-9 zeigt ein listbox Widget mit allen Basisfunktionen, inklusive der Definition der Anzahl Spalten (listcol), der listbox Kopfzeile (listhead) und eines Listen Elements (listitem). Das Listbox Widget <listbox rows="5" class="list" id="FlyTree" onselect="SelectFly( )"> <listcols> <listcol flex="1"/> <splitter class="tree-splitter"/> <listcol flex="1"/> </listcols> <listhead> <listheader label="Name" /> <listheader label="Type" /> </listhead> <listitem id="type-d"> <listcell label="Syrphidae" /> <listcell label="flower" /> </listitem> <!-- More Items --> </listbox> Den wichtigsten Punkt den wir uns in Beispiel 3-9 merken sollten, ist die Struktur der Verschachtelung in einem listbox Element. Die Anzahl Spalten wird mit <listcol> Elementen angegeben, die von einem <listcols> Set umgeben sind. Beispiel 3-9 hat zwei Spalten, die von einem verschiebbaren grippy getrennt werden, das auch als Trenner im Listenkopf verwendet wird. Die Zellen dieser Spalten sind in einem einzelnen <listitem> gruppiert. Die Kopfzeile ist optional und hat die gleiche Struktur wie ein Listitem. Wenn Sie diese Struktur einmal erstellt haben, können Sie Ihre Inhalte in eine tabellarischer Form anzeigen. Eine listbox kann keine eingebetteten/multilevel Reihen enthalten. Weiter ist zu beachten, dass das 'class'-Attribut oben, der Listbox ihr einzigartiges Aussehen verleiht. Listboxes und Trees verwenden oft 'class'-basierte Styles um ihr Aussehen und ihre Positionierung zu definieren (bsp: der Column Splitter in Beispiel 3-9). Beispiel 3-9 enthält den Sourcecode für die Listbox aus Abbildung 3-4.
Listbox
High Performance Trees Eine <listbox> kann nur bestimmte Inhalte aufnehmen. Zur besseren Skalierung, und für multilevel Eigenschaften, wurde das <tree> Element kreiert. <tree> ist ein fortschrittliches Tree Widget, das ursprünglich für die Mail/News Komponente von Mozilla erfunden wurde. In seiner ersten Form nannte man es outliner Widget. Tree wurde konzipiert um hohe Performance für grosse Listen zu erreichen. Beispiele dafür sind Newsgroups, Mail Ordner und andere Applikationen die grosse Datenmengen verwalten sollen. Das Tree Widget hat ein einfacheres Layout, ist aber trotzdem etwas komplizierter in der Anwendung, da es sogenannte 'Views' verwendet um geordnete Daten anzuzeigen. Tree Funktionalität Die Implementation des Tree Widgets unterscheidet sich von den anderen insofern, dass die Daten immer erst angezeigt werden wenn der entsprechende Inhalt in den Sichtbereich des Benutzers kommt. Trees sind deshalb besonders effizient um lange Listen von Daten anzuzeigen. Tabelle 3-1 enthält einige der Funktionalitäten des Trees: Die wichtigsten Features von Tree Reihen Features Spalten Features Visuelle Features Normale oder hierarchische Reihen Mehrspaltig Jede Zelle kann vor dem Text ein Bild enthalten Multiselektion basierend auf Selektionsumfang Grössenänderung via Maus Aussehen jedes Elements (row, cell, image, etc) kann über CSS definiert werden Drag und drop, entweder auf Reihen, oder zwischen Reihen Spaltenanzeige einstellbar über Popup Menu in der rechten, oberen Ecke Aussehen des Drop-Feedbacks kann via CSS angepasst werden Der Tree kann via Drag und Drop neu geordnet werden Container öffnen, nachdem mit der Maus eine bestimmte Zeit über dem geschlossenen Container gewartet wird Sortieren via Click auf die Kopfzeile, eigene Views können eigene Sortierreihenfolgen anbieten
Obwohl Trees eine breite Funktionalität aufweisen, können nur Texte und Bilder in den Zellen abgebildet werden. Die listbox ist in dieser Hinsicht flexibler.
Tree Views In einem Tree Widget ist eine view ein Modell der Anzeige der Daten. Views sind sehr flexibel und können mit einfachen Daten (Content View) genausogut umgehen wie mit dynamischen Daten einer angepassten View (custom View) oder einer RDF Datenquelle (Builder View). Tabelle 3-2 zeigt die wichtigsten Funktionen der verschiedenen Views unter Verwendung der generellen Kategorien Datenquelle, Geschwindigkeit und Anwendungsfall. Tree Views Content view Builder view Custom view Die Reihen werden aus dem Inhaltsmodell generiert. Die Reihen werden aus einer RDF Datenquelle generiert. Der Benutzer definierte seine eigene View Implementation. Schnell aber nicht sehr Speichereffizient (Footprint). Schnell und effizient. Am schnellsten und effizientesten. Für kleine Trees, einfach verwendbar. Einigermassen einfach im Gebrauch. Komplexe Implementation.
Wie bereits erwähnt wird das tree Widget in der Anzeige von Mail/News verwendet. Es gibt aber viele andere Orte an denen es ebenfalls eingesetzt wird. Custom Views und Tree Widgets werden im Adressbuch, in JS Debugger, DOM Inspector, Bookmarks und Auocomplete eingesetzt. Builder Views finden sich in der History und Content View in den Preferences.
Die Struktur von Tree Der Inhalt eines Trees wird mit von <tree>, <treecols>, <treecol> und <treechildren> definiert. Beispiel 3-10 enthält eine Definition der Spalten (zwei in diesem Fall) und ein treechildren Platzhalter für den Treebody. Ein Tree <tree id="tree" flex="1"> <treecols> <treecol id="Col1" label="Col1" flex="1"/> <treecol id="Col2" label="Col1" flex="1"/> </treecols> <treechildren/> </tree> Wie bei listbox, muss eine genaue Hierarchie der Elemente berücksichtigt werden. Diese Hierarchie ist Teil des Inhaltsmodells des Trees. Die Organisation der Inhalte eines Trees über die spezifischen Elemente wird weiter unten gezeigt. Im Gegensatz zu listbox, sind verschachtelte Reihen bei Trees möglich. Ein Beispiel solcher Verschachtelung zeigen wir später in diesem Kapitel, in Beispiel 3-11. <treeitem> Dieses Element enthält eine einzelne Reihe und all ihre Kinder-Reihen. Das container Attribut wird verwendet um zu definieren ob eine Reihe als Container verwendet werden soll. Dieses Attribut ist optional. Das Attribut open definiert den Zustand des Containers. <treerow> Die Reihe wird innerhalb des <treeitem> eingebettet. Sie können dem properties Attribut eine durch Leerzeichen getrennte Liste zusätzlicher Eigenschaften übergeben. <treeseparator> Ein spezielles Element, das verwendet wird eine horizontale Trennlinie zu zeichnen. Das properties Attribut wird verwendet wenn Sie weitere Eigenschaften übergeben möchten. <treecell> Das <treecell> Element muss innerhalb einer <treerow> verwendet werden. Es definiert den Text und die Eigenschaften einer Zelle. Das Attribut label wird verwendet um den Text einer Zelle zu setzen. Das ref Attribut korreliert eine Zelle einer <treerow> mit einer Spalte des Trees, und ist optional. In Beispiel 3-11 sehen wir, wie diese Elemente interagieren. Multilevel Tree Content View <tree id="tree" hidecolumnpicker="true" flex="1"> <treecols> <treecol id="type" label="Type" flex="1" primary="true"/> <treecol id="method" label="Method" flex="1"/> </treecols> <treechildren> <treeitem> <treerow> <treecell label="Bike"/> <treecell label="Bicycle"/> </treerow> </treeitem> <treeitem container="true" open="true"> <treerow> <treecell label="Fly"/> <treecell label="Wings"/> </treerow> <treechildren> <! -- Second level row -- > <treeitem> <treerow> <treecell label="Glide"/> <treecell label="Hand-Glider"/> </treerow> </treeitem> </treechildren> </treeitem> </treechildren> </tree> Um ein neues Sublevel zu erzeugen, erstellen Sie ein weiteres <treechildren> Element und setzen ein <treeitem> ein, das seinerseits eine oder mehrere Reihen oder Zellen enthält. Abbildung 3-5 zeigt diese Hierarchie.
Multilevel Tree Hierarchie
Trees in XUL Templates verwenden XUL Templates sind spezielle, eingebaute Strukturen, die erlauben, XUL Elemente dynamisch zu aktualisieren und die oft innerhalb von Trees und Listboxes verwendet werden. Templates benutzen die Stärken des Resource Description Framework (RDF) um Daten aus externen Datenquellen zu lesen und dynamisch XUL Inhalte zu erstellen bezw diese zu aktualisieren. Der folgende Code zeigt die Struktur des Templates, das verwendet wird um die Browser History in Mozilla anzuzeigen: <template> <rule> <treechildren> <treeitem uri="rdf:*" rdf:type="rdf:http://www.w3.org/1999/02/22-rdf-syntax- ns#type"> <treerow> <treecell label="rdf:http://home.netscape.com/NC-rdf#Name"/> <treecell label="rdf:http://home.netscape.com/NC-rdf#URL"/> <treecell label="rdf:http://home.netscape.com/NC-rdf#Date"/> <!-- further cells --> </treerow> </treeitem> </treechildren> </rule> </template> Für jeden Eintrag in der Browser History extrahiert das Template Informationen aus der Datenquelle und rendert diese in eine treecell. Danach aktualisiert sie diese bei jedem Besuch der Seite. Für weitere Informationen konsultieren Sie Kapitel 9. Custom Tree Views Custom Views erweitern die statische Präsentation der Daten in einem Tree. Sie bieten mehr Flexibilität, verschiedene Arten die gleichen Daten anzuzeigen und Interfaces um auf den Inhalten basierendes Verhalten zu definieren. Die Funktionen enthalten das Abfangen einer Treeitem Selektion um danach Aktionen auszuführen, abfragen und setzen von Werten des Trees und die Abfrage der Anzahl Reihen eines Trees. Um eine Custom View zu erstellen, müssen Sie als erstes einen tree instanzieren und danach ein view Object verbinden. document.getElementById('main-tree').treeBoxObject.view=mainView; In diesem Beispiel ist die View aus dem nsITreeView XPCOM Objekt die Lebenslinie des Trees, da sie dessen Daten zur Verfügung stellt. Die View wird dem Objekt zugewiesen, das alle Funktionen und die Implementation dessen was bei ihrem Aufruf geschehen soll, enthält. Funktionen die einem View Object zur Verfügung stehen: setTree(tree) Wird während der Initialisierung aufgerufen und verbindet die Tree View mit dem Frontend. Diese Verbindung garantiert dass der korrekte Tree mit der richtigen View assoziert bleibt. getCellText (row,column) Gibt den Text oder eine leere Zeichenkette einer bestimmten Zelle zurück. rowCount Legt die Anzahl Reihen fest die für den Tree erwartet werden. cycleHeader(index) Wird aufgerufen wenn auf die Kopfzeile einer Spalte geklickt wird. toggleOpenState Wird ausgeführt wenn eine View angezeigt/ausgeblendet wird. setCellText (row, colID, value) Wird aufgerufen um den Inhalt einer Zelle zu editieren. performAction (action) Der Tree ruft diese Methode auf wenn bestimmte Tasten gedrückt werden. Wenn zum Beispiel die ENTER Taste gedrückt wird, wird diese Methode mit der action 'enter' Aufgerufen. Es gibt darüber hinaus noch weitere, lokale Methoden wie performActionOnRow und performActionOnCell. selectionChanged Sollte im <tree> Element mit dem onselect Handler verbunden werden.
Grid Ein <grid> ist eine andere XUL Tabellenart, die jedoch sehr flexibel mit Inhalten umgehen kann. Beispiel 3-12 zeigt ein 2-Spalten Grid, das Textboxes und Labels enthält. XUL Grid <grid> <columns><column flex="1"/><column flex="2"/></columns> <rows> <row align="center"> <label value="Title"/> <textbox id="title-text" oninput="TextboxInput(this.id)"/> </row> <row align="center"> <label value="Author"/> <textbox id="author-text" oninput=" TextboxInput(this.id)"/> </row> <row align="center"> <label value="About"/> <textbox id="about-text" oninput=" TextboxInput(this.id)"/> </row> </rows> </grid> In einem Grid müssen die Spalten in einem <columns> Set definiert und gruppiert werden. In Beispiel 3-12, enthält die erste Spalte die Labels und die zweite Spalte die Textboxes. Diese zwei Spalten sind horizontal zueinander angeordnet. Der Flex ist bei der zweiten Spalte grösser, um mehr Platz für die Textboxes zu haben. Wie alle Beispiele in diesem Kapitel, können Sie Beispiel 3-12 ausprobieren, wenn Sie die XML Processing Instructions und ein umgebendes window Root-Element hinzufügen.
Worte und Bilder Die Text Widgetsi, die nachfolgend beschrieben werden, sind für die Beschriftung anderer Widgets, oder Contexthilfen für den Benutzer, zuständig. Bilder können entweder mit dem image Element oder verschiedenen inline Notationen bei Buttons oder Menus angezeigt werden. Texteingabe Das <textbox> Element ist ein Feld um Texteingaben zu verarbeiten, und funktioniert ähnlich wie das <textarea> Element in HTML. Das normale <textbox> Element hat 1 Zeile. <textbox id="singleFlyInput" /> Wenn Sie das multiline Attribut verwenden, können Sie auch grössere Felder anzeigen. <textbox id="multiFlyInput" value="Fly Name" multiline="true" rows="4" /> Eine multiline Textbox besteht aus 3 Zeilen, kann aber über das rows Attribut vergrössert oder verkleinert werden (Bis auf den Einsatz in einem Container, oder unter Verwendung eines Flex). Um die Anzahl Zeichen bei der Eingabe zu beschränken können Sie das size Attribut verwenden. <textbox id="holdtheFlyInput" cols="3" rows="2" /> Wenn kein value übergeben wird, ist das Textfeld zu Beginn leer. Indem Sie readonly auf true oder false setzen, können Sie zudem definieren, ob der Inhalt des Textfeldes editiert werden kann. Autocomplete Autocompletion nennt man den Prozess, die Eingabe des Benutzers automatisch fertigzustellen. In Mozilla wird dieser Vorgang einfach autocomplete genannt. In der Addressbar des Browsers und der Mail Komponente, werden zum Beispiel Textboxes mit Autocomplete verwendet. Beispiel 3-13 zeigt den Code des 'Webseite öffnen' Dialogs, welcher Autocompletion unterstützt. Text Autocomplete <textbox id="dialog.input" flex="1" type="autocomplete" searchSessions="history" timeout="50" maxrows="6" disablehistory="false" oninput="doEnabling( );"> <menupopup id="ubhist-popup" class="autocomplete-history-popup" popupalign="topleft" popupanchor="bottomleft" onpopupshowing="createUBHistoryMenu(event.target);" oncommand="useUBHistoryItem(event.target)"/> </textbox> Das eingebettete <menupopup> enthält eine Auswahl im drop-down Format. Das relevante Attribut in diesem Beispiel ist type, innerhalb von <textbox>, das den Wert autocomplete hat. Abbildung 3-6 zeigt ein autocomplete Widget. Während dem der Benutzer die URL in die Textbox eingibt, springt das Autocomplete Feature ein und zeigt ihm eine Auswahl früher verwendeter URLs zur Wahl an.
Autocomplete in 'Webseite öffnen'
Text Anzeige In XUL werden 3 Tags eingesetzt, von denen jedes seinen Kontext hat, Textausgaben im Interface zu ermöglichen. Diese Tags lauten <caption>, <label> und <description>. caption wird primär benutzt um Texte anzuzeigen, die inline im Rand einer Groupbox erscheinen. Um zu definieren an welcher Stelle die Anzeige steht, kann das Tag oberhalb oder unterhalb der Groupbox eingefügt werden: <groupbox id="textWidgetsBox"> <caption id="textTitle" label="Text Widgets"/> <!-- content here --> </groupbox> label ist flexibler als caption weil es überall verwendet werden kann, und nicht an eine Struktur gebunden ist. Für längere Texte wird das <description> Element eingesetzt. Sie können beliebigen Text einsetzen, der danach an entsprechender Stelle umgebrochen wird. <description> The mozdev.org site provides free project hosting for the Mozilla community. You are welcome to take a look at the more than 60 projects hosted on the site or to start your own development project. </description> Sie können auch das value Attribut verwenden wenn Sie sicher sind, dass der Text nicht umgebrochen werden muss. In diesem Fall ist <description> identisch mit <label>: <description value="Start a project today." /> Bilder XUL unterstützt die Anzeige von Bildern in den gängigen Webformaten JPEG, PNG und GIF. Die meisten Bilder die Sie im Interface von Mozilla finden sind im GIF Format abgelegt, weil dessen Qualität oft am besten ist. Kapitel 4 geht näher auf solche Theme-Angelegenheiten ein. Die einfachste Syntax zur Anzeige eines Bildes ist: <image src="myImage.png" /> Das <image> Element wird gleich angewendet wie das HTML <img> Element. Das Bild, das angezeigt werden soll wird direkt im src Attribut angegeben. Sie können auch das CSS2 Property list-style-image eines Elements verwenden, um dies zu tun, setzen Sie einen Style Selektor, in unserem Fall setzen wir die id. <image id="foo" /> Das Style Property kennt einen Parameter, src, der auf das Bild, oder eine Ressource mit dem Bild, verweist. #foo { list-style-image: url("myImage.png"); } src kann verwendet werden, wenn einzelne Bilder angezeigt werden sollen. Wir empfehlen der Gebrauch des CSS Properties, da dies dem Prinzip der Trennung von Logik und Inhalt entspricht und Themes zum Beispiel einfacher ausgewechselt werden können. Viele Leute in der OpenSource Bewegung finden, dass ein offenes Format wie PNG besser geeignet wäre. Ein offener Bug mit gamma-korrigierten CSS Farben in CSS1 und CSS2 hält die Entwicklung dieser Idee im Moment leider noch auf. Bilder in anderen XUL Elementen Anhand des list-style-image Properties können Sie fast jedem Element ein Bild zuordnen. Tree zum Beispiel verfügt über einige dieser Properties, die erlauben list-style-image zu definieren. -moz-tree-image definiert die Bilder einer Zelle und über den id Parameter kann definiert werden in welcher Reihe/Spalte das Bild angezeigt werden soll: treechildren:-moz-tree-image(col-id,row-id) { list-style-image: url("chrome://xfly/skin/images/outliner.gif"); } Über -moz-tree-twisty können Sie definieren, wie das twisty aussehen soll, das verwendet wird um Treelevels zu öffnen/schliessen. treechildren:-moz-tree-twisty(open) { list-style-image: url("chrome://xfly/skin/images/twisty.gif"); } Das Beispiel oben verwendet den Parameter open, wenn kein Parameter angegeben wird, ist der Status 'closed' - somit können Sie für beide Stati ein Bild angeben. Auch das <tab> Widget kennt ein list-style-image CSS Property. <tab id="TabOne" class="tabbies" selected="1" label="Click Me!" oncommand="SelectTab(1);" /> In diesem Fall ist das class Attribut der Selektor um die Style Regel mit dem Element zu verbinden: .tabbies { list-style-image: url("chrome://xfly/skin/images/tab.gif"); }
Form Controls In der HTML Welt ist das Textarea eines der wichtigsten Elemente im Formularen. Obwohl das XPFE Toolkit 'Formulare' als solche nicht kennt, lässt es den Benuter in begrenzten Masse HTML Elemente benutzen. Da jedoch Widgets wie Textbox, Checkbox oder Radiogroup zur Verfügung stehen, sollte darauf weitgehend verzichtet werden. Radio Radiogroups sind nützliche Interface Elemente, da sie den Benutzer aus einer Reihe von Möglichkeiten wählen lässt. In HTML wird das Element mit einem <INPUT> Tag mit dem type Attribut radio verwendet. Beispiel 3-14 zeigt, wie man Radiogroups in XUL erstellt. Eine Radiogroup <radiogroup id="flyTypes" orient="vertical"> <radio id="tachina" group="flyTypes" label="Tachinidae" oncommand="chooseType(this);"/> <radio id="primitive-crane" group="flyTypes" label="Tanyderidae" oncommand="chooseType(this);"/> <radio id="crane" group="flyTypes" label="Tipulidae" oncommand="chooseType(this);"/> <radio id="flower" group="flyTypes" label="Syrphidae" oncommand="chooseType(this);"/> <radio id="fruit" group="flyTypes" label="Tephritidae" oncommand="chooseType(this);"/> </radiogroup> Die Optionen müssen von einem <radiogroup> Element umgeben sein, und werden mit einem <radio> Tag dargestellt. Wichtig sind die id Attribute der <radiogroup> und die group Attribute der <radio> Elemente. Diese Attribute sollten identisch sein, um sicherzustellen dass nur eine der Optionen ausgewählt sein kann. Das this Schlüsselwort in JavaScript lässt Sie das ausgewählte Element direkt ansprechen. Im Beispiel wird also jedesmal die Node-id an das Script gesendet wenn, eine Option ausgewählt wird. Checkbox Eine Checkbox ist ein einfacheres Widget, das keiner Gruppe zugeordnet werden muss. Meist wird es benutzt, um festzulegen ob eine bestimmte Funktionalität ein- oder ausgeschaltet werden soll. Sehen Sie dazu Abbildung 3-7. <checkbox id="closeWindow" label="Close this window when download is complete" checked="true" />
Checkbox Widget
Wenn die Box angeklickt wird, wird das checked Attribut aktiviert, das einen positiven Wert andeutet. Sie können dieses Attribut selber setzen um der Checkbox einen Initialwert zu geben.
Buttons Ein Button ist ein Mehrzweck-Widget, das normalerweise in Toolbars und Dialogen verwendet wird. Die zwei Button Elemente <button> und <toolbarbutton> sind im Grunde gleich. Meist unterscheidet nur das class Attribut die beiden. Sie können <toolbarbutton> deshalb ausser- und <button> innerhalb von Toolbars verwenden - obwohl man in der Praxis gleiche Elemente normalerweise gruppiert. Diese Flexibilität hat den positiven Effekt, dass die Buttons in einem bestimmten Bereich mittels getElementsByTagName angesprochen werden können. Eine gängige Version des Buttons enthält einen Text und ein Bild, wobei das Bild meist rechts oder links des Textes angezeigt wird. Möglicherweise möchten Sie jedoch vordefinierte Klassen aus Mozilla selber übernehmen, oder gar eigene Style Regeln definieren um die Anzeige zu beinflussen. Leider ändern sich die Klassennamen innerhalb von Mozilla zu oft, als dass man sie hier alle aufführen könnte. "toolbar-primary" wird oft wiederverwendet. Um weitere Klassen zu finden, sollten Sie sich direkt im Sourcecode umsehen. Der Text auf dem Button wird durch das label Attribut definiert: <button id="newfileBtn" tooltiptext="New File" oncommand="doNew( )" label="New"/> Sie können das Bild mit dem Button verknüpfen in dem Sie das src Attribut oder das CSS Element list-style-image benutzen, wie folgendes Beispiel zeigt: #newfileBtn { list-style-image: url("chrome://editor/skin/images/newfile.gif"); } Button Typen Mozilla enthält mehr als die normalen "click" und "go" Buttons des Toolkits. Tabelle bietet eine Übersicht. Button Typen Typ Gebrauch Beschreibung Menu type= "menu" Button enthält eingebettetes Menu, das durch einen kleinen Pfeil Icon angezeigt wird Dual Menu type= "menu-button" Das Menu wird in einem eigenen klickbaren Gebiet im Button angezeigt Checkbox type= "checkbox" Verbleibt im definierte Zustand wenn angeklickt, springt bei erneuten anklicken in den Originalzustand zurück. Radio type= "radio" Sollte Teil einer Gruppe sein, in der jeweils nur eine der Optionen wählbar ist. Disclosure dlgtype= "disclosure" Zeigt einen Teil eines Dialog an, bezw blendet diesen aus. Default dlgtype= "accept" Führt die definierte Aktion für einen Dialog aus Cancel dlgtype= "cancel" Schliesst den Dialog und führt keine weiteren Aktionen aus. Help dlgtype= "help" Aktiviert kontextsensitive Hilfe
Wenn einer der Button Typen aus Tabelle 3-3 als Beispiel verwendet werden soll, kann der Typ menu-button benutzt werden. Dieser Button erlaubt es, mehr als eine Option anzuzeigen. Mozilla verwendet diese Art zum Beispiel bei den Back/Forward Buttons, bei denen die zuletzt besuchten Seiten aufgelistet werden. Abbildung 3-8 zeigt das Aussehen des 'back' Buttons nachdem mehrere Seiten betrachtet wurden.
menu-button in Mozilla
Andere Anwendungsfelder sind zum Beispiel 'new' Buttons, welche verschiedene Optionen zur Verfügung stellen (new File, new Project, ...) - und bei denen die Standardaktion das erstellen einer neuen Datei ist.
Dialog Buttons Die letzten vier Elemente in Tabelle 3-3 sind Buttons, die vorallem für Dialoge konzipiert wurden. Der einfachste Weg, sie in Dialogen zu verwenden, ist, sie im buttons Attribut des <dialog> Elements zu notieren: <dialog xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" buttons="accept,cancel,help" buttonpack="center" ondialogaccept="return onAccept( );" ondialogcancel="return onCancel( );" ondialoghelp="return doHelpButton( );"> Die Funktionen die aufgerufen werden wenn diese Buttons angeklickt werden, werden in den ondialogaccept, ondialogcancel und ondialoghelp Eventhandler-Attributen definiert. Diese Eventhandler sind am einfachsten, wenn Sie die normalen Buttontexte (Ok,Cancel und Help) verwenden wollen. Falls Sie eigene Texte definieren oder mehr Kontrolle über die Buttons möchten, können Sie dies im dlgtype Attribut notieren: <button dlgtype="accept" label="Go For It!" oncommand="doExtraFunction( )"/> Das buttonpack Attribut bestimmt ob die Buttons rechts, links oder in der Mitte des Fensters angezeigt werden sollen. Wenn kein Wert übergeben wird, werden die Buttons anhand der Plattformdefinition positioniert. Bei Windows rechts, bei Unix in der Mitte.
Widget Interaction Nebst dem Gebrauch von Widgets um einzelne Funktionalitäten im Interface zugänglich zu machen, stellt Mozilla Funktionen zur Verfügung Elemente zusammenzuhängen und so komplexere Aufgaben zu übernehmen. Wenn Sie zum Beispiel mehrere Widgets haben, die die gleiche Funktion aufrufen, können Sie das Command- und Oberserver-System verwenden um die Wiederverwendbarkeit zu steigern. Oder Sie können Command-Sets zusammenstellen und in verschiedenen Teilen Ihrer Applikation überlagern. Ein Beispiel dafür ist die Cut- and Paste-Funktion in Mozillas Interface. Broadcaster und Observer Broadcaster und Observer ist ein Mechanismus um eine Anzahl Elemente über den Zustand eines anderen Elements zu informieren. Dieses 'broadcasting' Element kann ein <broadcaster> oder jedes andere Element sein, das seinen Status über ein spezielles Attribut verbreiten kann. Ein Beispiel dafür, ist das ausschalten eines 'View Source' Buttons und eines Menuitems, wenn die Webseite noch nicht verfügbar ist. Der Status eines Broadcasters muss explizit geändert werden, um die Oberserver zu aktualisieren. <broadcasterset> <broadcaster id="save_command" disabled="false"/> </broadcasterset> Wenn ein Broadcaster Set definiert ist, können in einer XUL Datei die Elemente definiert werden, die diese Broadcasts überwachen. <button id="new" label="Save File" observes="save_command"/> <key id="key_new" xulkey="true" key="s" observes="save_command" /> <menuitem id="new_menuitem" label="New" observes="save_command"/> Observierende Elemente können auch über einzelne Attributsänderungen wachen, dies wird mit dem <observes> Element definiert: <menuitem id="new_menuitem" value="New" observes="open_new"/> <observes element="open_new" attribute="disabled"/> </menu> Das Element Attribut verbindet den Broadcaster und Attribut definiert, dass er auf Statusänderungen von <menuitem> reagieren soll, indem er die gleiche Statusänderung vollzieht. Commands / Befehle In einem <commandset> können unbeschränkt viele andere Commands eingebettet werden, und verschiedene Sets können für verschiedene Events benutzt werden. Weiter ist es möglich, dass Commandsets weitere Commandsets enthalten. Die Idee dahinter ist die, dass ein Basis-Set existiert, von dem alle anderen ausgehen; dieses Set wird meist in der obersten XUL Datei Ihrer Applikation abgelegt. Der folgende Code enthält ein Commandset und bindet ein weiteres Commandset mit ein (moreEditItems). <commandset id="EditItems" oncommandupdate="updateCommandsetItems(this)" commandupdater="true" events="select"> <commandset id="moreEditItems" /> <command id="cmd_cut" oncommand="goDoCommand('cmd_cut');"/> <command id="cmd_copy" oncommand="goDoCommand('cmd_copy');"/> <command id="cmd_delete" oncommand="goDoCommand('cmd_delete');"/> </commandset> Der Command Updater ist ein Mechanismus der verwendet wird um Command Events zwischen den Widgets zu verteilen. Wenn ein Event ausgeführt wird, wird es durch die Commandsets weitergereicht. Wenn im Beispiel oben, das select event aktiviert wird, werden alle Elemente dieses Sets aktiv. So können durch das setzen des disabled Attributs, alle angeschlossenen Widgets ausgeschaltet werden. Es gibt verschiedene Wege den Command Updater zu starten. Erstens, assozieren des Widgets mit einem Command unter der Verwendung des command Attributs: <button id="cut-item" label="Cut" command="cmd_cut" enabled="true"/> Wenn der Button angeklickt wird, wird das Command (cmd_cut) gesucht und ausgeführt indem die goDoCommand Routine für das entsprechende Command aufgerufen wird. Alternativ kann Ihre Applikation ein 'select' Event für einen Text oder ein Bild enthalten. Wenn dieses Event ausgelöst wird, läuft es durch das Commandset, das seinerseits mittels oncommandupdate die anderen Widgets aktualisiert. Das Keyset Element wird benutzt, um Aktionen bei Tastendruck auszulösen. Die Tastenkomination Ctrl-Shift-s kann so zum Beispiel als 'Speichern' definiert werden. <key id="key_saveas" key="s" modifiers="control,shift" command="cmd_saveas"/> Das Key Element kennt verschiedene Attribute, wie key, das die Taste definiert, die den Aufruf auslösen soll. modifiers="accel" definiert, dass bei Windows und Unix Plattformen die Ctrl-Taste und bei Macintosh der Command Button gedrückt werden müssen. Beispiel 3-15 zeigt ein einfaches Fenster, das alle Sets enthält: Commands, Broadcasters und Keys. Shortcut Keys mit Command Observer <?xml version="1.0"?> <window id="hello-goodbye" title="Hello Goodbye" xmlns:html="http://www.w3.org/1999/xhtml" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" style="min-width:100px;min-height:100px;background-color:white;"> <broadcasterset id="broadcasterset"> <broadcaster id="cmd_hello" oncommand="alert('Hello There!');" /> </broadcasterset> <keyset id="keyset"> <key id="key_h" key="H" observes="cmd_hello" modifiers="accel,shift" /> <key id="key_g" key="G" command="cmd_goodbye" modifiers="accel,shift" /> </keyset> <commandset id="commandset"> <command id="cmd_goodbye" oncommand="alert('Goodbye!');" /> </commandset> <spacer flex="1"/> <label value="hello/goodbye"/> <textbox value="type ctl+shft+h"/> <textbox value="type ctl+shft+g"/> <spacer flex="1"/> </window> Content Panels Content Widgets erlauben es Ihnen, Inhalte in einem Fenster zu laden. Diese Widgets -- browser und editor -- können entsprechende Inhalte laden. Zum Beispiel HTML, XML oder text. Browser und IFrame Das <browser> Element bietet Ihrer Applikation komplette Browser-Eigenschaften, inklusive Navigation und History. <browser id="content" type="content-primary" src="ch3.html"/> browser bietet folgende Interfaces die in Ihren Scripts verwendet werden können: nsIDocShell nsIWebNavigation nsIMarkupDocumentViewer nsIContentViewerEdit nsIContentViewerFile nsIWebBrowserFind nsIDocumentCharsetInfo Ohne weiter in die Details zu gehen sei gesagt, dass diese Interfaces komplexe Funktionalität im Umgang mit webbrowsing und anderen browserspezifischen Dingen ermöglichen und durch Javascript ansprechbar sind. Weitere Informationen dazu finden Sie in den IDL Dateien mit dem selben Namen im Mozilla Source Tree. Wenn Sie mehr zu diesen Interfaces erfahren wollen, ist der beste Ort dazu der Sourcecode von Mozilla. Die zwei wichtigsten Dateien sind browser.xml, die zeigt welche Interfaces benutzt werden können und navigator.js, die aufzeigt wie diese Interfaces verwendet werden. Beide Dateien können in der online Mozilla Cross Reference, unter http://lxr.mozilla.org eingesehen werden. Eine Alternative zu <browser> ist <iframe>. Da es dem Browser im Aussehen sehr ähnlich ist, ist es sehr gut für kurzlebige Inhalte verwenbar, zum Beispiel als Vorschau-Fenster in einem HTML/XML Editor oder anderen WYSIWYG Applikationen. IFrames sind auch sehr gut dazu geeignet Dokumente dynamisch zu editieren: <iframe id="simple-content" /> Die Methoden open( ), write( ) und close( ) werden benutzt um ein Dokument zu editieren: var doc = window.frames[1].document; doc.open( ); doc.write("<html><body>Come fly with me ...</body></html>"); doc.close( ); In diesem Beispiel greifen wir auf das Dokument zu, indem wir es über window.frames ansprechen, dem Objekt, das alle Frames enthält. Wenn mehrere Frames vorkommen werden diese numeriert. Im Beispiel verwenden wir das zweite Frame (Element 1 in einem 0-basierten Array Index). Die doc Variable hält eine Referenz zum Inhalt und verwendet die Methoden des document um es zu editieren. Ideen für Control Panel sind: Diese Beispiele dienen nicht dazu aufzuzeigen wie Sie die Gecko Engine in einer eigenen Applikation integrieren, dafür sind ein anderes Toolkit und ein Set von APIs verfügbar. HTML oder XML Helpseiten, die in der Applikation durch den Browser geladen werden. Vorschau Fenster: testen Sie Ihr XML, HTML oder CSS Layout und Styling in Gecko. Eine Font-Vorschau, ähnlich wie im vorhergehenden Beispiel, aber mit mehreren verschiedenen Elementen, die sich je nach Auswahl des Benutzers ändern. Kleine Fenster, die Webinhalte anzeigen Editor Das <editor> Element lädt editierbare Inhalte und kann mit Text und HTML umgehen. Ein gutes Beispiel dafür ist der Mozilla Composer, der HTML Editor, der in Mozilla enthalten ist. Das <editor> Tag erstellt eine Instanz von nsEditorBoxObject. Von diesem Punkt an, können Sie via Javascript (element.editorShell) auf die editorShell Methoden zugreifen. Der Editor wird an verschiedenen Orten in Mozilla eingesetzt. Zum Beispiel in einer textbox in HTML Forumlaren und um Nachrichten in Mail/News zu schreiben. Reine Text-Widgets unterscheiden sich insofern, als dass sie nur limitierte Editiereigenschaften zur Verfügung stellen. Anwendungen des Editors, sowohl praktisch als auch spekaultiv: Plaintext Editor HTML Formular Editor Ein Bulletin Board das mit HTML arbeitet, ein Gästebuch Formular oder ein Wiki Interface um Kommentare zu posten. Instant Messaging Dokumente mit mehreren Frames verarbeiten Die Inhalte in einem <browser>, <iframe> und <editor> werden als einzelne Dokumente behandelt. Wie können Sie also auf spezifische Inhalte zugreifen? Um auf alle Frames eines Dokuments zuzugreifen benutzen Sie: var contentAreas = content.frames; Um ein Frame auszuwählen, können Sie entweder dessen id oder den Index verwenden. Nach Index, Start 0: var content = window.frames[ 1 ]; Nach id: var content = window.frames[ contentId ]; Dieser Code gibt das zweite Frame zurück. Um ein IFrame als Standard zu definieren, setzen Sie dessen Attribut type und geben ihm einen eindeutigen Wert. <iframe id="print-panel" type="content-primary" src="about:blank" flex="1""/> Danach können Sie so auf den Inhalt zugreifen: window.content.print( ); Das Box Modell Das box model ist der einfachste Weg, Elemente in einem Fenster zu positionieren. Obwohl dies auch über Layout-Attribute des window Elements (ein Box basierter Container) möglich ist, können Sie mit Boxes Widgets verschachteln, ausrichten und positionieren wie Sie wünschen. Das Box Modell definiert: Wieviel Platz ein Element in Relation zu seiner Umgebung einnehmen darf. Die Ausrichtung der Elemente Die Verbindung der Elemente untereinander Raum kann auf verschiedene Weisen definiert werden. Sie können den Fenstern zum Beispiel fixe Grössen geben, oder den Widgets, die in dem Fenster enthalten sind. Oder Sie können die Elemente sich selbst an die Platzverhältnisse anpassen lassen. Boxes zu verwenden optimiert das Layout Ihrer XUL Fenster und Dialoge. Box Attribute Über das XUL Element <box> können verschiedene Attribute gesetzt werden, die sich auf das Layout auswirken. Boxes können verschachtelt werden um das Layout des Interfaces zu definieren. Dabei belegen einige Boxes den gesamten, ihnen zur Verfügung stehenden Platz, andere nur genug um die eigenen Inhalte darzustellen. Attribute der Box und derer Kindelemente definieren wie die Inhalte in einer Box angezeigt werden, die Art wie die Fenstergrösse geändert werden kann und die Ausrichtung der Elemente, wie Tabelle 3-4 beschreibt. Normale Box Attribute Attribut Wert Standardwert Beschreibung align start | end | center | baseline | stretch | inherit stretch Definiert wie die Kinder ausgerichtet werden. flex <number> | inherit 0.0 Definiert die Flexibilität eines Elements style CSS Property oder Wert N/A Fügt der Box CSS Style Regeln hinzu orient horizontal | vertical | inline-axis | block-axis | inherit inline-axis Definiert die Ausrichtung der Kindelemente innerhalb der Box pack start | end | center | justify | inherit start Definiert was mit dem übrigbleibenden Raum gemacht werden soll, wenn alle Objekte in Ihrer vollen Grösse angezeigt werden. direction normal | reverse | inherit normal Definiert die Richtung der Kindelemente ordinal-group <integer> | inherit 1 Kontrolliert die Reihenfolge in der die Widget erscheinen.
Die Attribute in Tabelle 3-4 (mit Ausnahme von style), werden direkt an der Box definiert. Es gibt dazu aber auch CSS Properties, die den Prefix box- tragen. pack wird zum Beispiel zu box-pack. Da diese Properties nicht Teil der CSS Spezifikation sind, müssen wir noch einen Schritt weiter gehen und das Format -moz-box-pack verwenden. Diese speziellen Erweiterungen werden in Abschnitt in Kapitel 4 näher erläutert. Die meistgebrauchten Attribute sind orient, align und pack. Die Ausrichtung der Elemente kann entweder horizontal oder vertikal erfolgen. Der Standardwert ist horizontal für eine normale <box>. Andere Box-Typen (wie <groupbox>) sind vertikal ausgerichtet. <vbox> und <hbox> wurden zur Vereinfachung entwickelt, einerseits, um dieses Attribut zu umgehen, aber auch um die Renderzeit zu senken. Folgend, ein Beispiel davon, wie 'pack' und 'align' das Layout beinflussen. Zuerst ein bisschen Code: <vbox style="width: 90px; height: 90px"> <button label="Pack Me!" /> <label value="This text is naturally aligned to the left" /> </vbox> Dieser Code weist dem Button keine Position zu. Deshalb wird er an der Standardposition angezeigt: Abbildung 3-9.
Standardpositionierung
Hier eine angepasste Version mit gesetzten align und pack Attributen: <vbox style="width: 90px; height: 90px" align="right" pack="center"> Wie Sie sehen, ändert dies die Anzeige ziemlich: Abbildung 3-10.
Box Alignment und Packing
Der Wert von align positioniert beide Elemente rechts in der Box, beschränkt die Grösse des Buttons auf das notwendigste und gibt dem label den benötigten Platz. pack zentriert danach beide Elemente horizontal.
Boxartige Container Eine normale XUL Box wird vorallem durch <box>, <vbox> und <hbox> gestaltet, es gibt aber noch weitere, Box-ähnliche Container: <radiogroup>Radiogroup Element, XUL <scrollbox>Scrollbox Element, XUL <tabbox>Tabbox element, EUL <groupbox>Groupbox Element, XUL <toolbox>Toolbox Element, XUL <stack>Stack Element, XUL <deck>Deck Element, XUL <listbox>Listbox Element, XUL <popup>Popup Element, XUL <statusbar>Statusbar Element, XUL Weitere Informationen zu Box Widgets finden Sie in der Referenz in Anhang C. Hier noch ein paar Beschreibungen zu Tabbed-Boxes: Tab Box Tab Boxes können nur <tabs> und <tabpanels> enthalten, wie in Beispiel 3-16 gezeigt wird. Darüber hinaus gibt es keine Einschränkungen welche Inhalte Panels enthalten dürfen. Um eine korrekte Anzeige zu garantieren sollten Sie immer gleich viele Tabpanels wie Tabs benutzen. Tabbed Panels <tabbox orient="vertical" flex="1"> <tabs> <tab label="Fish" /> <tab label="Birds" /> <tab label="Coders" /> </tabs> <tabpanels flex="1"> <button label="Swim"/> <button label="Fly"/> <button label="Hack"/> </tabpanels> </tabbox> Beispiel 3-16 zeigt, wie einfache Tab-Panels erstellt werden, die Tabs werden mit den Panels anhand der Reihenfolge im Code assoziert. Status Bar Eine Statusbar ist eine horizontale Box, die am unteren Rand einer Apllikation angezeigt wird. Die <statusbar> enthält normalerweise Icons und Text in einem oder mehreren <statusbarpanel> Elementen. <statusbar id="ch3-bar" persist="collapsed"> <statusbarpanel class="statusbarpanel-iconic" id="book-icon"/> <statusbarpanel id="status-text" label="Thanks for reading chapter 3" flex="1" crop="right"/> <statusbarpanel class="statusbarpanel-iconic" id="book-icon-2"/> </statusbar> Als Box verhält sich die Statusbar wie jedes andere Widget. Die Panels begrenzen ihre Grösse auf den ihnen zugewiesenen Platz und Flex. In diesem Beispiel erscheinen die Icons links und rechts der Statusbar, während dem das Textpanel mit dem Flex den übrigen Platz beansprucht. Weitere Box Features Boxes arbeiten mit <separator> und <spacer> zusammen. Diese beiden Elemente kreieren Platz zwischen Widgets in einer Box und können horizontal oder vertikal ausgerichtet werden. Der Separator ist ein sichtbarer Trenner und der Spacer bleibt unsichtbar. Die Standardgrösse von beiden ist klein, kann aber, wie bei anderen Elementen, durch die flex, width und height Werte beeinflusst werden. Korrekt angewandt haben sie grossen Einfluss auf das Aussehen Ihrer Interfaces. Visibility / Sichtbarkeit Sie können die Sichtbarkeit einer Box nach Wunsch ändern, zum Beispiel wenn Sie Dialoge machen möchten die man aufklappen kann, oder Text anzeigen wollen, nachdem der Benutzer eine Auswahl getroffen hat. Ein Weg dies zu kontrollieren ist über das collapsed Attribut: <box flex="1" collapsed="true" /> Sie können auch das CSS Property display auf none setzen: <box flex="1" style="display: none;" /> Das Dokument wird gerendered als ob es nicht existieren würde. Wenn Sie den Leerraum zwischen den Elementen erhalten wollen, können Sie dazu das CSS visibility Property verwenden: <box flex="1" style="visibility: hidden;" /> Den Leerraum anzuzeigen verhindert, dass das Interface flackert wenn Teile angezeigt und wieder ausgeblendet werden. Overflow / Overflow Verhalten Die Werte scroll und auto für das CSS overflow Property stellen sicher, dass Scrollbalken angezeigt werden wenn der Inhalt ansonsten unzugänglich wäre. Der Wert hidden versteckt den Inhalt ausserhalb der Box. Der Inhalt wird nicht abgeschnitten wenn dieser Wert auf visible gesetzt wird, dann wird der Inhalt ausserhalb der Box angezeigt. <vbox flex="1" style="height:39px;overflow: auto;"> Dieses Codeschnipsel beschränkt die Höhe der Box, zeigt aber einen Scrollbalken an, wenn der Inhalt den verfügbaren Platz übersteigt. Stacks und Decks Spezielle Varianten von box sind mit stack und deck verfügbar. Beides sind auch Boxes, zeigen jedoch die Kind-Elemente, einem Kartenstapel ähnlich, übereinander an. Ein stack zeigt alle Level gleichzeitig an. Wenn Sie Transparenz oder zusätzlichen, freien Platz auf einem Level haben, sehen Sie die darunter liegenden Elemente. Somit können Stacks auch verwendet werden, wenn Sie Schatten oder transparente Layer-Effekte verwenden wollen. Abbildung 3-11 zeigt ein Beispiel eines Stacks. <stack> <image src="logo5.gif"/> <label value="BUZZ ..." style="font-weight:bold; font-size: large" top="70px" left="140px"/> </stack>
Text auf einem Bild
Decks zeigen nur ein Level an. In Beispiel 3-17 wird logo3.gif zuoberst angezeigt, weil das Attribut selectedIndex des Decks auf 2 gesetzt ist. Ein Deck mit 3 Bild-Layern <deck id="fly-deck" selectedIndex="2"> <image src="logo1.gif" /> <image src="logo2.gif" /> <image src="logo3.gif" /> </deck> Wie Beispiel 3-18 zeigt, ist es möglich, durch DOM Manipluation die Anzeige zu ändern, indem der Index des Decks geändert wird. Die Methode setAttribute ändert das selectedIndex Attribut des Deck element im Script, und kann zum Beispiel ausgeführt werden, wenn der Benutzer einen Button anklickt. Deck Layer umschalten var deck = document.getElementById("fly-deck"); var selected = deck.getAttribute("selectedIndex"); if (!selected) selected = 0; if (selected < 2) { selected = parseInt(selected) + 1; deck.setAttribute("selectedIndex", selected); } else { selected = 0; deck.setAttribute("selectedIndex", selected); } Wenn Sie dieses Script mit dem Code aus Beispiel 3-17 verwenden, sorgt er dafür, dass unaufhörlich das nächste Bild im Deck-Stapel angezeigt wird, wenn Sie den Button betätigten. Bewegbare Inhalte Früher gab es das bulletinboard Element, welches zuliess dass Elemente übereinander gestapelt und anhand der left und top Attribute positioniert werden konnten. Als stack entwickelt wurde und immer mehr dieser Funktionalität übernahm, wurde bulletinboard entfernt und die übrigen Features in das stack Element eingebaut. Wie Beispiel 3-19 zeigt, war dies für das stack Element von Vorteil. Die zwei Boxes im Beispiel werden anhand ihres Abstands zur oberen linken Ecke des Stacks positioniert. Positionierung in einem Stack <stack> <box id="box1" top="20px" left="40px"> <image src="logo1.gif" /> </box> <box id="box2" top="40px" left="50px"> <image src="logo2.gif" /> </box> </stack> Sie können die Position der Boxes wie folgt ändern: Indem Sie die top und left Attribute innerhalb des Tags definieren. Indem Sie die CSS Properties top und left benutzen Oder durch DOM Manipulation Folgendes Script ändert die Positionierung durch die Änderung der Attribute top und left: Box1=document.getElementById("box1") Box1.setAttribute("top","40px") Box1.setAttribute("left","50px") Box2=document.getElementById("box2") Box2.setAttribute("top","20px") Box2.setAttribute("left","40px")
XUL Attribute Jedes XUL Element hat ein attributes Property, das einen Array aller seiner Attribute enthält. Dieser Abschnitt geht auf ein paar Attribute (unter anderem debug) ein, die in der Entwicklung hilfreich sind. FlexibilitĂt von Elementen Ein Objekt wird anhand des flex Attributes als flexibel definiert. Flexible Objekte können ihre Grösse ändern, wenn die umgebende Box ihre Grösse ändert. Wann immer freier Platz im Layout verfügbar ist, ändert sich die Grösse flexibler Objekte um diesen Platz optimal auszunutzen. Die FlexibilitĂt wird mit einem numerischen Wert definiert und ist relativ. Wenn ein Kindobjekt den Flex 2 hat, ist es zweimal so flexibel wie ein Kindobjekt mit Flex 1, wie Beispiel 3-20 zeigt. Das flex Attribut ist unabdingbar für die Positionierung im Box Modell. Flexible Buttons <?xml version="1.0"?> <?xml-stylesheet href="chrome://global/skin" type="text/css"?> <window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> <box id="parent" style="margin: 50px;"> <button flex="2" label="flex2" /> <button flex="1" label="flex1" /> </box> </window> Style Das style Attribut erlaubt es Ihnen, dem Element CSS Style Regeln zuzuweisen. Sie können so die Werte für width, height, min-width, min-height, max-width und max-height inline definieren, womit Sie mehr Kontrolle über das Layout haben. <button style="height: 20px; background-color: blue;" /> Wenn Sie mehr als ein Theme für Ihre Applikation anbieten wollen, sollten Sie das style Attribut nicht zu oft verwenden. Konsultieren Sie Abschnitt 4.2.1.3 in Kapitel 4 für mehr Informationen über Attribute, und wie Sie Ihre Applikation modularer machen können. Nebst einem anderen, für manche besseren, Weg einem XUL Dokument Styles zuzuweisen. Persistenz Das persist Attribut speichert den Zustand von Elementen und Fenstern auf einer Attribut-für-Attribut Basis. Dieses Feature ist sinnvoll, wenn der Benutzer Einstellungen an der Applikation verĂndern kann, die bei einem Neustart erhalten bleiben sollen. Beispiele davon sind die Fenstergrösse, der Splitter Status und die Sichtbarkeit einzelner Elemente. <splitter id="sidebar-splitter" collapse="before" persist="state hidden" align="center" orient="vertical"> Wenn der Status eines Splitters ändert -- wenn der Benutzer also das <grippy> bewegt, oder den Splitter schliesst -- und danach die Applikation verlässt, wird der Zustand des Splitters erhalten. Das debug Attribut Viele XUL Elemente, vorallem Container-Elemente wie Box und Toolbar, unterstützen das Attribut debug, das dem Entwickler nützliche Informationen verschaffen kann. Wenn debug auf true gesetzt ist, werden um das Element und dessen Kinder spezielle Ränder gezogen, die je nach Level eine andere Färbung aufweisen. Dieses Attribut wird benutzt, um die Ausrichtung und die Flexibilität eines Elementes zu prüfen. debug zeigt horizontale Boxes in blau, vertikale in rot an. Der Rand ist gewellt wenn es sich um ein flexibles Element handelt und durchzogen wenn es ein fixes Element ist. Overlays Ein Overlay ist eine separate Datei, die XUL enthält und zur Laufzeit eingebunden wird. Overlays werden somit oft für Menus verwendet die an mehreren Orten in der Applikation angezeigt werden sollen. Wenn Sie eine grosse Applikation entwickeln, kann es sein, dass Ihr Quellcode sehr gross wird. Obwohl die Grösse selber kein Problem bei der Performance mit sich bringt, wird es für den Entwickler schnell schwierig Änderungen vorzunehmen. Der einfachste Weg dies zu umgehen, ist, Overlays zu verwenden. Ein weiterer Grund ist die modularisierung der Codebasis, was einer erhöhten Wiederverwendbarkeit gleichkommt. Wie Overlays verwendet werden Die folgende Deklaration ist die hauptsächliche Methode um Inhalte einzubinden: <?xul-overlay href="chrome://global/content/globalOverlay.xul"?> Diese Deklaration folgt der Syntax von CSS Instruktionen. Wie andere XML basierende Instruktionssprachen (a.d.Ă: xslt,..) wird ein ? Zeichen an Anfang und Ende einer Instruktion erwartet. Das href Attribut verweist auf den Ort an dem das Overlay abgelegt ist und verwendet Mozillas chrome:// URL. Um Inhalte aus einem Overlay einzufügen, verwenden Sie die selbe id eines Elements in der Basisdatei, bei einem Element im Overlay. Das Overlay wird danach an dieser Stelle eingefügt / zusammengefügt. Weitere Informationen dazu finden Sie in Abschnitt 3.11.2 Wenn das Basiselement leer ist, wird der Inhalt des Overlays an dieser Stelle eingefügt. Folgendes Beispiel zeigt wie die Toolbar in einer Basisdatei referenziert wird. <toolbar id="main-toolbar" /> Wenn ein Overlay mit diesem Inhalt gelesen wird, wird die vorhergehende Zeile dadurch ersetzt: <toolbar id="main-menubar" persist="collapsed"> <toolbarbutton id="new-button" label="New" observes="cmd_new"/> <toolbarbutton id="open-button" label="Open" observes="cmd_open"/> <toolbarbutton id="save-button" label="Save" observes="cmd_save"/> </toolbar> Overlay-Datein sind XUL-Dateien mit einer .xul Endung. Der Inhalt der Datei muss in einem <overlay> Element enthalten sein, das als Root des Dokuments dient. Die Toolbar also in diesem Fall ein Kind-Element von Overlay: <overlay id="xflyOverlay"> <toolbar id="main-toolbar" /> <!-- more overlay content --> </overlay> Styles von Oberlays überschreiben die Styles die in der Basisdatei angegeben wurden, stellen Sie deshalb sicher, dass Sie in Overlays keine Masterstyles laden. Dynamic loading / dynamisches laden von Inhalten Normalerweise werden Inhalte über Overlays geladen, wie im vorhergehenden Abschnitt erläutert wurde. Dynamisch neue Inhalte zu laden ist etwas subtiler. Mozilla unterhält ein Registry aller Overlays in seinem chrome Verzeichnis. Diese Overlays sind in einem Verzeichnis namens overlayinfo abgelegt. Kapitel 9 hat mehr Informationen zu RDF Datenquellen. Um mehr Informationen zum Chrome Layout und Installationsvorgängen zu erhalten, schlagen Sie Kapitel 6 auf. Wenn ein neues Packet registriert wird, werden dessen Overlays automatisch geladen. Dynamische Oberlays werden benutzt, um bestimmte Teile der Applikation zu erweitern. Themes und Language Packs benutzen diese Schnittstelle beispielsweise. Einige Menus des Interfaces sind offen für andere Benutzer, die somit zum Beispiel dem Task-Menu weitere Optionen hinzufügen können. Kapitel 6 hat weitere Informationen zu diesem Gebiet, in Abschnitt 6.2.3.3. Positionierung von Inhalten Die Positionierung der Inhalte wird normalerweise über die Reihenfolge gesteuert, in der die Elemente in der XUL-Datei definiert wurden. Es gibt jedoch verschiedene Wege, diese Platzierung zu überschreiben. Wie gesagt ist es erlaubt, dass sowohl das Overlay Element in der Basisdatei, als auch das Overlay selbst, weitere Elemente enthalten kann. In diesem Fall wird der Inhalt zusammengefügt, wobei der Originalinhalt vor dem des Overlays erscheint. <toolbar id="main-toolbar"> <toolbarbutton id="print-button" label="Print" observes="cmd_print"/> </toolbar> Wenn toolbarbutton in der Basisdatei enthalten ist, sollte die Reihenfolge der Buttons Print, New, Open, und Save sein. Es ist jedoch möglich diese Reihenfolge, mit Hilfe von insertbefore zu unterbrechen, wie in Beispiel 3-21 gezeigt wird. Positionierende Attribute <toolbar id="main-toolbar" persist="collapsed"> <toolbarbutton id="new-button" label="New" observes="cmd_new" insertbefore="print-button"/> <toolbarbutton id="open-button" label="Open" observes="cmd_open"/> <toolbarbutton id="save-button" label="Save" observes="cmd_save" position="2"/> </toolbar> Das Attribut insertbefore weist ein Kind-Element an, sich vor dem nächstfolgenden in der Basisdatei einzufĂgen. insertbefore verwendet die id eines Elements und definiert in diesem Fall, dass der New Button vor dem Print Button sein soll. Um ein Element nach einem anderen Element anzuzeigen, können Sie insertafter verwenden. Anhand des position Attributs können Sie die absolute Position eines Elements angeben, was zur Folge hat, dass in Beispiel 3-21 die Reihenfolge am Ende New, Save, Print und Open anzeigt. Extras Einige weniger bekannte Elemente sind unabdingbar für den cleveren XUL Entwickler, da mit ihnen einer Mozilla Applikation das spezielle Etwas verliehen werden kann. Tooltips Tooltips sind visuelle Popups die erscheinen, wenn der Cursor über einem Teil des Interfaces für längere Zeit verweilt. Dieses Verhalten ist an verschiedenen Orten nützlich, zum Beispiel um Hilfen anzuzeigen, oder Texte vollständig auszugeben die sonst zu lang wären. In einer Mozilla Applikation werden sie vorallem bei Toolbar Buttons und Splitter Grippies benutzt, die Panels innterhalb des Fensters teilen. Um einen Tooltip hinzuzufügen, setzen Sie einfach das Attribut tooltiptext. <button id="printButton" label="Print" tooltiptext="Print this page" /> Dieses Attribut zu definieren reicht aus, um einen generischen Tooltip anziegen zu lassen, wenn der Benutzer mit der Maus über dem Element verweilt. Tooltips sind als XBL-Binding implementiert. Als Basis dient ein Popup Fenster mit einem 'description' Element das den Text anzeigt. Sie können auch eigene Tooltips entwerfen. So erstellen Sie einen eigenen Tooltip: Erstellen Sie den Inhalt. Verbinden Sie ihn mit dem Popup Element das Sie verwenden wollen. Geben Sie dem Popup eine einzigartige ID. Folgenden Code können Sie in Ihrer Applikation verwenden: <popupset id="aTooltipSet"> <popup id="myTooltip" class="tooltip" onpopupshowing="return FillInTooltip(document.tooltipNode);" > <description id="TOOLTIP-tooltipText" class="my-tooltip-label" flex="1"/> </popup> </popupset> Verbinden Sie das neue Widget, indem Sie dessen id dem tooltip Attribut eines Elements übergeben. <treeitem id="FlyDescription" tooltip="myTooltip" tooltiptext="" /> Achtung, gehen Sie davon aus dass der Text in diesem Beispiel dynamisch dem tooltiptext Attribut hinzugefügt wird. Dies ist in vielen Situationen sinnvoll, zum Beispiel, wenn Sie Informationen in einem Tree anzeigen wollen. Der Vorteil eigene Tooltips zu erstellen liegt darin, dass Sie auch eigene Styles dafür definieren können. Eine Variation von tooltip ist übrigens contenttooltip das in Content Panels verwendet wird. Fortschrittsanzeige Manchmal benötigen Sie für eine Applikation eine Anzeige die den Benutzer über den Fortschritt eines Prozesses informiert. Das beste Beispiel ist die Ladeanzeige eines Browsers die verwendet wird, um dem Benutzer anzuzeigen, dass eine Seite geladen wird. Bei Aktivitäten wie Dateidownloads wird der determinierte Typ von Fortschrittsanzeigen verwendet, da errechnet werden kann, wie lange der Download dauern wird. Bei Anwendungen bei denen im Voraus nicht sicher ist, wie lange sie dauern werden, wird eine undeterminierte Anzeige empfohlen, die dem zweiten Modus für Fortschrittsanzeigen entspricht. Der dritte Modus ist 'normal', wobei ein leerer Balken angezeigt wird. Sie können den Modus über das mode Attribut festlegen. Hier der XUL Code für eine einfache Fortschrittsanzeige: <progressmeter id="progressTask" mode="normal" value="0" onclick="alert(`Task is in progress')"/> Und hier das Script dazu: var meter = document.getElementById('progressTask'); meter.setAttribute('mode', 'undetermined'); sometask( ); meter.setAttribute('mode', 'determined'); meter.setAttribute('value', '100%'); Der Modus wechselt kurz bevor die Operation sometask() ausgeführt wird zu 'undetermined'. Der Javascript Code ist synchron und wird somit die Kontrolle nicht vor Erledigung der Funktion zurückgeben. Links Mozilla ist eine Webapplikation und viele Betriebssysteme (wie Windows XP) bewegen sich auf eine vollständige Webintegration zu. Links sind somit fundamental und werden von Mozilla auf verschiedene Arten unterstützt. Verwendung des <html:a> Elements Um HTML in Ihrer XUL Datei direkt benutzen zu können, müssen Sie dies am Anfang des Dokuments deklarieren: <window id="MyOverlay" xmlns:html="http://www.w3.org/1999/xhtml" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> Danach können Sie HTML Element genau wie auf einer Website verwenden, wenn Sie die Namespace voranstellen: <vbox> <html:a href="myOverlay.html">Go to Help page</html:a> </vbox> Wenn Sie eine Seite mit Links in Ihrer Applikation verwenden, kann der Benutzer diese Links anklicken und den Mozilla Browser zur Ansicht benutzen. Einfache XLinks Wenn Sie die korrekte Namespace verwenden, können Sie auch XLinks gebrauchen, die erweiterte XML Funktionalität bereitstellen: <window xmlns:xlink=http://www.w3.org/1999/xlink ...> Danach können Sie Links wie folgt notieren: <xlink:link xlink:type="simple" xlink:href="c.xml">c.xml</xlink:link> Das Element ist link, der type ist 'simple' und href ist der Locator. Ein Applikationsgerüst Nun, da Sie einen ersten Überblick über die XUL Elemente und das Box-Model gewinnen konnten, wird es Zeit das gelernte umzusetzen und ein Applikationsgerüst zu bauen das zwar (noch) nicht mit Applikationscode verbunden ist, aber in verschiedenen Anwendungen benutzt werden kann. Der Code in Beispiel 3-22 erweitert die xFly Applikation die Sie bereits aus Kapitel 2 kennen. Er definiert das Interface eines Viewers, der Ihnen erlaubt, durch die Beispiele aus diesem Buch zu browsen. Studieren Sie den Code genau, um zu sehen wie die verschiedenen Elemente interagieren. Speziell die anwendung von vbox, hbox, tabbox und statusbar sollte beachtet werden. xFly Applikation, Arbeitsoberfläche <?xml version="1.0"?> <?xml-stylesheet href="chrome://global/skin" type="text/css"?> <?xml-stylesheet href="chrome://xfly/skin" type="text/css"?> <?xul-overlay href="chrome://xfly/content/xflyoverlay.xul"?> <!DOCTYPE window SYSTEM "chrome://xfly/locale/xfly.dtd"> <window title="&window.title;" xmlns:html="http://www.w3.org/1999/xhtml" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" type="xfly:main" width="800" height="600" onload="onLoad( )"> <script type="application/x-javascript" src="chrome://xfly/content/xfly.js" /> <stringbundle id="bundle_xfly" src="chrome://xfly/locale/xfly.properties"/> <toolbox> <menubar id="appbar"> <menu label="xFly"> <menupopup> <menuitem label="Close" oncommand="exitxFly( )"/> </menupopup> </menu> <menu label="Examples"> <menupopup> <!-- items to go here --> </menupopup> </menu> <menu label="Help"> <menupopup> <menuitem label="About" oncommand="doAbout( )"/> </menupopup> </menu> </menubar> </toolbox> <hbox flex="1"> <vbox id="left-frame"> <tree id="example-tree" /> <hbox align="start"> <image src="chrome://xfly/skin/images/logo5.gif" /> </hbox> </vbox> <splitter collapse="before" resizeafter="grow" persist="state"> <grippy /> </splitter> <tabbox id="raven-main-tabcontent" flex="1" orient="vertical"> <tabs orient="horizontal"> <tab id="tab-view" label="View Example"/> <tab id="tab-source" label="View Example Source"/> </tabs> <tabpanels flex="1"> <iframe id="right-frame" name="right-frame" flex="3" src="chrome://xfly/content/examples/2-1.xul"/> <iframe id="right-frame-source" name="right-frame-source" flex="3" src="view-source:chrome://xfly/content/examples/2-1.xul"/> </tabpanels> </tabbox> </hbox> <statusbar id="ch3-bar" persist="collapsed"> <statusbarpanel class="statusbarpanel-iconic" id="book-icon"/> <statusbarpanel id="status-text" label="Thanks for reading the book!" flex="4" crop="right"/> <statusbarpanel class="statusbarpanel-iconic" id="example-status" flex="1"/> </statusbar> </window> Das Hauptfenster der Applikation besteht aus einer Menubar, zwei Frames und einer Statusbar. Die Menus bieten Zugriff auf Applikationsfunktionen wie dem Schliessen des Fensters und dem Öffnen eines 'About' Fensters. Die Statusbar zeigt das Buch-Icon und die Statusmeldungen der Applikation. Zwischen Menubar und Statusbar sind zwei Panel: ein vertikales auf der linken Seite, das einen Tree zur Wahl der Beispiele und ein xFly Logo enthält. Daneben ist ein <iframe> Element, in dem die Beispiele geladen werden sollen. Weiter gibt es 2 Tabs im Beispiel-Panel, eines um den Quellcode und eines um die Anwendung anzusehen.
xFly Beispiel-Viewer
Der Code in Beispiel 3-22 ist nicht der finale Code für unsere Applikation, zeigt jedoch auf, welche Widgets eingesetzt werden, um das Hauptfenster anzuzeigen. Das Layout enthält aber bereits die <toolbox> mit Menus, eine <statusbar> zeigt die Meldunge an und das Box-Model wird verwendet, um die Elemente anzuordnen. Somit kann er gut als Vorlage für Ihre eigene Applikation verwendet werden. Uns bleibt nur noch, die Tree-Struktur zu definieren, die die verschiedenen Beispiele enthalten wird. In Beispiel 3-22 hat der Tree eine ID die benutzt werden soll, um ein Overlay darüberzulegen. Beispiel 3-23 zeigt wie ein solches Overlay aussehen könnte. Wenn Sie möchten, können Sie diese Inhalte natürlich auch direkt im Code notieren. Mehr Informationen zu Overlays finden Sie in Abschnitt 3.11 in diesem Kapitel. Wenn Sie das Beispiel ausführen, sehen Sie Abbildung 3-12. Beispiel Tree für die xFly Applikation <?xml version="1.0"?> <overlay id="xflyOverlay" xmlns:html="http://www.w3.org/1999/xhtml" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> <tree id="example-tree" onselect="onExampleSelect( );" seltype="single" hidecolumnpicker="false" enableColumnDrag="true" flex="1"> <treecols> <treecol id="type" label="Title" flex="1" primary="true" persist="width ordinal hidden"/> <splitter class="tree-splitter"/> <treecol id="method" label="Example" flex="1" persist="width ordinal hidden"/> </treecols> <treechildren> <treeitem container="true" open="true"> <treerow> <treecell label="Chapter 2"/> </treerow> <treechildren> <!-- Second level row --> <treeitem> <treerow> <treecell label="Hello xFly" url="chrome://xfly/content/examples/2-1.xul"/> <treecell label="2-1"/> </treerow> </treeitem> </treechildren> </treeitem> <treeitem container="true" open="true"> <treerow> <treecell label="Chapter 3"/> </treerow> <treechildren> <!-- Second level row --> <treeitem> <treerow> <treecell label="Menu Bar" url="chrome://xfly/content/examples/3-5.xul"/> <treecell label="3-5"/> </treerow> </treeitem> <treeitem> <treerow> <treecell label="Listbox" url="chrome://xfly/content/examples/3-9.xul"/> <treecell label="3-9"/> </treerow> </treeitem> <treeitem> <treerow> <treecell label="Grid" url="chrome://xfly/content/examples/3-12.xul"/> <treecell label="3-12"/> </treerow> </treeitem> </treechildren> </treeitem> </treechildren> </tree> </overlay>