<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Filzblog &#187; lernen</title>
	<atom:link href="http://the-pixelpla.net/blog/tag/lernen/feed/" rel="self" type="application/rss+xml" />
	<link>http://the-pixelpla.net/blog</link>
	<description>So long and thanks for all the fish!</description>
	<lastBuildDate>Fri, 26 Nov 2010 15:43:02 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>Mal nicht meckern.</title>
		<link>http://the-pixelpla.net/blog/2010/11/mal-nicht-meckern/</link>
		<comments>http://the-pixelpla.net/blog/2010/11/mal-nicht-meckern/#comments</comments>
		<pubDate>Sat, 13 Nov 2010 13:09:20 +0000</pubDate>
		<dc:creator>Phil</dc:creator>
				<category><![CDATA[Ausflüge]]></category>
		<category><![CDATA[Party]]></category>
		<category><![CDATA[South Africa]]></category>
		<category><![CDATA[Spaß & Unsinn]]></category>
		<category><![CDATA[feiern]]></category>
		<category><![CDATA[fotos]]></category>
		<category><![CDATA[freizeit]]></category>
		<category><![CDATA[lernen]]></category>
		<category><![CDATA[sap]]></category>
		<category><![CDATA[südafrika]]></category>

		<guid isPermaLink="false">http://the-pixelpla.net/blog/?p=507</guid>
		<description><![CDATA[So.. Heute mal ein beschwerdefreier Post. Und falls jemand doch Passagen finden sollte, wo es so scheint, als wenn ich mich über was beschweren würde, dann scheint das nur so. Wirklich! Also&#8230; Was ist so schönes passiert die letzten Wochen über? Ahja. Also die erste wirklich coole Geschichte spielt sich in einem Naturreservat nahe Sun [...]]]></description>
			<content:encoded><![CDATA[<p>So.. Heute mal ein beschwerdefreier Post. Und falls jemand doch Passagen finden sollte, wo es so scheint, als wenn ich mich über was beschweren würde, dann scheint das nur so. Wirklich!</p>
<p>Also&#8230; Was ist so schönes passiert die letzten Wochen über? Ahja. Also die erste wirklich coole Geschichte spielt sich in einem Naturreservat nahe <a href="http://maps.google.com/maps?f=q&#038;source=s_q&#038;hl=en&#038;geocode=&#038;q=Sun+City,+South+Africa&#038;sll=37.0625,-95.677068&#038;sspn=33.901528,79.013672&#038;ie=UTF8&#038;split=0&#038;ei=ro7eTLj5KY6-yQXjs-TeCA&#038;hq=&#038;hnear=Sun+City&#038;ll=-25.344336,27.090912&#038;spn=0.151106,0.308647&#038;z=12">Sun City</a> ab. Nachdem wir den Tag über wieder einmal die Tierwelt bestaunt haben, kam dann am späteren Nachmittag das eigentliche Highlight. Braai (Grillen) direkt in dem Reservat. Denn, was ich nicht wusste ist, dass es da viele Plätze gibt, wo man das tatsächlich einfach machen kann. Inmitten von staubtrockenem Gebüsch stehen dann ein paar zusammengeschweißte Grillplätze. Coole Sache! Wir haben dann da also den Tag gaaaanz entspannt ausklingen lassen. Allerdings ein bisschen zu entspannt. Denn 20min bevor die Tore schließen haben wir uns auf den Weg raus gemacht. Normalerweise kein Problem, WENN man für die Strecke nicht eigentlich 40min bräuchte. Kurz nach dieser Feststellung hieß es dann: &#8220;Wüstenrally&#8221; (schreibt man das so?). Zum Glück hat uns keiner der Ranger gesehen, denn wir haben das erlaubte Geschwindigkeitslimit doch &#8220;leicht&#8221; überschritten würd ich mal sagen. Aber immernoch besser, als 100€ pro Person Strafe zu zahlen. </p>
<p>Letztes Wochenende gings dann zum Paintball. Aus Deutschland kennt man ja so die Regulierungen: Teilnahme erst ab 18 und es ist nicht unbedingt erwünscht, wenn auch nicht verboten, dass man im Militärdress spielt. Hier sehen die Dinge mal wieder ganz anders aus. Wir sind da angekommen und Paintball ist wohl ziemlich beliebt bei der Generation um 8 Jahre. Außerdem waren viele Gruppen unterwegs, die vollkommen in Camouflage angezogen waren und deren Markierer einem M4A1 Sturmgewehr nachempfunden waren. Man muss dann auch gar nicht mehr erwähnen, dass hier nicht von Markierern und Bällen, sondern von Weapons und Bullets gesprochen wird. Mir stößt das allerdings doch ziemlich unwohl auf. Der Gedanke jemanden zu markieren, ohne ihm wirklich etwas zu tun, gefällt mir wesentlich besser als davon zu sprechen, ihn zu erschießen. Konnte die Gruppe allerdings nicht wirklich nachvollziehen, als ich das erklärt habe. Nichtsdestotrotz ein Heidenspaß. Auch wenn die Holländerjungs ziemlich defensiv gespielt haben. Das lernen wir noch <img src='http://the-pixelpla.net/blog/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>So langsam bekomme ich es auch hin, dass Donnerstag Abend weg gegangen wird. Ich bin da zwar die einzige wirkliche Konstante, aber was solls. Hauptsache Spaß. Wo wir beim Thema sind. Donnerstag letzte Woche. Einem der Holländer (Tom) und mir ist es etwas langweilig, also wollen wir neue Leute kennenlernen. Nunja, irgendwie wollten wir Mädels anquatschen ohne so zu wirken, als wenn wir sie nur ins Bett bekommen wollen. Gar nicht so einfach. Doch auf einmal schien es so, als wenn Tom ein Licht aufgegangen ist. Er sagt also zu mir: &#8220;Ich habe DIE Idee, spiel einfach mit!&#8221;. Und ich denke mir: &#8220;Was kann schon passieren?&#8221;. Wir gehen also auf zwei nett aussehende Mädels zu und was sagt er? &#8220;Hey, das ist mein Freund und er heiratet morgen. Deshalb muss er diese Nacht unbedingt noch einmal flach gelegt werden!&#8221;. Na danke! Ich war in den ersten Sekunden so perplex, dass ich tatsächlich mitgespielt habe. Allerdings (wie zu erwarten) nicht mit Erfolg. Die Rechnung kam dann diesen Donnerstag. Ohne etwas böses zu ahnen, werde ich auf einmal von einem Mädchen angesprochen. Und zwar mit den Worten: &#8220;Hey, solltest du nicht in Holland sein?&#8221; Ich hab die Gute zuerst gar nicht erkannt und habe dann verwundert gefragt &#8220;Holland? Was zur Hölle soll ich denn in Holland? Ich komm aus Deutschland! Und warum fragst du überhaupt?&#8221;. Naja, sagen wir mal so. Ich konnte sie nicht so richtig davon überzeugen, dass ICH eigentlich das Opfer in dieser Geschichte bin. Gelernt habe ich jedenfalls, dass ich aufpassen muss, wenn Tom mit mir Leute kennenlernen möchte. </p>
<p>Heute ist mal entspannen angesagt und morgen Mittag geht&#8217;s dann zum Braai mit ein paar Kollegen von Arbeit. Also mal ein ganz entspanntes Wochenende. </p>
<p>So&#8230; Und nun noch ein paar Bilder <img src='http://the-pixelpla.net/blog/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  Die sind eigentlich alle von dem Braai nahe Sun City (und auch auf Facebook zu finden).</p>

<a href='http://the-pixelpla.net/blog/2010/11/mal-nicht-meckern/braai-trip-1/' title='braai-trip-1'><img width="100" height="150" src="http://the-pixelpla.net/blog/wp-content/uploads/2010/11/braai-trip-1-100x150.jpg" class="attachment-thumbnail" alt="braai-trip-1" title="braai-trip-1" /></a>
<a href='http://the-pixelpla.net/blog/2010/11/mal-nicht-meckern/braai-trip-2/' title='braai-trip-2'><img width="150" height="100" src="http://the-pixelpla.net/blog/wp-content/uploads/2010/11/braai-trip-2-150x100.jpg" class="attachment-thumbnail" alt="braai-trip-2" title="braai-trip-2" /></a>
<a href='http://the-pixelpla.net/blog/2010/11/mal-nicht-meckern/braai-trip-3/' title='braai-trip-3'><img width="100" height="150" src="http://the-pixelpla.net/blog/wp-content/uploads/2010/11/braai-trip-3-100x150.jpg" class="attachment-thumbnail" alt="braai-trip-3" title="braai-trip-3" /></a>
<a href='http://the-pixelpla.net/blog/2010/11/mal-nicht-meckern/braai-trip-4/' title='braai-trip-4'><img width="150" height="100" src="http://the-pixelpla.net/blog/wp-content/uploads/2010/11/braai-trip-4-150x100.jpg" class="attachment-thumbnail" alt="braai-trip-4" title="braai-trip-4" /></a>
<a href='http://the-pixelpla.net/blog/2010/11/mal-nicht-meckern/braai-trip-5/' title='braai-trip-5'><img width="150" height="100" src="http://the-pixelpla.net/blog/wp-content/uploads/2010/11/braai-trip-5-150x100.jpg" class="attachment-thumbnail" alt="braai-trip-5" title="braai-trip-5" /></a>
<a href='http://the-pixelpla.net/blog/2010/11/mal-nicht-meckern/braai-trip-6/' title='braai-trip-6'><img width="100" height="150" src="http://the-pixelpla.net/blog/wp-content/uploads/2010/11/braai-trip-6-100x150.jpg" class="attachment-thumbnail" alt="braai-trip-6" title="braai-trip-6" /></a>
<a href='http://the-pixelpla.net/blog/2010/11/mal-nicht-meckern/braai-trip-7/' title='braai-trip-7'><img width="100" height="150" src="http://the-pixelpla.net/blog/wp-content/uploads/2010/11/braai-trip-7-100x150.jpg" class="attachment-thumbnail" alt="braai-trip-7" title="braai-trip-7" /></a>
<a href='http://the-pixelpla.net/blog/2010/11/mal-nicht-meckern/braai-trip-8/' title='braai-trip-8'><img width="100" height="150" src="http://the-pixelpla.net/blog/wp-content/uploads/2010/11/braai-trip-8-100x150.jpg" class="attachment-thumbnail" alt="braai-trip-8" title="braai-trip-8" /></a>
<a href='http://the-pixelpla.net/blog/2010/11/mal-nicht-meckern/braai-trip-9/' title='braai-trip-9'><img width="150" height="100" src="http://the-pixelpla.net/blog/wp-content/uploads/2010/11/braai-trip-9-150x100.jpg" class="attachment-thumbnail" alt="braai-trip-9" title="braai-trip-9" /></a>
<a href='http://the-pixelpla.net/blog/2010/11/mal-nicht-meckern/braai-trip-10/' title='braai-trip-10'><img width="150" height="100" src="http://the-pixelpla.net/blog/wp-content/uploads/2010/11/braai-trip-10-150x100.jpg" class="attachment-thumbnail" alt="braai-trip-10" title="braai-trip-10" /></a>
<a href='http://the-pixelpla.net/blog/2010/11/mal-nicht-meckern/braai-trip-11/' title='braai-trip-11'><img width="100" height="150" src="http://the-pixelpla.net/blog/wp-content/uploads/2010/11/braai-trip-11-100x150.jpg" class="attachment-thumbnail" alt="braai-trip-11" title="braai-trip-11" /></a>
<a href='http://the-pixelpla.net/blog/2010/11/mal-nicht-meckern/braai-trip-12/' title='braai-trip-12'><img width="150" height="100" src="http://the-pixelpla.net/blog/wp-content/uploads/2010/11/braai-trip-12-150x100.jpg" class="attachment-thumbnail" alt="braai-trip-12" title="braai-trip-12" /></a>

]]></content:encoded>
			<wfw:commentRss>http://the-pixelpla.net/blog/2010/11/mal-nicht-meckern/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Richtext Editing</title>
		<link>http://the-pixelpla.net/blog/2010/10/richtext-editing/</link>
		<comments>http://the-pixelpla.net/blog/2010/10/richtext-editing/#comments</comments>
		<pubDate>Tue, 19 Oct 2010 17:33:21 +0000</pubDate>
		<dc:creator>Phil</dc:creator>
				<category><![CDATA[Nerd Stuff]]></category>
		<category><![CDATA[cross-browser]]></category>
		<category><![CDATA[hell]]></category>
		<category><![CDATA[lernen]]></category>
		<category><![CDATA[signavio]]></category>
		<category><![CDATA[web 2.0]]></category>

		<guid isPermaLink="false">http://the-pixelpla.net/blog/?p=420</guid>
		<description><![CDATA[Diesen Sommer habe ich den August noch einmal bei Signavio verbringen dürfen. Meine Aufgabe war es einen Richtext Editor zu implementieren. Das besondere dabei war, dass der Editor natürlich nicht nur im Firefox, sondern in allen großen Browsern, also auch Chrome, Opera (, IE6) laufen muss. Dass das nicht leicht werden würde, war mir schon [...]]]></description>
			<content:encoded><![CDATA[<p>Diesen Sommer habe ich den August noch einmal bei <a href="http://www.signavio.com">Signavio</a> verbringen dürfen. Meine Aufgabe war es einen Richtext Editor zu implementieren. Das besondere dabei war, dass der Editor natürlich nicht nur im Firefox, sondern in allen großen Browsern, also auch Chrome, Opera (, IE6) laufen muss. Dass das nicht leicht werden würde, war mir schon klar aber mit manchen Tücken habe ich wirklich nicht gerechnet. Da mich schon mindestens zwei Leute darauf angesprochen haben, meine Erfahrungen doch mal mit ihnen zu teilen, und um meinen Frust los zu werden, hier also ein Artikel zum Thema Richtext Editing. Zu beachten ist, dass hier einige nicht-standard JavaScript Funktionen genutzt werden. Dies sind Funktionen des <a href="http://www.prototypejs.org">PrototypeJS</a>-Frameworks.</p>
<h2>Der Anfang&#8230;</h2>
<p>&#8230; schien gar nicht so schlimm! Denn als ich schon überlegte, wie ich die einzelnen Textbausteine am besten mit Tags umschließe, fand ich <a href="https://developer.mozilla.org/en/midas">das hier</a>. Kommandos, die man direkt auf dem <code>document</code> Objekt ausführen kann. Diese Art Kommandos wurden einst von Microsoft in <code>DHTML</code> eingebunden, dann von der Mozilla Gruppe adaptiert und stehen nun in eigentlich allen großen Browsern zur Verfügung. Man braucht nur einen <code>iframe</code>, der den Editor beherbergen soll und in diesem setzt man den sogenannten <code>designMode</code> auf <code>On</code>. Um die ganze Sache auch im IE laufen lassen zu können muss das <code>contentEditable</code> Attribute des <code>body</code> Tags auf <code>true</code> gesetzt werden. Beispiel gefällig?</p>
<pre class="brush: js; html-script: true">
<scirpt language="text/javascript">
    // no IE!
    document.observe("dom:loaded", function() {
        document.designMode = "On";
    });
</script>
</pre>
<p>Soweit, so gut. Allerdings wurden nicht alle Befehle von allen Browserherstellen übernommen oder implementiert. Am schlimmsten erweist sich hierbei übrigens Opera. Bemerken tut man dies, wenn man versucht, mit dem <code>selection</code> Objekt zu arbeiten. Opera schmückt sich ja gern damit, mit den neuesten Standards konform zu sein. Wie sie das erreichen ist allerdings eine andere Sache. Im Falle vom Selektionsobjekt wird dies oft durch einfaches <b>stubben</b> von Methoden erreicht. Da diese Methoden dann keine Fehler werfen, sondern einfach <strong>nichts</strong> tun, erweist sich das debuggen als große Qual. Außerdem sind die Methoden, die tatsächlich Auswirkungen zeigen teils fehlerhaft implementiert. So funktionieren im Opera viele Funktionen nur, wenn man von rechts nach links selektiert, und nicht in der anderen Richtung. Aber zurück zum Thema.</p>
<p>Ein wohl sehr wichtiger Befehl ist <code>heading</code> für Überschriften. Der Befehl erhält als zweiten Parameter lediglich &laquo;<code>h[1,2,3,4,5]</code>&raquo; um die gewünschte Headline zu erzeugen. Leider zeigt er zur Zeit nur im Firefox seine Wirkung. Opera ignoriert ihn einfach und Chrome zeigt unerwünschtes Verhalten. Kurz nachdem man mit der Implementierung eines Befehls, wie <code>heading</code> begonnen hat, wird einem klar, dass die eigentliche Funktionalität leicht zu erreichen ist, wenn da nicht die Benutzerfreundlichkeit wäre. Ein Benutzer erwartet im Allgemeinen, dass der komplette Paragraph in eine Überschrift gewandelt wird, wenn auch nur ein Bruchteil davon selektiert wurde. Die generelle Idee ist es also, von den Selektionsgrenzen aus nach links und rechts nach begrenzenden Elementen zu suchen. Allgemein würde man hier von einem <code>br</code> tag ausgehen, das einen Zeilenumbruch, und damit einen Abschnitt begrenzt. Leider kommt uns hier wiederum die unterschiedliche Implementierung der Browser in die Quere. Drückt man währen der Eingabe <code>Enter</code> so fügt Firefox <code>br</code> ein, wie man es erwarten würde. Chrome hingegen nutzt <code>div</code> tags, um Abschnitte abzugrenzen und Opera fügt <code>p</code> Elemente ein. </p>
<h2>Die richtigen Elemente finden</h2>
<p>Mit der Idee im Kopf, dass wir einfach nur nach links und nach rechts suchen müssen, bis wir entweder ein begrenzendes Tag finden oder der nächste Kindknoten <code>undefined</code> ist, fangen wir also an zu programmieren. Aber schon nach kurzer Zeit wird uns klar, dass das nicht so einfach ist. Das Selektionsobjekt gibt nämlich nur Auskunft über den Knoten, in dem es anfängt und aufhört. Da wir Text selektieren wird das meist ein Textknoten sein. Und der kann in <code>b</code>, <code>i</code> und weitere Tags geschachtelt sein. Wir müssen also sehen, dass wir zwei Eltern von den beiden finden, die auf einer Ebene im DOM-Baum liegen und von diesen dann nach links und rechts suchen. </p>
<p>Die Tiefe eines Knotens im DOM-Baum lässt sich rekursiv recht einfach durch folgende Funktion ermitteln.</p>
<pre class="brush: js">
function getDepth(node, count) {
    if(node.parentNode) {
        return getDepth(node.parentNode, (count || 0) + 1);
    }

    return count || 0;
}
</pre>
<p>Von hier an denken wir weiter. Wie muss unsere Suche aussehen? Wenn der Startknoten tiefer im Baum liegt, als der Endknoten, müssen wir unsere Suche mit dem Elternknoten von Start und dem gleichen Endknoten fortsetzen. Genau andersrum ist es, wenn der Endknoten tiefer im Baum liegt. Was aber passiert, wenn beide Knoten die gleiche Tiefe haben? Die Annahme, dass dann alles in Ordnung ist und wir einfach mit der Links-Rechts-Suche fortfahren könnten, ist leider falsch. Es könnte folgende Situation aufgetreten sein:</p>
<pre class="brush: js; html-script: true">
Lorem ipsum <b><i>Start</i> Text</b> dolor sit <b><i>End</i> Text</b> amet.
</pre>
<p>Oder, um die Baumstruktur ein bisschen besser hervorzuheben:</p>
<pre class="brush: js; html-script: true; highlight: [4,11]">
Lorem ipsum
    <b>
        <i>
            Start
        </i>
        Text
    </b>
dolor sit
    <b>
        <i>
            End
        </i>
        Text
    </b>
amet.
</pre>
<p>Wie man sieht, liegen der Start- und Endtext in einer Ebene, aber die Suche nach links und rechts wäre sinnlos. Hier müssen wir den Algorithmus also auf die Elternknoten, der beiden anwenden. </p>
<p>Die folgende Funktion sucht diejenigen Knoten, die auf einer Ebene im Baum liegen und auch Geschwister sind. Dabei wird ein Objekt zurückgegeben, dass unter den Schlüsseln <code>left</code> und <code>right</code> den linken und rechten Knoten bereithält. Dies ist lediglich eine Hilfe für die spätere Suche nach den Grenzen des Abschnitts. Bitte beachtet auch, dass hier <a href="http://prototypejs.org">Prototype</a> spezifische Funktionen, wie <code>$A(...)</code> verwendet werden.</p>
<pre class="brush: js; highlight: [15, 19, 31]">
function findHighestSiblings(start, end, depthStart, depthEnd) {           

    // first we need to check which node is deeper in the tree
    if(!depthStart) {
        depthStart = getDepth(start);
    }

    if(!depthEnd) {
        depthEnd = getDepth(end);
    }

    if(depthStart > depthEnd &#038;&#038; start.parentNode) {
        // start is deeper in the tree
        // -> we check whether the parent of start has the same depth as end
        return findHighestSiblings(start.parentNode, end, undefined, depthEnd);
    } else if (depthStart < depthEnd &#038;&#038; end.parentNode) {
        // end is deeper in the tree
        // -> we check whether the parent of end has the same depth as start
        return findHighestSiblings(start, end.parentNode, depthStart);
    } else {
        // both nodes have the same depth but are wrapped in containers
        if(start.parentNode &#038;&#038; end.parentNode &#038;&#038;
           start.parentNode !== end.parentNode) {               

            var gpStart = start.parentNode.parentNode;
            var children = $A(gpStart.childNodes);

            if(gpStart) {
                if(children.indexOf(end.parentNode) === -1) {
                    // the wrapping can be multilevel
                    return findHighestSiblings(start.parentNode, end.parentNode, depthStart, depthEnd);
                }                   

                // now we have the same parent and determine which of the elements
                // is the left and which is the right one
                // we need this for the previousSibling-/ nextSibling-search
                if(children.indexOf(start.parentNode) < children.indexOf(end.parentNode)) {
                    return {
                        left: start.parentNode,
                        right: end.parentNode
                    };
                } else {
                    return {
                        left: end.parentNode,
                        right: start.parentNode
                    };
                }
            }
        }

        var sParent = start.parentNode;
        var children = $A(sParent.childNodes);

        if(children.indexOf(start) < children.indexOf(end)) {
            return {
                left: start,
                right: end
            };
        } else {
            return {
                left: end,
                right: start
            };
        }
    }
}
</pre>
<p>Nachdem die begrenzenden Elemente gefunden wurden, kann diese Selektion mit einem <code>h</code> Tag umschlossen werden. Die Überschrift wurde also erzeugt. </p>
<h2>Das Selektionsobjekt</h2>
<p>Ist der Dreh- und Angelpunkt beim arbeiten mit Text. Generell läuft man an jeder Stelle in das Objekt, an dem man Text extrahieren, hinzufügen oder bearbeiten möchte. Abfragen kann man das Objekt wie folgt:</p>
<pre class="brush: js">
function getSelection() {
    // Mozilla
    if (window.getSelection) {
        return window.getSelection();
    }

    // Safari + Chrome
    if (document.getSelection) {
        return document.getSelection();
    } 

    // IE
    if (document.selection) {
        return document.selection.createRange().text;
    }
}
</pre>
<p>Die Safari/ Chrome-Abzweigung dient allerdings nur für ältere Versionen dieser Browser. Die neusten Versionen folgen alle dem Mozilla Beispiel. </p>
<p>Falsch ist die Annahme, dass die sichtbare Selektion gleich dem Selektionsobjekt ist. Was man sieht sind die sogenannten <code>Ranges</code> des Objektes. Ein Selektionsobjekt kann im allgemeinen Fall beliebig viele <code>Ranges</code> beherrbergen. Dies entspricht dann einer Mehrfachselektion mittels gedrückter <code>STRG</code>-Taste. Allerdings will man sich in den meisten Fällen nur mit der ersten <code>Range</code> beschäftigen. Das Objekt gibt auch Auskunft über die Elemente in denen es beginnt und endet. Wenn man zum Beispiel aus einer Selektion einen Link erstellen möchte, kann man dies wie folgt tun:</p>
<pre class="brush: js">
function createLink() {
    var selection = getSelection();
    var range = selection.getRangeAt(0);
    var link = undefined;

    link = findLink(range.startContainer, range.endContainer);

    if(link) {
        var href = Element.readAttribute(link, 'href');
        var url = prompt("Edit the following link:", href);                

        if(url &#038;&#038; url !== 'http:/'+'/') {
            link.setAttribute('href', url);
        }
    } else {
        var url = prompt("Set link to:", "http://");

        if(url &#038;&#038; url !== 'http:/'+'/') {
            document.execCmd('createlink', url);
        }
    }
}
</pre>
<p>Diese Funktion sucht als erstes in der Selektion nach bereits bestehenden Links. Existiert bereits ein Link, so wird dessen Wert übernommen und zum Editieren angeboten. Wie man sieht ist das eigentliche Erstellen des Links nicht durch mühsehlige, selbstimplementierte Funktionen realisiert, sondern durch das einfache Ausführen des <code>createlink</code> Kommandos auf dem <code>document</code> Objekt.</p>
<h3>Unterschiede beim Erstellen von Selektionen</h3>
<p>Wenn man per Hand Selektionen erstellen möchte, um dann beispielsweise Kommandos auf ihnen auszuführen, so muss man dabei eine gewisse Vorsicht mit an den Tag bringen. </p>
<p>Das <code>Range</code> Objekt hat von Haus aus die sehr nützlichen Funktionen <code>setStart</code>, <code>setStartBefore</code>, <code>setEnd</code> und <code>setEndAfter</code>. Leider verhalten sich diese Funktionen nicht in allen Browsern gleich. Nehmen wir folgendes Beispiel:</p>
<pre class="brush: js; html-script: true">
Lorem <i>ipsum</i> <b>dolor</b> <i>sit</i> amet.
</pre>
<p>Wenn wir nun eine Selektion um das <code>dolor</code> setzen möchten, würde man (oder ich) intuitiv annehmen, dass wir den Start der Selektion <strong>vor</strong> das <code>b</code> Element setzen und das Ende <strong>hinter</strong> das Element. Anscheinend waren die Entwickler von Mozilla und Chroma auch meiner Meinung. Allerdings sehen die Jungs bei Opera die Sache etwas anders. Wenn wir im Opera die Selektion vor das <code>b</code> Element setzen, so umschließen wir auch das komplette <code>i</code> Element damit. Gleich verhält es sich für das Ende der Selektion. Was nun also tun? Zum Glück ist das Verhalten der Browser für die <code>setStart</code> und <code>setEnd</code> Methoden gleich. Diese nehmen zwei Parameter. Der erste gibt das Element an, in dem die Selektion liegen soll und einen <code>offset</code> wert.</p>
<pre class="brush: js; highlight: [11,13]">
function selectBetween(l, r) {
    var selection = getSelection();
    var range = selection.getRangeAt(0);

    if(l === r) {
        range.selectNodeContents(l);
    } else {
        range.setStart(l, 0);

        if(this.isTextNode(r)) {
            range.setEnd(r, r.textContent.length);
        } else {
            range.setEnd(r, $A(r.childNodes).length);
        }
    }
}
</pre>
<p>So, und wem fällt beim Ansehen des Codes die nächste Tücke auf? Nagut, ist nicht so schwer, da ich die Zeilen schon markiert habe. Man hätte annehmen können, beim <code>offset</code> handelt es sich um ein Zeichen-Offset. Das stimmt auch, so lange es sich bei dem gewählten Knoten um einen Textknoten handelt. Ist dies aber nicht mehr der Fall, so beschreibt das Offset die Position des Knotens in der <code>childNodes</code> Liste des Elternelements. Und dann bedeuted es, dass auch das komplette Element mit eingeschlossen wird.</p>
<p>Das soll es für's Erste gewesen sein. Ich habe zwar nicht alle Schwachstellen und Lücken beleuchtet aber auf die gröbsten und fiesesten Stellen aufmerksam gemacht. Hoffentlich ist das hier jedem, der es liest eine Hilfe. An einer Übersetzung ins Englische arbeite ich übrigens noch.</p>
]]></content:encoded>
			<wfw:commentRss>http://the-pixelpla.net/blog/2010/10/richtext-editing/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Ein Hoch auf TI</title>
		<link>http://the-pixelpla.net/blog/2009/07/ein-hoch-auf-ti/</link>
		<comments>http://the-pixelpla.net/blog/2009/07/ein-hoch-auf-ti/#comments</comments>
		<pubDate>Thu, 30 Jul 2009 22:15:43 +0000</pubDate>
		<dc:creator>Phil</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[bier]]></category>
		<category><![CDATA[lernen]]></category>
		<category><![CDATA[ti]]></category>

		<guid isPermaLink="false">http://the-pixelpla.net/blog/?p=18</guid>
		<description><![CDATA[So.. Morgen ist die TI-Klausur. Scheiße noch was.. Bestehen is da echt nich garantiert. Aber zur Festigung meines Wissens gabs heute Abend noch zwei Bier, &#8216;nen ordentlichen Actionstreifen und Pizza Da kann ja eigentlich nichts mehr schief gehn.]]></description>
			<content:encoded><![CDATA[<p>So.. Morgen ist die TI-Klausur. Scheiße noch was.. Bestehen is da echt nich garantiert. Aber zur Festigung meines Wissens gabs heute Abend noch zwei Bier, &#8216;nen ordentlichen Actionstreifen und Pizza <img src='http://the-pixelpla.net/blog/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  Da kann ja eigentlich nichts mehr schief gehn.</p>
]]></content:encoded>
			<wfw:commentRss>http://the-pixelpla.net/blog/2009/07/ein-hoch-auf-ti/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>

