HTML5 versus Internet Explorer 6 - Das <hr>-Element und seine Rahmen

Veröffentlicht am 2. März 2010

Ich habe ja eigentlich dem IE6 abgeschworen und halte das bisher auch gegen erbitterten Widerstand von allen möglichen Seiten durch, aber dieser eine Hack ist einfach zu genial um ihn nicht zu bloggen. Für mich ist er eine unterhaltsame Kuriosität, aber vielleicht hilft es ja dem einen oder anderen noch-IE6-Unterstützer auch mal wirklich – insbesondere wenn besagte IE6-Unterstützer HTML5 verwenden wollen.

HTML5 belebt, wie wir alle wissen, das <hr>-Element wieder. Es dient nicht mehr horizontaler Trennstrich, sondern markiert thematische Umbrüche in Texten – für Szenenwechsel innerhalb eines Kapitels in einer Geschichte zum Beispiel. Diese neue Rolle ändert freilich nichts daran, dass Browser das Element immer noch als horizontalen Strich anzeigen, was in den neueren Versionen aller Browser auch kein Problem darstellt. Entweder will man das <hr>-Element gar nicht mehr sehen und schafft es mit display:none; aus der sichtbaren Welt oder man entfernt seinen Rahmen mit border:none;. Das ist besonders dann sinnvoll, wenn man es als Container für ein dekoratives Hintergrundbild einsetzen möchte, ähnlich wie die Trenner mit Zweig in meinem Blogdesign. Das Problem: Da macht der IE6 nicht mit, border:none; bewirkt in ihm bei <hr>-Elementen rein gar nichts.

Wenn der Hintergrund einfarbig ist, lässt sich das Problem dadurch lösen, dass man im IE6 color für die <hr> auf den Wert der Hintergrundfarbe setzt, denn im IE6 ist offenbar border-color nicht für Rahmenfarben zuständig. Wenn man allerdings keinen einfarbigen Hintergrund hat, nützt das freilich nichts mehr. Also macht man das Folgende:

hr {
    display: list-item;
    list-style: url(hintergrund.png) inside;
    height: 48px;
    filter: alpha(opacity=0);
}

Ja, der IE6 unterstützt display:list-item; und list-style die man durch kreativen Mißbrauch ganz wunderbar instrumentalisieren kann. Einfach das Hintergrundbild als Bulletpoint einsetzen und das ganze Element via Alpha-Filter unsichtbar machen. Liegt ja auch ganz nahe, sowas. Respekt an den Autoren dieses Hacks, dessen Blogpost ich beim googlen zu einem ganz anderen Thema gefunden habe.

HTML-Bausteine zum Zusammenklicken im CMS - Property Sets in MODx Revolution

Veröffentlicht am 13. Oktober 2009

Es gibt bei Content-Management-Systemen zwei Kernprobleme: Wie hält man den Redakteuer davon ab, komplexe HTML-Dinge zu verwenden, die er besser lassen sollte (z.B. <blink>, <marquee> und Konsorten) und wie macht man es ihm gleichzeitig möglichst einfach, jene komplexen HTML-Konstruktionen einzufügen, die er wirklich verwenden soll? Für letzteres scheint die Lösung der Wahl in MODx Revolution aus dynamischen Chunks mit Property Sets zu liegen.

Chunks sind statischer HTML-Code, die aber seit MODx Revolution Platzhalter für wechselnden Content kennen. Diese notiert man als im Chunk-HTML.

<div class="graue-box">
    <h2></h2>
    <p>[[+Text]]</p>
</div>

Die Verwendung dieser Platzhalter ist wie bei Snippets via Parameter möglich. Man könnte also beim Einbinden des Chunks schreiben:

[[$GraueBox? &Headline=`Lorem Ipsum` &Text=`Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium`]]

Das Prinzip ist aus MODx seit jeher bekannt und für Nichtnerds nicht gerade komfortabel. Aber es gibt ja die Revolution tollen Drag&Drop-Funktion, mit denen man solche Konstruktionen einfach zusammenklickbar machen kann. Alles was man dazu tun muss, ist ein den Platzhaltern entsprechendes Property Set zum Chunk anzulegen. Dort gibt man an, welcher Platzhalter welchen Inhalt wiedergeben soll.

Anlegen eines Property Sets in MODx Revolution

Wenn ein Redakteur diesen Chunk nun per Drag&Drop in seinen Text befördert, poppt ein Dialog auf, in dem er den Chunk bequem konfigurieren kann:

Property-Dialog in MODx Revolution

Heraus kommt der gleiche Chunk-Code wie oben, nur dass der Redakteur sich dank des Dialogs die Verstrickung in Parameter und Sonderzeichen sparen kann. Und das Ergebnis ist trotzdem ein sauberes, standardisiertes Stück HTML. Property Sets gibt es nicht nur für Chunks, sondern für alle Contentressourcen – komplizierte Snippets lassen sich also auch auf diese Weise konfigurieren und dann einfach einfügen.

Mootools für die Massen, Teil 5: Programmieren im Mootools-Stil

Veröffentlicht am 6. August 2009

Nachdem wir in den ersten vier Teilen dieser Artikelserie die einzelnen Funktionen und Prinzipien von Mootools kennengelernt haben stellt sich nur noch die Frage: was kann man damit anstellen? Objekte, Klassen, Events und Dollarfunktionen schön und gut – doch was hat man im Programmieralltag davon? Diese Frage soll dieser letzte Teil der Serie anhand eines Beispiels aus dem Mootools-Core und einem Tutorial für ein selbstgebautes Plugin beantworten.

Was Klassen leisten können

Das Klassensystem von Mootools ermöglicht es, bestehende Funktionen zu verändern, ohne ihren Code anrühren zu müssen. Die Scripts bleiben sauber, modular und vor allem klein – ein Prinzip, das auch im gesamten Kerncode von Mootools seine Anwendung findet.

In Teil 3 der Artikelserie haben wir uns ja unter anderem die Request-Klasse angesehen, mit der sich bequem Ajax aus dem Ärmel schütteln lässt. Mootools hat mit Request.JSON auch eine abgewandelte Form dieser Request-Funktion dabei, die statt purem Text JSON verarbeitet. Dank des Klassensystems ist Request.JSON eine Sache von nicht mal 20 Zeilen Code:

Request.JSON = new Class({
    Extends: Request,
    options: {
        secure: true
    },

    initialize: function(options){
        this.parent(options);
        this.headers.extend({'Accept': 'application/json', 'X-Request': 'JSON'});
    },

    success: function(text){
        this.response.json = JSON.decode(text, this.options.secure);
        this.onSuccess(this.response.json, text);
    }

});

Einfach die Ursprungsklasse um zwei Funktionen erweitern, fertig! Ganz ohne irgendwelchen Code zu hacken oder zu duplizieren – elegant und kompakt. Dieses Prinzip kann (und sollte man) auf fast jedes seiner Mootools-Scripts anwenden.

Ein Beispiel

Setzen wir uns doch mal folgende Beispielaufgabe: ein Script soll beim Klick auf einen Link ein Fenster ähnlich dem Popup der alert()-Funktion anzeigen. Spontan würde es sich anbieten, das Fenster einfach zusammenzusetzen, indem man ein entsprechendes HTML-Element erstellt und in das Dokument einfügt:

$('link').addEvent('click', function(e){
    e.stop();
    var container = $('container');
    var popup = new Element('div', {
        'class': 'popup',
        'text': 'Das hier ist der Text unseres Popup-Fensters'
    });
    popup.inject(container);
});

Das ist ganz nett und funktioniert. Aber nehmen wir doch mal an, wir würden die gleiche Funktion in eine Klasse verpacken …

Popups mit Klasse

… dann könnte das in einem ersten Schritt so aussehen:

var Popup = new Class({
    popup: null,

    // Initialisierung
    initialize: function(popupText){
        this.popup = new Element('div', {
            'class': 'popup',
            'text': popupText
        });
    },

    // Popup anzeigen
    display: function(container){
        var container = $(container);
        this.popup.inject(container);
    }
});

// Unser schönes neues Popup-Fenster
$('link').addEvent('click', function(e){
    e.stop();
    var meinPopup = new Popup('Das hier ist der Text unseres Popup-Fensters');
    meinPopup.display('container');
});

Was ist damit gewonnen außer dass die ganze Geschichte mehr Zeilen in Anspruch nimmt? Ganz einfach: Portabilität. Wollten wir unser Popup-System in eine andere Website verwenden, könnten wir jetzt die Klasse in einer JS-Datei ablegen, diese in anderen Projekten einbinden und dann am Fließband neue Popups produzieren – pro Fenster reicht dann eine einzige Code-Zeile mit new Popup('Text').display('container'). Das Ergebnis sieht am Ende gleich aus, aber ohne Klasse müssten wir jeweils den gesamten Code aufs neue einfügen.

Wo wir schon mal eine Klasse an der Hand haben bietet es sich auch an, das Popup-Fenster gleich etwas flexibler und konfigurierbarer zu gestalten:

var Popup = new Class({

    Implements: Options,
    options: {
        'className': 'popup',
        'popupText': 'Hier fehlt Text! Bitte ändern!',
        'container': document.body
    },
    popup: null,

    // Initialisierung
    initialize: function(options){
        this.setOptions(options); (unter anderem <code>document.body</code> als Container)
        this.popup = new Element('div', {
            'class': this.options.className,
            'text': this.options.popupText
        });
    },

    // Popup anzeigen
    display: function(){
        this.popup.inject(this.options.container);
    }

});

// Unser schönes neues Popup-Fenster
$('link').addEvent('click', function(e){
    e.stop();
    var meinPopup = new Popup({
        'popupText': 'Das hier ist der Text unseres Popup-Fensters'
    }).display();
});

Jetzt ist der Code noch länger, aber dafür ist das Plugin einfacher zu verwenden, bei immer noch gleichem Ergebnis. Es kann das aus Mootools bekannte Options-Objekt verwendet werden, so dass man Klasse des Popups und auch den Text einfach an einer Stelle ändern kann. Außerdem haben wir unter options Standardwerte für alle Werte notiert, so dass man bei Bedarf auch einfach new Popup.display() schreiben und trotzdem ein funktionierendes Ergebnis bekommen könnte.

Jetzt kann man die Popup-Klasse bequem in jedem Mootools-Projekt einsetzen, in dem man Popups braucht. Der Code ist portabel und flexibel. Nun könnte man sowas ähnliches vielleicht auch mit einfachen Funktionen hinbekommen, aber Mootools kann ja noch mehr.

Pimp my Popup

Unterschiedliche Websites brauchen ähnliche, aber nie ganz identische Funktionen. Deswegen ist Otto Normalwebworker oft damit beschäftigt, alten Code aus Website A in Website B zu kopieren und anzupassen. An genau dieser Stelle kann Mootools auftrumpfen – denn wir können ja unsere Klassen erweitern, ohne irgendwelchen alten Code hacken zu müssen.

Nehmen wir mal an, wir bräuchten für eine andere Website Popups mit Titelleisten und einem OK-Button um das Popup zu schließen. Die können wir ganz einfach kriegen, indem wir entsprechende Methoden in unser bewährtes Popup implementieren:

Popup.implement({

    // Eine zusätzliche Titelleiste
    addTitle: function(text){
        var titleBar = new Element('div', {
            'class': 'popupTitle',
            'text': text
        });
        titleBar.inject(this.popup, 'top');
    },

    // Und ein OK-Button
    addButton: function(text){
        var button = new Element('div', {
            'class': 'popupButton',
            'text': text
        });
        Popup.implement(Events);
        button.addEvent('click', function(){
            this.popup.destroy();
        }.bind(this));
        button.inject(this.popup, 'bottom');
    }

});

// Unser schönes neues Popup-Fenster
$('link').addEvent('click', function(e){
    e.stop();
    var meinPopup = new Popup({
        'popupText': 'Das hier ist der Text unseres Popup-Fensters'
    });
    meinPopup.addTitle('Wichtige Meldung');
    meinPopup.addButton('OK');
    meinPopup.display();
});

Damit ist unser kleines Popup ganz schön aufgemotzt – ohne dass wir ein Byte an unserer Ursprungsklasse verändern mussten. Und wenn wir wollten, könnten wir immer noch die ursprünglichen Popups ohne Extras erzeugen.

Popups der nächsten Generation

Ein verbessertes Popup-Fenster

Wenn man Erweiterungen einbaut, von denen man glaubt dass man sie später bei anderen Projekten nochmal gebrauchen kann, bietet es sich natürlich an, die Erweiterungen ihrerseits in eine Klasse zu packen, die die normale Popup-Klasse erweitert. Drag & Drop, Lightbox-Effekt und Minimieren-Button – das kann man alles umsetzen, ohne die Ursprungsklasse zu verändern.

var FancyPopup = new Class({
    Extends: Popup,
    // Code für die zusätzlichen Funktionen
});

var meinPopup = new FancyPopup({
    'popupText': 'Das hier ist der Text unseres Popup-Fensters'
});
meinPopup.addTitle('Wichtige Meldung');
meinPopup.addButton('OK');
meinPopup.addOverlay();
meinPopup.display();

Und die Erweiterungen selbst sind wieder in einer handlichen Klasse zusammengefasst, die man ihrerseits in andere Projekte portieren und dort noch mehr erweitern kann.

The Art of Moo

Die Kunst des Mootools-Programmierens liegt also einfach darin, Scripts so zu gestalten, dass sie entweder erweiterbar sind oder ihrerseits auf vorhandenen Scripts aufbauen. Das Klassensystem von Mootools macht dieses Vorhaben in der Sache einfach – man muss nur ein gewisses Maß an planerischer Weitsicht aufbringen.

Wenn man immer fleißig Klassen anlegt, baut man sich in kurzer Zeit einen Fundus an Plugins auf, die portabel und im Bedarfsfall einfach erweiterbar sind, wobei die Erweiterungen ihrerseits wiederum portabel und erweiterbar sind. Die Klassen sind zwar von der Codemenge her alle etwas länger als wenn man einfach ständig $().foo().bar() schreiben würde, aber bereits bei der ersten Portierung in ein anderes Projekt macht sich das bezahlt. Und bei der ersten Erweiterung mit einem einfachen Extend erst recht.

Und als Bonus kommt eben noch hinzu, dass man nicht alles in Klassen verpacken muss. Man kann das tun und sollte es in 90% der Fälle sicher auch tun, aber wenn man nur eben mal schnell etwas zusammenhauen möchte, geht das auch: $('foo').fade('out'); funktioniert in Mootools genau so wie bei jQuery und Konsorten. Mootools macht die einfachen Dinge einfach, hat aber auch (und vor allem) für die komplexeren Dinge alle nötigen Funktionen auf Lager. Und genau das ist der Grund, warum dieses schöne kleine Javascript-Framework unsere Aufmerksamkeit verdient.

Mootools für die Massen, Teil 4: Klassen erstellen und erweitern

Veröffentlicht am 3. August 2009

Nachdem wir im vergangenen Teil der Serie gesehen haben wie man Mootoools-Objekte benutzt, wird es Zeit, sich um die Erstellung eigener Klassen zu kümmern. Dieser Artikel soll das Klassen- und Vererbungssystem in seinen Grundzügen darstellen. Wer objektorientierte Programmierung kennt, sollte sich diesbezüglich schnell zurechtfinden. Was man mit den Klassen tolles anstellen kann, soll dann Bestandteil des nächsten Teils sein.

Klassen erstellen

Die Klassen in Mootools lassen sich genau so verwenden, wie man es aus anderen (richtigen) objektorientierten Programmiersprachen kennt. Ein simples Beispiel:

var Huhn = new Class({
    pick: function(){
        alert('Pick, pick!')
    }
});

So sieht die simpelste Form einer Mootools-Klasse aus. Unsere neue Klasse Huhn hat mit pick() eine Methode, die sich genau so aufrufen lässt, wie man das von anderen Objekten kennt:

var meinHuhn = new Huhn();
meinHuhn.pick(); // Alert: Pick, pick!

Klassen erweitern

Will man eine bestehende Klasse erweitern, muss man nur in der Extends-Eigenschaft entsprechend notieren:

var Hahn = new Class({
    Extends: Huhn,
    kraeh: function(){
        alert('Kikeriki!');
    }
});

Die Klasse Hahn erbt von der Klasse Huhn alle Eigenschaften und Methoden – in diesem Fall die pick()-Methode. Zusätzlich bringt Hahn noch seine eigene kraeh()-Methode mit:

var meinHahn = new Hahn();
meinHahn.pick();  // Alert: Pick, pick!
meinHahn.kraeh(); // Alert: Kikeriki!

Optionen benutzen

Um in die eigenen Klassen Funktionen aus anderen Klassen nutzbar zu machen, bietet sich die Implements-Eigenschaft an. In diesem Fall wird die Options-Klasse implementiert, die es uns erlaubt, unsere Klassen mit zusätzlichen Optionen zu initialisieren.

var Henne = new Class({
    Extends: Huhn,
    Implements: Options,
    options: {
        startEier: 2
    },
    eier: 0,
    initialize: function(options){
        this.setOptions(options);
        this.eier = this.options.startEier;
    },
    legeEi: function(){
        this.eier++;
    },
    zaehleEier: function(){
        alert(this.eier);
    }
});

Die Henne-Klasse erweitert die Huhn-Klasse und erbt dadurch die pick()-Methode. Sie implementiert die Options-Klasse und macht sich damit die setOptions()-Methode zu Eigen. Außerdem hat Henne mit initialize() eine Constructor-Funktion, die die Variablen verarbeitet, die beim Erstellen der Klasse übergeben werden.

Henne hat mit startEier eine Option, die festlegt, wie viele Eier unser Federvieh als Startkapital bekommt. In der Klasse selbst ist in der 4. Zeile ein Standardwert (2) notiert, der von initialize() überschrieben wird. Das sieht in der Praxis dann so aus:

meineHenne = new Henne();
meineHenne.zaehleEier(); // Alert: 2 (Standardwert)

var meineAndereHenne = new Henne({
    startEier: 5
});
meineAndereHenne.zaehleEier(); // Alert: 5

Die Anzahl der Eier wird in der internen Variable eier gespeichert. Mit der legeEi()-Methode erhöht man den internen Ei-Counter um eins, während der Startwert weiterhin unter options.startEier zu finden ist:

var meineHenne = new Henne({
    startEier: 7
});
meineHenne.legeEi();
meineHenne.legeEi();
meineHenne.zaehleEier(); // Alert: 9
alert(meineHenne.options.startEier); // Alert: 7

Zusätzliche Methoden implementieren

In jede bestehende Klasse kann man nachträglich zusätzliche Methoden implementieren:

Huhn.implement({
    scharr: function(){
        alert('Scharr, scharr!');
    }
});
var meinHuhn = new Huhn();
meinHuhn.scharr(); // Alert: Scharr, scharr

All das geht auch mit den Standardklassen von Mootools! Um mal ein Beispiel ohne Hühner zu nehmen, implementieren wir doch einfach mal eine Methode in die Element-Klasse (die Klasse für alle HTML-Elemente), die die betroffenen Elemente komplett leer macht:

// Vorher: <div id="meinDiv">Ein <code>DIV</code> voller HTML!</div>
Element.implement({
    empty: function(){
        this.set('html', '');
    }
});
$('meinDiv').empty();
// Nacher: <div id="meinDiv"></div>

Und weil, wir erinnern uns, alles in Mootools aus Objekten und Klassen besteht, können wir auch alles im Framework nach unserem Geschmack umkrempeln oder als Basis für eigene Kassen verwenden.

Und wozu das Ganze?

Nun ist es ja ganz nett, dass man Klassen erstellen und modifizieren kann, aber es drängt sich natürlich die Frage auf, wie man das Ganze effektiv nutzen kann. Im nächsten Teil der Serie werden wir wieder tutorialartig ein Beispiel durchgehen, das verdeutlichen wird, wie man sich mit Mootools-Klassen viel Arbeit ersparen kann.