Die dritte Generation

Firefox 3.0 für Entwickler
Kommentare

Ohne Browser geht heute kaum noch etwas. Bedenkt man, dass für viele Leute das Internet praktisch nur aus E-Mail und Webseiten besteht, wird eine komfortable Nutzbarkeit dieser Dienste immer wichtiger. Mit Firefox 3.0 setzt die Mozilla Foundation im Browserumfeld wieder viele Neuerungen um – auch für (XUL-)Entwickler.

Auf den ersten Blick scheint sich zwischen dem noch aktuellen Firefox 2.0 und der neuen, dritten Generation wenig getan zu haben: Es gibt einige neue Icons und der eine oder andere Dialog sieht etwas auf- bzw. umgeräumter aus. Viel scheint das nicht zu sein. Doch die wichtigsten Änderungen stecken wie so oft im Detail: Neben teilweise massiven Optimierungen im Speicherverbrauch der Engine selbst, auf dessen Erfolg die Mozilla-Entwickler sichtlich stolz sind, ist es jedoch primär das neue Bookmarking-System Places, dass als Killerfeature – zumindest für die Endanwender – gehandelt wird. Mit Places ist es endlich möglich, Bookmarks nicht einfach nur stumpf als Lesezeichen in einer mehr oder weniger geordneten Struktur zu verwalten, sondern auch diese Information an diversen Stellen im Alltagsbetrieb zu verwenden. So wird die Mächtigkeit dieses Subsystems schon nach dem Aufrufen weniger Webseiten deutlich: Firefox schlägt beim Eintippen von Worten in der URL-Zeile passende Webseiten aus der Aufrufhistorie sowie den Bookmarks vor. Dabei werden sowohl URL, vom Benutzer vorgegebene Keywords als auch textliche Inhalte der besuchten Seite zur Auswahl herangezogen. Vorbei sind damit die Zeiten, in denen man als Anwender mehr oder weniger verzweifelt in der Historie der vormals besuchten Webseiten herumklickte, um einen bestimmten Artikel oder Eintrag wieder zu finden – vorausgesetzt, man kann sich an das eine oder andere Keyword aus dem Inhalt erinnern.

SQLite und XML

Technisch gelöst wurde dieses System vor allem durch die Verwendung von SQLite zur Speicherung und Verwaltung der anfallenden Datenmengen. Um diese Daten zudem performant anzeigen zu können, wurde die in älteren Versionen nur auf RDF-Datenstrukturen ausgelegte Template Engine vollständig überarbeitet und in großen Teilen neu geschrieben. Neben der so hinzugekommenen Unterstützung für SQLite-Daten können mit Gecko 1.9 – der Version der Gecko-Engine, auf der Firefox 3.0 basiert – auch eigene XML-Strukturen templategestützt verarbeitet werden. War die Verarbeitung von XML an sich natürlich schon mit den Vorgängerversionen via DOMParser respektive XMLHttpRequest möglich, so stellt die Überarbeitung der bereits vorher leistungsfähigen und hochperformanten Template Engine dennoch eine für XUL-Entwickler gerade zu traumhafte Weiterentwicklung dar, die gerade bei größeren Datenmengen ihr Stärken ausspielt und bekannte AJAX-Frameworks alt aussehen lässt. Ein Beispiel für die Ausgabe von XML-Daten zeigt Listing 1: Referenziert über die ID zu einer diesem Fall eingebetteten Struktur, dem Inhalt der letzten PHP-Magazine, verarbeitet das Template-Subsystem Regeln und Abfragen zum Aufbau einer zweistufigen Ansicht in einem Tree Control.

Listing 1: XML Templates mit Gecko 1.9

Die im query-Tag sowie bei den where-Abfragen verwende Syntax sieht übrigens nicht nur aus wie XPath – es ist XPath, die XML Query Language, mit all ihren Möglichkeiten. Das Ergebnis kann in Abbildung 1 begutachtet werden. Die unterschiedliche Färbung der Einträge kommt durch das in Listing 2 abgedruckte CSS zustande. Wen dieses kleine Beispiel nicht abgeschreckt hat, findet auf den Developer-Seiten ein ausführliches Tutorial zur Arbeit mit Templates in XUL.

Abb. 1: Das durch Templates erzeugtes Tree Control aus Listing 1

Neben der Darstellung und Ausgabe via Template Engine ist selbstverständlich auch der Zugriff via API möglich: Die in C bzw. C++ geschriebenen Teile werden, wie in Gecko üblich, durch XPCOM, der Cross-Plattform-Komponenten-Schnittstelle, für JavaScript bereit gestellt. Auf diese Weise stehen dem geneigten Entwickler zum Zugriff auf die SQLite-Daten des Places-Systems sowie beliebige eigene Strukturen einfach anzuwendende API-Aufrufe zur Verfügung, wie Listing 3 zeigt. Gefolgt von der üblichen, für PHP- und JavaScript-Entwickler vielleicht etwas kryptisch anmutenden Initialisierung der gewünschten Komponenten, lässt sich mit weniger Zeilen Code lesend und schreibend auf eine SQLite-Struktur zugreifen.

Listing 2: Die CSS-Regeln (tree.css)
      treechildren::-moz-tree-row(groupEntry) {
         background-color: #ccc;
      }
      
      treechildren::-moz-tree-cell-text(groupEntry) {
         font-size:12px;
         font-weight:bold;      
      }
Listing 3: Mit XPCom und JavaScript auf SQLite-Datenbank zugreifen
// Instanz von nsIFile mit Referenz auf das Profil-Verzeichnis 
var file = Components.classes["@mozilla.org/file/directory_service;1"]
                     .getService(Components.interfaces.nsIProperties)
                     .get("ProfD", Components.interfaces.nsIFile);

// Instanz des storageService erzeugen
var storageService = Components.classes["@mozilla.org/storage/service;1"]
                        .getService(Components.interfaces.mozIStorageService);

                     
// sqlite-Datei dem nsIFile-Objekt zuweisen ...                      
file.append("datenbank.sqlite");

// ... und Datenbank öffnen
var sqlConn = storageService.openDatabase(file);

// Abfrage vorbereiten ...
var sqlStatement = sqlConn.createStatement("SELECT foo FROM bar");

// .. ausführen und Daten abrufen
while (sqlStatement.executeStep()) {
   // Feld 0 (foo) auslesen
   var foo=sqlStatement.getString(0);
   alert('Foo: '+foo);
}

// Aufräumen
sqlStatement.reset();
Webbasierte Protokoll-Handler

Das Internet besteht bekanntlich aus vielen Protokollen, von denen HTTP, webdav oder auch FTP nur mit die bekanntesten ihrer Art darstellen. Auch einige Pseudo-Protokolle wie mailto oder torrent in Links sind weit verbreitet und den meisten Anwendern gut bekannt. Speziell über derartige Verlinkungen werden bisher allerdings vor allem lokale Anwendungen mit entsprechend passenden Parametern gestartet bzw. bereits laufende Programme zur Ausführung gewünschter Funktionen veranlasst – etwa dem Öffnen einer neuen E-Mail. Mit Firefox 3.0 ist es jetzt möglich, auch eine Webseite, genauer gesagt eine Ziel-URL, für beliebige Protokolle als Zielanwendung zu definieren, die dann anstelle einer lokalen Applikation aufgerufen wird. Aus Sicherheitsgründen gilt, wie auch sonst im JavaScript-Kontext, die Same Domain Policy: Eine Webseite kann zwar einen browserweit gültigen Handler registrieren (Abbildung 2), die angebotene URL muss jedoch auf den gleichen Host verweisen, von dem auch die Registrierungsanfrage stammt. Das in Listing 4 abgedruckte HTML/JavaScript-Dokument zeigt, wie einfach der Aufruf zur Anmeldung eines webbasierten Handlers funktioniert: Wird die Funktion navigator.registerProtocolHandler() aufgerufen, erbittet Firefox die im Screenshot sichtbare Zustimmung des Benutzers. Neben dem zu registrierenden Protokoll und der gewünschten Ziel-URL wird ein dritter Parameter der Kurzbeschreibung übergeben, welche im Autorisierungsdialog angezeigt wird.

Abb. 2: Sicher ist sicher – Firefox fragt nach, bevor ein neuer Handler registriert wird
Listing 4: Webbasierte Handler
 
 
 
  Eigene Handler 

PHP Protokoll Demo

Aufmerksamen Lesern wird das %s im zweiten Parameter, der URL, nicht entgangen sein: Diesen Platzhalter, PHP-Entwicklern aus Funktionen wie sprintf() bekannt, befüllt Gecko beim Aufruf der URL mit den vollständigen Daten aus dem Link. Nach Freigabe der Aktion durch den Anwender (Abbildung 3), wird das hinterlegte Skript aufgerufen – ganz so, als ob direkt auf diesen Link geklickt worden wäre. Eine mögliche Implementierung für das hier beispielhaft verwendete PHP-Protokoll zeigt Listing 5.

Abb. 3: Auch bei der Ausführung geht Sicherheit vor: Die Verwendung muss explizit bestätigt oder generell aktiviert werden
Listing 5: Serverseite der webbasierten Handler
<?php // Der vollständige Inhalt des href-Attributes aus dem Link 
  $uri=$_GET['uri'];  
  echo "
  • Vollständiger Inhalt der URI: „.htmlspecialchars($uri).“
  • „; // Protokoll und Daten trennen list($proto,$payload)=explode(‚:‘,$uri); // Erkanntes Protokoll ausgeben echo „
  • Protokoll: $proto
  • „; // Daten Parsen parse_str($payload, $result); // Daten verwenden echo „
  • Name: {$result[’name‘]}
  • „; echo „
  • Link {$result[‚website‘]}
  • „; ?>

    Da Entwickler nicht darauf beschränkt sind, nur für eigene Protokolle entsprechende Handler zu registrieren, sondern auch bereits meist schon anderweitig verwendete Vertreter wie mailto überschrieben werden dürfen, wäre auf diesem Wege endlich eine Umleitung auf einen Webmail-Dienst denkbar. Es bleibt abzuwarten, ob und wann Anbieter wie GMX, Web.de oder auch Hotmail diese Möglichkeit erkennen und umsetzen. Wer nicht so lange warten will, kann dies natürlich durch eine Weiterleitung über einen eigenen Server realisieren. Speziell wenn aufwändigere Parameterketten übergeben werden müssen, könnte dies sogar die praktikablere Vorgehensweise sein.

    JSON

    Die JavaScript Object Notation, kurz JSON, wird immer beliebter und schickt sich an, dem klassischen XML bei AJAX-Anwendungen als Übertragungsformat den Rang abzulaufen. Dabei werden Objektstrukturen durch einen Serialisierungsprozess in extrem kompakten JavaScript-Quelltext transformiert, übertragen und auf der Gegenseite wieder in native Objekte zurückübersetzt.

    PHP liefert daher seit einiger Zeit die Erweiterung ext/json standardmäßig mit aus und erlaubt so eine C-basierte Verarbeitung von JSON-Daten sowohl als Parser als auch Serialisierer. Der größte Vorteil von JSON, neben dem sehr kompakten Aufbau, ist jedoch auf Browserseite leider auch der größte Nachteil: Es handelt sich um potenziell ausführbaren Quelltext – die schnellste Möglichkeit, JSON-Quelltext in Objekte zurückzuwandeln ist aber die Funktion eval(). Da diese Funktion in der Praxis aufgrund offensichtlicher Sicherheitsbedenken nicht verwendet werden kann, blieb bisher nur die von json.org bereitgestellte, in JavaScript implementierte Klasse mit Parser und Serialisierer. Neben der Tatsache, dass sich diese Implementierung in der Vergangenheit oft änderte – und dabei auch gerne mal das API bzw. der technische Ansatz geändert wurde – ist dieser Weg zwar sicherer, aber wenig wartbar und naturgegeben langsamer. Doch mit der Freigabe von Firefox 3.0 wird wohl in Gecko eine C-basierte Implementierung Einzug in die Browserwelt halten, die massive Performancegewinne verspricht. Mark Finkle, einer der Hauptautoren des PRISM-Projekts hat in seinem Blog eine ausführliche Gegenüberstellung der verschiedenen Implementierungen und ihrer jeweiligen Performance veröffentlicht. Leider ist zurzeit die native Implementierung nur für privilegierten Chrome-Code, sprich nur für Firefox selbst und seine Extensions, verfügbar. Der Wunsch, derartige Funktionalität auch im „Userland“, also der Sandbox einer Webseite, benutzbar zu machen, ist jedoch auch bei den Mozilla-Entwicklern schon angekommen und wird als Feature-Wunsch im Bug #408838 begleitet.

    XULRunner

    Machten vor einiger Zeit noch Gerüchte die Runde, das Projekt XULRunner würde bald eingestellt, beweist Firefox 3.0 allen Zweiflern das Gegenteil: Denn wer Firefox 3 installiert, erhält neben dem Browser selbst auch die aktuelle XUL Runtime. Und auch wenn Firefox selbst nicht explizit, wie früher geplant, auf XULRunner selbst aufsetzt, so hat die Koppelung dennoch sowohl für Anwender als auch für Entwickler gleich mehrere Vorteile: Zum einen müssen auf XUL setzende Anwendungen Dritter keine eigenständigen Versionen der Laufzeitumgebung mehr installieren, was eine nicht unbeträchtliche Erleichterung bei der Wartung von Systemen und der Pflege von Abhängigkeiten mit sich bringt, zum anderen ergibt sich auf diesem Weg natürlich eine viel breitere Installationsbasis, auf die Anwendungsentwickler mit deutlich kleineren Installationspaketen aufsetzen können.

    Listing 6: XUL-Anwendung
        
    
    

    Um eine eigenständige XUL-Anwendung zu erstellen, bedarf es zusätzlich zu den von klassischen Erweiterungen für Firefox und Co. bekannten Strukturen zweier weiterer Dateien: Zunächst die Datei application.ini (Listing 7). Sie ist im klassischen INI-Format gehalten und enthält grundlegende Daten zur Anwendung: So wird definiert, wer Hersteller der Anwendung ist, welche ID die Anwendung hat – was z.B. für Erweiterungen wichtig ist um die Kompatibilität sicherzustellen – und wie das Programm überhaupt heißen soll. Der unter Vendor angegeben Wert wird unter Anderem beim Bestimmen des Ordners für Profildaten berücksichtigt. Unter Unix/Linux führt eine Angabe von Vendor=phpmagazin zu einem neuen .phpmagazin-Ordner im Benutzerverzeichnis. Als letzter Wert in der INI-Datei – im Bereich [Gecko] – lässt sich, sofern notwendig, eine minimale und eine maximale Version der Gecko Engine, respektive des XULRunners, vorgeben, mit dem diese Anwendung ausführbar sein soll.

    Listing 7: Anwendungs-Information „application.ini“
    [App] 
    Vendor=NonFood 
    Name=PHPMagazin 
    Version=1.0 
    BuildID=2008040201 
    Copyright=Copyright (c) 2008 NonFood Werbeagentur Unit II GmbH 
    ID={xulrunner@phpmagazin.de} 
    
    [Gecko] 
    MinVersion=1.8

    Die zweite Datei enthält Laufzeitinformationen im prefs.js-Format, das in dieser Form auch bei klassischen Mozilla-Anwendungen anzutreffen ist. Eine grundlegende Version einer solchen Datei mit praktikablen Standardwerten ist in Listing 8 abgedruckt. Der wichtigste Punkt ist die erste Zeile: Sie definiert, welche XUL-Datei beim Programmstart angezeigt werden soll – im Fall von Firefox wäre dies das bekannte Browserfenster. Die weiteren Angaben stellen sicher, dass während der Entwicklung kein unnötiges Caching aktiv ist sowie allgemeine Mozilla-Funktionalitäten mit sinnvollen Startwerten versehen sind. Je nach Anwendung können hier aber natürlich beliebige weitere Werte definiert werden.

    Listing 8: Standardeinstellungen in der default-prefs.js
    pref("toolkit.defaultChromeURI", "chrome://phpmagazin/content/main.xul"); 
    pref("browser.dom.window.dump.enabled", true); 
    pref("browser.download.useDownloadDir", true); 
    pref("browser.download.folderList", 0); 
    pref("browser.download.manager.showAlertOnComplete", true); 
    pref("browser.download.manager.showAlertInterval", 2000); 
    pref("browser.download.manager.retention", 2); 
    pref("browser.download.manager.showWhenStarting", true); 
    pref("browser.download.manager.useWindow", true); 
    pref("browser.download.manager.closeWhenDone", true); 
    pref("browser.download.manager.openDelay", 0); 
    pref("browser.download.manager.focusWhenStarting", false); 
    pref("browser.download.manager.flashCount", 2); 
    pref("alerts.slideIncrement", 1); 
    pref("alerts.slideIncrementTime", 10); 
    pref("alerts.totalOpenTime", 4000); 
    pref("alerts.height", 50); 
    pref("javascript.options.showInConsole", true); 
    pref("javascript.options.strict", true); 
    pref("nglayout.debug.disable_xul_cache", true); 
    pref("nglayout.debug.disable_xul_fastload", true);
    Kompatibilität

    Neben den bisher vorgestellten Neuerungen haben die Mozilla-Entwickler auch an der Kompatibilität nicht nur zu offiziellen Webstandards, sondern auch zu weit verbreiteten Implementierungen gearbeitet. So sind diverse proprietäre DOM-Methoden von Microsofts Internet Explorer jetzt auch in Firefox verfügbar: Die Properties clientTop und clientLeft wurden ebenso implementiert wie die Events oncut, oncopy und onpaste. Dem kommenden Standard (X)HTML 5/Web Applications 1.0 verdanken wir die DOM-Funktion getElementsByClassName(), die es ermöglicht, Elemente nicht mehr nur über den Tag-Namen, eine ID oder das Attribute name zu finden, sondern auch über den Wert des class-Attributs. Das Schöne an dieser Funktion ist, dass eine Suche auch die Nodes findet, in denen mehrere Klassen zugewiesen wurden.

    Ebenfalls dem Web Applications Standard geschuldet ist eine erste Implementierung der Funktion postMessage(), die es mehreren Fenstern erlaubt zu Kommunizieren – auch über Domaingrenzen hinweg – sowie das dazu gehörende Event message. Dank des optionalen zweiten Parameters der postMessage()-Methode ist selbst Cross-Domain-Kommunikation sicher möglich, wie man Listing 9 entnehmen kann. Passt der angegebene Wert nicht zur URL des im angesprochenen Browserfensters angezeigten Dokuments, wird keine Nachricht verschickt und auch auf Empfängerseite lässt sich über das Origin-Property des Event-Objekts die Herkunft verifizieren und so das Verarbeiten von Daten aus unerwarteten Quellen sicher verhindern. Sollten die anderen Browserhersteller diesen Ansatz übernehmen, wäre ein großes Problem der Web-2.0-Welt endlich gelöst.

    Listing 9: Nachrichten per PostMessage verschicken
    // Fenster öffnen 
     var popup=window.open('http://remote.mobile/popup.html'); 
     
    // An das Fenster eine Nachricht schicken 
     popup.postMessage('Hallo welt!', 'http://remote.mobile'); 
    
     // Eventhandler für Antworten definieren 
     function getMessage(event) { 
        // Nur 'erwartete' Quellen zulassen 
        if (event.origin !== 'http://remote.mobile') return; 
    
        alert('remote.mobile sendet folgende Nachricht:'+event.data); 
     } 
    
     // Eventhandler registrieren und damit aktivieren 
     document.addEventListener("message", getMessage, false);

    Die in früheren Betaversionen bereits implementierte Unterstützung für Cross-Domain-XMLHttpRequest wurde übrigens wieder entfernt, da sich die Spezifikation erneut geändert hat und die Mozilla-Entwickler verständlicherweise keine unfertige Lösung ausliefern möchten. Wer also Daten über Domaingrenzen hinweg tauschen will, muss entweder auf klassische Post/Get-Konstrukte zurückgreifen oder auf baldige Verbreitung der postMessage()-Methode auch in anderen Browsern hoffen.

    Doch nicht nur im Skriptingbereich hat sich die Standardabdeckung verbessert, auch die Rendering-Engine selbst hat viele Verbesserungen erfahren: Der SVG-Support wurde signifikant verbessert, sodass jetzt sämtliche in SVG 1.1 definierten Filter verwendet werden können. Die Behebung einer Vielzahl bekannter Fehler bei der Darstellung von SVG sorgt jetzt für eine deutlich sauberere Ausgabe auch komplexerer Dokumente.

    Zu guter Letzt dürfen sich all diejenigen freuen, die XSL-Transformationen in Firefox ausführen lassen, denn mit Freigabe der nächsten Generation wird endlich auch die beliebte Erweiterung eXSLT unterstützt.

    Fazit

    Firefox 3.0, beziehungsweise die dahinter werkelnde Gecko Engine in der Version 1.9, stellen einen riesigen Schritt nach vorne da. Die lange Entwicklungszeit und endlose Stunden an Arbeit, die nicht zuletzt viele Freiwillige an allen Ecken und Enden in das Projekt gesteckt haben und hoffentlich auch weiter stecken werden, merkt man deutlich. Nicht nur, dass die kommende Generation noch einmal deutlich schneller arbeitet als die Vorgänger, auch der Speicherverbrauch wurde trotz diverser neuer Funktionen auffallend reduziert. Wie sehnsüchtig die (Web-)Welt auf die Freigabe dieser Version zu warten scheint, wird wohl auch daran deutlich, dass verschiedenste Magazine auf den beiliegenden CDs und DVDs die Vorabversionen von Firefox mit ausliefern und auch etliche Linux-Distributoren schon erste Pakete verfügbar haben.

    Darf es etwas mehr sein?

    Hat Ihnen der Artikel gefallen? Diesen und weitere Artikel aus den Bereichen Development, Enterprise oder auch Web finden Sie in unserer aktuellen Ausgabe 4.08 vom PHP Magazin. Hier gibt es übrigens auch alle Quellcodes noch einmal bequem zum Download.

    Ob das neue Places-System als Ersatz für die altbekannten Bookmarks den Leuten gefallen wird, bleibt zwar abzuwarten – der technische und konzeptionelle Ansatz überzeugt aber schon jetzt und besticht durch seine Einfachheit und Effektivität. Rein optisch bietet Firefox 3 neben einem zwar auffallenden Facelift ansonsten eher wenig. Wer – je nach Geschmack – gehofft oder befürchtet hatte, es würde eine erneute Überarbeitung der Einstellungsdialoge geben, der wird enttäuscht bzw. erleichtert sein: Zwar gibt es auch hier ein Facelift, die grafiklastige Top-Navigation ist allerdings beibehalten worden.

    Alles in allem wirkt Firefox 3 schon recht rund, auch wenn vor allem im Chrome-Bereich noch der eine oder andere Fehler schlummert – aber bis zur Final ist ja noch etwas Zeit. Der aktuelle RC steht bei der Mozilla Corporation in vielen Sprachen und für diverse Plattformen zum Download bereit.

    Arne Blankerts ist Leiter der Entwicklung bei der NonFood Werbeagentur Unit 2 GmbH in Hamburg.

    Unsere Redaktion empfiehlt:

    Relevante Beiträge

    Meinungen zu diesem Beitrag

    X
    - Gib Deinen Standort ein -
    - or -