Das HTML-textarea ist zugegeben primitiv. Was tun?
Ein naiver Ansatz ist, alles mit JavaScript selbst zu machen und nach jedem Tastendruck einen String passend zusammenzubauen, dann Einfärbungen durch Hinzufügen von HTML-Tags zu machen, an der richtigen Stelle noch ein Bild für den Cursor einzufügen und dann das ganze einem <div> als `innerHTML` zuzuweisen, um den "Editor" dazustellen.
Das funktioniert, ist aber bereits nach wenigen Zeilen extrem langsam. Zudem weiß ich nicht, ob es möglich ist, etwas mit der Maus zu selektieren. Bekommt man die Events mit und kann die normale Selektionsfunktion des Browsers überschreiben?
Ein anderer Ansatz, der wohl von CodePress verfolgt wird ist, den "WYSIWYG"-Modus (der leider in jedem Browser etwas anders funktioniert und einem total kaputten Hack vom IE folgt) zu benutzen. Man bekommt dadurch die Bearbeitung von Text inklusive Selektion geschenkt, muss aber damit umgehen, das Anwender beliebiges HTML in den Text per Zwischenablage einfügen können. Das Einfärben muss nach jedem Tastendruck immer wieder passieren und geht man ähnlich naiv wie oben beschrieben vor, ist das ebenfalls langsam.
Größtes Problem ist aber, dass die CodePress-Demo im Safari einfach gar nicht geht.
EditArea scheint trickreich ein <textarea> mit normalem HTML zu überlagen und dort jeweils den aktuellen Inhalt des Eingabefelds in Farbe nachzuvollziehen. Interessant und funktioniert auch mit Safari, doch es gibt zwei Selektionen - die des Browsers in dem überlagerten HTML und die im Eingabefeld. Sehr verwirrend. Zudem scheint EditArea das Syntaxhighlighting in der aktuellen Zeile jeweils abzuschalten - vielleicht aus Performance-Gründen - ich finde das jedenfalls häßlich.
Mir scheint der beste, aber wohl auch aufwendigste Ansatz der, einen Editor direkt basierend auf dem DOM zu bauen, um das ständige neue Parsen beim Zuweisen eines Strings an `innerHTML` zu vermeiden. Ich habe den Nachbau eines Emacs und eines vi in JavaScript gefunden, die möglicherweise so vorgehen. Beide funktionierten nicht unter Safari. Ich glaube jedoch, beim Emacs-Clone liegt das daran, dass Webkit relativ streng in der Auslegung ist, wie Keyboard-Events zu funktionieren haben und sich der Autor wohl mittels trial-and-error die fehlerhaften Umsetzung von Mozilla erarbeitet hat. Beide Editoren haben den Vorteil, dass sie keine Maus-Selektion brauchen.
Die Rails-IDE Heroku scheint einen Editor zu haben so wie ich mir das vorstelle - wie der realisiert ist, kann ich nur raten, da sie nur ein Video aber keinen Code zeigen. Allerdings haben die Jungs auch $3,000,000 Risikokapital bekommen und dann ist es ja wohl locker drin, sich da einen eigenen Editor zu bauen. Vielleicht ist das ja auch eine Flash-Komponente?
Es gibt noch einen längeren Aufsatz von jemandem, der den Weg der DOM-Manipulation gegangen ist und der klagt über Unterschiede zwischen den Browsern. Er benutzt einen inkrementellen JavaScript-Parser mit Continuations für das Einfärben (er kann nur JavaScript) was meinen Respekt verdient, doch der Quelltext ist umfangreich und nicht verlockend, studiert zu werden. EditArea ist auch unglaublich groß und es will mir nicht in den Kopf, dass man dafür soviel Code brauchen soll.
Lasse ich das Einfärben weg und nutze ein <pre> als Container, dann habe ich folgenden DOM:
Code: Alles auswählen
<pre id='editor'>...<span id='cursor'>...</span>...</pre>
Möglicherweise ist es effizienter, pro Zeile einen Text-Knoten zu benutzen und dann die Zeilen mit BR-Knoten zu trennen. Innerhalb einer Zeile könnte ich dann nach wie vor `innerHTML` benutzen, um das Syntax-Highlighting zu realisieren und muss nicht weitere SPAN-Knoten erzeugen.
Die Cursorposition speichert man entweder als Index vom Anfang des Texts oder als Paar aus Zeile und Spalte. Zu einer Cursorposition muss man dann den passenden DOM-Knoten und den Offset im Text des Knotens bestimmen. Grundoperationen sind das Einfügen eines Zeichens, Einfügen eines Zeilenumbruchs, Löschen eines Zeichens, Löschen eines Zeilenumbruchs und das Setzen des Cursors. Kann man auch eine Selektion aufspannen, so muss man damit klarkommen, dass diese mehrere Zeilen überspannen kann.
Am einfachsten scheint mir, wenn man parallel zu den DOM-Knoten nochmals den Text als einfache Strings vorhält, um darauf schneller das Syntax-Highlighting durchzuführen. Idealerweise erkennt man irgendwie, dass Text schon korrekt eingefärbt ist und macht dann nichts.
Ich habe keine Zeit mehr, aber falls jemand da noch weitere Informationen hat, würde ich mich freuen. Vielleicht komme ich heute Abend mal dazu, den überlegten Ansatz auszuprobieren.
Stefan