Teil von SELFHTML aktuell Teil von Artikel Teil von JavaScript

Größe eines Textfeldes an dessen Inhalt anpassen

nach unten JeSchnell (Autor)
nach unten Einführung
nach unten Einbindung
nach unten Grundgerüst
nach unten Reaktion auf automatische Zeilenumbrüche
nach unten Reaktion auf händische Zeilenumbrüche
nach unten Gesamtcode

JeSchnell (Autor)

E-Mail: E-Mail jeschnell@ymail.com

Bei Fragen zu diesem Beitrag bitte den Autor des Beitrags kontaktieren!

nach obennach unten

Einführung

Ein variables Textfeld ist auf einer Webseite nicht unbedingt nötig, allerdings kann es bei Textfeldern, in denen Text von ganz unterschiedlicher Länge editiert wird, ein nettes Tool sein. Für diesen Anwendungszweck ist JavaScript jedoch gut geeignet, denn es sollte lediglich als "Verzierung" und keinesfalls als Basis einer Webseite dienen.

Ich selbst programmierte dieses Script anfangs auch nur als "Schnick-Schnack" für meine Webseite; doch als ich merkte, dass es eigentlich sehr ausgereift war, beschloss ich es weiter zu verbessern und einen SELFHTML Artikel darüber zu verfassen.

Im Prinzip wäre das Mitwachsen eines Textfeldes ganz einfach: Man müsste nur bereichsübergreifende Seite Math.ceil(eingabe.value.length / cols) durchführen und schon hätte man es geschafft, da bräuchte man gar keine eigene Funktion dazu. Da gibt es aber zwei Erschwernisse, die in den nächsten beiden Kapiteln behandelt werden: nach unten automatische und nach unten händische Umbrüche, denn bei Umbrüchen wird immer in die nächste Zeile gesprungen (die Zeilenlänge ist dabei irrelevant); hier müssen etwas speziellere Berechnungen durchgeführt werden, die später in das in diesem Kapitel besprochene Grundgerüst eingebunden werden.

Einbindung

Da sich die Zeichenanzahl und somit die Zeilenanzahl bei jedem Tastendruck ändern kann, sollte das Ereignis nach jedem Druck ausgeführt werden. Am besten wäre es, diese Funktion außerdem nach jeder Änderung eines wertverändernden JavaScripts und nach dem Laden der Seite (Anpassung auf den Defaulttext) aufzurufen.

Beispiel:

<body onload="addZeile(document.getElementById('eingabe'))">
    <form action="">
        <textarea id="eingabe" style="font-size:14px;font-family:monospace;" cols="60" rows="2"
        onkeydown="setTimeout('addZeile(document.getElementById(\'eingabe\'))',10)">
    </form>
<body>

Erläuterung:

Auch hier wird unsere Funktion, die, wie später noch erwähnt wird, addZeile() heißt, beim Laden und bei jedem Tastendruck aufgerufen. Dies geschieht durch die Eventhandler bereichsübergreifende Seite onload und bereichsübergreifende Seite onkeydown (es wurde nicht bereichsübergreifende Seite onkeypress verwendet, da dies bei "Strg+V" im Explorer zu Problemen führt).

Da onkeydown schon vor dem Hinzufügen des der Taste entsprechenden Zeichens ausgeführt wird, muss man mit bereichsübergreifende Seite setTimeout arbeiten. Hier sollte beachtet werden, dass der eigentliche Befehl als String übergeben werden muss.

Außerdem muss dem Textfeld eine feste Zeichenanzahl (cols-Attribut, ebenso auch rows), eine dicktengleiche (nicht-proportionale) Schriftart (z.B. Courier) und eine feste Schriftgröße zugewiesen werden, da das Script, wie sich auch in den weiteren Kapiteln zeigen wird, immer eine feste Zeichenanzahl pro Zeile braucht. Bei Schriftarten wie Arial wäre dies unmöglich, da jedes Zeichen eine andere Breite hat und somit in jede Zeile, je nach Inhalt, unterschiedlich viele Zeichen passen - falls diese Voraussetzung nicht erfüllt werden, würde das hier dokumentierte Script nicht funktionieren.

Grundgerüst

Jetzt kommen wir zur eigentlichen Funktion, auf diese von unseren Eventhandlern referenziert wird:

Beispiel:

function addZeile(eingabe) {
    var Inhalt = eingabe.value;

    var geteilt = Inhalt.split('\n');
    var Abstand = 0;
    var altPos = -1;
    for(var Zaehler = 0; Zaehler < geteilt.length; Zaehler++) {
      //Die Reaktionen auf Umbrüche
    }

    Abstand = Abstand / eingabe.cols * 17 + 28;
    if(Abstand > 560)
        Abstand = 560;
    eingabe.style.height = Abstand+'px';
}

Erläuterung:

In den ersten beiden Zeilen werden sowohl der Knoten selbst als auch der Inhalt in lokale Variablen gespeichert.

Danach wird der Inhalt in einzelne Absätze aufgesplittet. In der for()-Schleife dieser Funktion kann dadurch später auf jeden Absatz einzeln zugegriffen werden. In dieser werden auch in der Variablen Abstand die Zeichen gezählt; die Verwendung von altPos kann erst im Kapitel über nach unten automatische Umbrüche erläutert werden.

Danach wird die Zeichenanzahl (Abstand) durch die maximale Zeichenanzahl pro Zeile dividiert. Da die Eigenschaft rows uneditierbar ist, sollte man dies danach noch mit der Zeilenhöhe multiplizieren. Die Zeilenhöhe ist jedoch nicht das Gleiche wie die Schriftgröße, da sich über und unter der Zeile auch noch etwas Space befindet.

Dann sollte man noch ein bisschen Freiraum lassen, damit es für den Benutzer nicht so aussieht, als würde der Platz im Textfeld schon zur Neige gehen.

Falls man nicht möchte, dass das Textfeld zu groß wird, kann man die Höhe natürlich auch begrenzen.

Zu guter Letzt muss man Abstand nur noch der Stylesheeteigenschaft height zuweisen. Da manche Browser die Zuweisung einer Zahl nicht akzeptieren, sondern eine korrekte CSS-Längenangabe verlangen, wird die Maßeinheit px für Pixel hinzugefügt.

Reaktion auf automatische Zeilenumbrüche

Ein automatischer Zeilenumbruch wird automatisch eingefügt, damit lange Absätze innerhalb eines Textfeldes Platz haben. Falls die Wortgrenze (Bindestrich oder Leerzeichen) nicht genau auf der Zeilengrenze liegt, muss hier jedoch mit Freiräumen aufgefüllt werden, damit nicht mitten im Wort umgebrochen werden muss. Doch auch diese Freiräume verbrauchen Platz und bei langen Wörtern auch nicht gerade wenig. Deswegen müssen wir diese auch berechnen.

Beispiel:

var Position = geteilt[Zaehler].search(/ |-/);
while(Position != altPos) {
    if(parseInt(Position / eingabe.cols) != parseInt(altPos / eingabe.cols))
        Abstand += Math.abs(altPos%eingabe.cols - (eingabe.cols-1));
    altPos = Position;
    Position++;
    Position = geteilt[Zaehler].slice(Position).search(/ |-/)+Position;
}

Erläuterung:

Innerhalb der im vorigen Kapitel besprochenen bereichsübergreifende Seite for()-Schleife bauen wir jetzt das weitere Script ein. Zu Beginn wird nach einem der beiden Wortgrenzen im ganzen Absatz gesucht. Danach wird eine bereichsübergreifende Seite while-Schleife in unser Script eingefügt. Deren Bedingung besagt, dass die Schleife nur ausgeführt wird, solange ob bei der Suche -1 herausgekommen sein muss; deswegen wird im nach oben Grundgerüst in altPos auch -1 gespeichert.

Wenn sich altPos und Position nicht in der selben Zeile befinden, bedeutet dies, dass zwischen ihnen ein automatischer Umbruch liegt. Hier wird dann errechnet, wie viel Platz sich ein Zeichen nach dem altPos noch befindet; jener wird zu Abstand hinzugerechnet.

Danach wird Position in altPos gespeichert, da die jetzige Position im nächsten Schleifendurchlauf die alte sein wird. Da sonst wieder das gleiche Zeichen gefunden werden würde, muss Position um eines erhöht werden. Danach wird nach unserer gerade um eins erhöhten Position nach Wortgrenzen gesucht. Deren Position im Teilstring, der durch bereichsübergreifende Seite slice() erzeugt wurde, wird gleich absolut gemacht.

Auch die nächste Überprüfung wird, außer wenn -1 herausgekommen ist, true ergeben, da Position bereits um den alten Inhalt der Variablen Position erhöht wurde. Diese war um eins höher als altPos auch jetzt noch ist; und da im Fehlerfall -1 zurückgegeben wird, würden diese genau den gleichen Inhalt haben.

Reaktion auf händische Zeilenumbrüche

Natürlich ist es innerhalb eines Textfeldes auch möglich, händische Zeilenumbrüche (bereichsübergreifende Seite \n) durch Betätigung der Entertaste einzufügen. Hier ist der dadurch verbrauchte Platz auch unterschiedlich, da immer, egal wie lange eine Zeile ist, in die nächste Zeile gesprungen wird.

Beispiel:

Abstand += Math.abs((geteilt[Zaehler].length-1) % eingabe.cols - eingabe.cols) + geteilt[Zaehler].length-1;

Erläuterung:

Hier wird zuerst die Zeichenanzahl in der Zeile errechnet (es wird 1 subtrahiert, da das bereichsübergreifende Seite \n das letzte Zeichen sein würde, jenes aber nicht sichtbar und somit irrelevant ist); von diesem wird dann durch das Umwandeln in das Positive nach einer Subtraktion von cols der Restplatz in der Zeile errechnet. Zu diesem wird danach die Länge des Absatzes hinzugerechnet.

Gesamtcode

Gesamte Funktion (ohne der Variablen cols):

function addZeile(eingabe) {
    var Inhalt = eingabe.value;

    var geteilt = Inhalt.split('\n');
    var Abstand = 0;
    var altPos = -1;
    for(var Zaehler = 0; Zaehler < geteilt.length; Zaehler++) {
        var Position = geteilt[Zaehler].search(/ |-/);
        while(Position != altPos) {
            if(parseInt(Position / eingabe.cols) != parseInt(altPos / eingabe.cols))
                Abstand += Math.abs(altPos%eingabe.cols - (eingabe.cols-1));
            altPos = Position;
            Position++;
            Position = geteilt[Zaehler].slice(Position).search(/ |-/)+Position;
        }
        Abstand += Math.abs((geteilt[Zaehler].length-1) % eingabe.cols - eingabe.cols) + geteilt[Zaehler].length-1;
    }

    Abstand = Abstand / eingabe.cols * 17 + 28;
    if(Abstand > 560)
        Abstand = 560;
    eingabe.style.height = Abstand+'px';
}

Vollständiges Beispiel:

Beispiel-Seite Anzeigebeispiel: So sieht's aus

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Beispiel - Größe eines Textfeldes an dessen Inhalt anpassen</title>
<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
<meta name="description" content="Skript zum dynamischen Vergrößern einer Textarea bei der Texteingabe.">
<meta name="keywords" content="mitwachsen, Textarea, Formular, Textfeld, anpassen, js, javascript, jscript,
Inhalt, height, value, cols, rows, Zeilen">
<script type="text/javascript">
<!--
function addZeile(eingabe) {
    var Inhalt = eingabe.value;

    var geteilt = Inhalt.split('\n');
    var Abstand = 0;
    var altPos = -1;
    for(var Zaehler = 0; Zaehler < geteilt.length; Zaehler++) {
        var Position = geteilt[Zaehler].search(/ |-/);
        while(Position != altPos) {
            if(parseInt(Position / eingabe.cols) != parseInt(altPos / eingabe.cols))
                Abstand += Math.abs(altPos%eingabe.cols - (eingabe.cols-1));
            altPos = Position;
            Position++;
            Position = geteilt[Zaehler].slice(Position).search(/ |-/)+Position;
        }
        Abstand += Math.abs((geteilt[Zaehler].length-1) % eingabe.cols - eingabe.cols) + geteilt[Zaehler].length-1;
    }

    Abstand = Abstand / eingabe.cols * 17 + 28;
    if(Abstand > 560)
        Abstand = 560;
    eingabe.style.height = Abstand+'px';
}
//-->
</script>
</head>
<body onload="addZeile(document.getElementById('eingabe'))">
    <form action="">
        <textarea id="eingabe" onkeydown="setTimeout('addZeile(document.getElementById(\'eingabe\'))',10)"
        style="font-size:14px;" cols="60" rows="2">Ihr Text</textarea>
    </form>
</body>
</html>

Teil von SELFHTML aktuell Teil von Artikel Teil von Bereich

© 2006 bereichsübergreifende Seite Impressum, für diese Seite: E-Mail JeSchnell, jeschnell@ymail.com