HTML-Elemente

Die Klasse Nette\Utils\Html ist ein Helfer zum Erzeugen von HTML-Code, der dabei hilft, Sicherheitslücken durch Cross-Site Scripting (XSS) zu verhindern.

Sie funktioniert so, dass ihre Objekte HTML-Elemente repräsentieren; Sie setzen deren Parameter und rendern sie anschließend:

$el = Html::el('img');  // erzeugt das Element <img>
$el->src = 'image.jpg'; // setzt das Attribut src
echo $el;               // gibt '<img src="image.jpg">' aus

Den Körper eines Elements füllen Sie mit der Methode add() mit Text und weiteren Elementen. Text wird automatisch escapt, Elemente werden so eingefügt, wie sie sind:

echo Html::el('div')->add(
	'Hallo ',
	Html::el('b')->setText('Welt'),
);
// '<div>Hallo <b>Welt</b></div>'

Installation:

composer require nette/utils

Alle Beispiele setzen voraus, dass dieser Klassen-Alias definiert ist:

use Nette\Utils\Html;

Erzeugen eines HTML-Elements

Ein Element wird mit der Methode Html::el() erzeugt:

$el = Html::el('img'); // erzeugt das Element <img>

Neben dem Namen können Sie in HTML-Syntax auch weitere Attribute angeben:

$el = Html::el('input type=text class="red important"');

Oder Sie übergeben sie als assoziatives Array im zweiten Parameter:

$el = Html::el('input', [
	'type' => 'text',
	'class' => 'important',
]);

So ändern und lesen Sie den Namen des Elements:

$el->setName('img');
$el->getName(); // 'img'
$el->isEmpty(); // true, denn <img> ist ein leeres Element

HTML-Attribute

Die einzelnen HTML-Attribute lassen sich auf drei Arten setzen und auslesen; welche Ihnen lieber ist, bleibt Ihnen überlassen. Die erste geht über Properties:

$el->src = 'image.jpg'; // setzt das Attribut src

echo $el->src; // 'image.jpg'

unset($el->src);  // entfernt das Attribut
// oder $el->src = null;

Die zweite Art sind Methodenaufrufe, die sich anders als das Setzen von Properties verketten lassen:

$el = Html::el('img')->src('image.jpg')->alt('photo');
// <img src="image.jpg" alt="photo">

$el->alt(null); // entfernt das Attribut

Und die dritte Art ist die ausführlichste:

$el = Html::el('img')
	->setAttribute('src', 'image.jpg')
	->setAttribute('alt', 'photo');

echo $el->getAttribute('src'); // 'image.jpg'

$el->removeAttribute('alt');

Attribute lassen sich mit addAttributes(array $attrs) gesammelt setzen und mit removeAttributes(array $attrNames) gesammelt entfernen.

Der Wert eines Attributs muss nicht nur ein String sein; für boolesche Attribute lassen sich boolesche Werte verwenden:

$checkbox = Html::el('input')->type('checkbox');
$checkbox->checked = true;  // <input type="checkbox" checked>
$checkbox->checked = false; // <input type="checkbox">

Ein Attribut kann auch ein Array von Werten sein, die durch Leerzeichen getrennt ausgegeben werden. Das ist zum Beispiel für CSS-Klassen nützlich:

$el = Html::el('input');
$el->class[] = 'active';
$el->class[] = null; // null wird ignoriert
$el->class[] = 'top';
echo $el; // '<input class="active top">'

Eine Alternative ist ein assoziatives Array, dessen Werte angeben, ob der Schlüssel enthalten sein soll:

$el = Html::el('input');
$el->class['active'] = true;
$el->class['top'] = false;
echo $el; // '<input class="active">'

CSS-Stile lassen sich als assoziative Arrays schreiben:

$el = Html::el('input');
$el->style['color'] = 'green';
$el->style['display'] = 'block';
echo $el; // '<input style="color:green;display:block">'

Bisher haben wir Properties verwendet, dasselbe lässt sich aber auch mit Methoden erreichen:

$el = Html::el('input');
$el->style('color', 'green');
$el->style('display', 'block');
echo $el; // '<input style="color:green;display:block">'

Oder sogar auf die ausführlichste Weise:

$el = Html::el('input');
$el->appendAttribute('style', 'color', 'green');
$el->appendAttribute('style', 'display', 'block');
echo $el; // '<input style="color:green;display:block">'

Eine letzte Kleinigkeit: Die Methode href() kann das Zusammensetzen von Query-Parametern einer URL vereinfachen:

echo Html::el('a')->href('index.php', [
	'id' => 10,
	'lang' => 'en',
]);
// '<a href="index.php?id=10&amp;lang=en"></a>'

Data-Attribute

Data-Attribute werden besonders unterstützt. Weil ihre Namen Bindestriche enthalten, ist der Zugriff über Properties und Methoden nicht so elegant, deshalb gibt es die eigene Methode data():

$el = Html::el('input');
$el->{'data-max-size'} = '500x300'; // nicht so elegant
$el->data('max-size', '500x300'); // ist elegant
echo $el; // '<input data-max-size="500x300">'

Ist der Wert eines Data-Attributs ein Array, wird er automatisch nach JSON serialisiert:

$el = Html::el('input');
$el->data('items', [1,2,3]);
echo $el; // '<input data-items="[1,2,3]">'

Inhalt des Elements

Den inneren Inhalt des Elements setzen Sie mit den Methoden setHtml() oder setText(). Die erste verwenden Sie nur dann, wenn Sie sicher sind, dass der Parameter einen verlässlich sicheren HTML-String enthält.

echo Html::el('span')->setHtml('hello<br>');
// '<span>hello<br></span>'

echo Html::el('span')->setText('10 < 20');
// '<span>10 &lt; 20</span>'

Umgekehrt lässt sich der innere Inhalt mit den Methoden getHtml() oder getText() auslesen. Die zweite entfernt HTML-Tags aus dem Inhalt und wandelt HTML-Entities zurück in Zeichen.

echo $el->getHtml(); // '10 &lt; 20'
echo $el->getText(); // '10 < 20'

Kindknoten

Der innere Inhalt eines Elements kann auch ein Array von Kindknoten sein. Jedes Kind kann entweder ein String oder ein weiteres Html-Objekt sein. Hinzugefügt werden sie mit addHtml() oder addText():

$el = Html::el('span')
	->addHtml('hello<br>')
	->addText('10 < 20')
	->addHtml( Html::el('br') );
// <span>hello<br>10 &lt; 20<br></span>

Die Methode add() fügt mehrere Kinder auf einmal ein. Strings werden genauso escapt wie bei addText(), Html-Objekte werden so eingefügt, wie sie sind, und null-Werte werden übersprungen, was sich für bedingte Inhalte anbietet. Einen String, der verlässlich sicheres HTML ist, verpacken Sie in Html::html():

$el = Html::el('span')->add(
	'10 < 20',
	Html::el('br'),
	Html::html('hello<br>'),
	$showNote ? Html::el('small')->setText('note') : null,
);
// <span>10 &lt; 20<br>hello<br><small>note</small></span>

Eine weitere Möglichkeit, einen neuen Html-Knoten zu erzeugen und einzufügen:

$ul = Html::el('ul');
$ul->create('li', ['class' => 'first'])
	->setText('erster');
// <ul><li class="first">erster</li></ul>

Mit den Knoten lässt sich arbeiten, als wären sie Array-Elemente. Sie greifen also über eckige Klammern auf einzelne Knoten zu, zählen sie mit count() und iterieren über sie:

$el = Html::el('div');
$el[] = '<b>hello</b>';
$el[] = Html::el('span');
echo $el[1]; // '<span></span>'

foreach ($el as $child) { /* ... */ }

echo count($el); // 2

Einen neuen Knoten fügen Sie mit insert(?int $index, $child, bool $replace = false) an einer bestimmten Position ein. Ist $replace = false, wird das Element an der Position $index eingefügt und die übrigen werden verschoben. Ist $index = null, wird das Element ans Ende angehängt.

// fügt das Element an der ersten Position ein und verschiebt die übrigen
$el->insert(0, Html::el('span'));

Alle Knoten liefert die Methode getChildren(), entfernen lassen sie sich mit der Methode removeChildren().

Erzeugen eines Dokumentfragments

Wenn Sie mit einer Menge von Knoten arbeiten wollen und kein umschließendes Element brauchen, können Sie ein Dokumentfragment erzeugen. Es rendert nur seine Kinder, ohne einen eigenen Tag. Die Methode fragment() erzeugt es und füllt es in einem einzigen Aufruf mit Kindern, nach denselben Regeln wie add():

echo Html::fragment(
	Html::el('strong')->setText('hello'),
	'10 < 20',
	Html::el('br'),
);
// <strong>hello</strong>10 &lt; 20<br>

Ein Fragment mit ausschließlich Text- oder ausschließlich HTML-Inhalt erzeugen die Methoden text() und html():

echo Html::text('10 < 20');   // '10 &lt; 20'
echo Html::html('hello<br>'); // 'hello<br>'

Wenn Sie Versionen vor 4.1.5 unterstützen müssen, erzeugen Sie ein Fragment, indem Sie statt eines Elementnamens null übergeben, und füllen es mit addHtml() und addText(). Statt text() und html() bieten diese Versionen die Methoden fromText() und fromHtml(), die weiterhin funktionieren, aber veraltet sind:

$el = Html::el(null)
	->addHtml('hello<br>')
	->addText('10 < 20');
// hello<br>10 &lt; 20

echo Html::fromText('10 < 20');   // '10 &lt; 20'
echo Html::fromHtml('hello<br>'); // 'hello<br>'

Erzeugen der HTML-Ausgabe

Am einfachsten geben Sie ein HTML-Element mit echo aus oder casten das Objekt nach (string). Sie können auch den öffnenden Tag, den schließenden Tag und die Attribute getrennt ausgeben:

$el = Html::el('div class=header')->setText('hello');

echo $el;               // '<div class="header">hello</div>'
$s = (string) $el;      // '<div class="header">hello</div>'
$s = $el->toHtml();     // '<div class="header">hello</div>'
$s = $el->toText();     // 'hello'
echo $el->startTag();   // '<div class="header">'
echo $el->endTag();     // '</div>'
echo $el->attributes(); // 'class="header"'

Die Methode render(?int $indent = null) bietet eine hübsche Formatierung. Wenn Sie eine Einrückungsebene übergeben, wird die Ausgabe über mehrere Zeilen sauber eingerückt:

echo $el->render(0); // gibt eingerücktes HTML zurück

Eine wichtige Eigenschaft ist der automatische Schutz vor Cross-Site Scripting (XSS). Alle Attributwerte und alle über setText(), addText(), add() oder fragment() eingefügten Inhalte werden verlässlich escapt:

echo Html::el('div')
	->title('" onmouseover="bad()')
	->setText('<script>bad()</script>');

// <div title='" onmouseover="bad()'>&lt;script&gt;bad()&lt;/script&gt;</div>

Umwandlung HTML ↔ Text

Zur Umwandlung von HTML in Text können Sie die statische Methode htmlToText() verwenden:

echo Html::htmlToText('<span>One &amp; Two</span>'); // 'One & Two'

HtmlStringable

Das Objekt Nette\Utils\Html implementiert das Interface Nette\HtmlStringable. Latte und Forms nutzen dieses Interface zum Beispiel, um Objekte zu erkennen, deren Methode __toString() HTML-Code zurückgibt. Das verhindert doppeltes Escaping, wenn Sie das Objekt etwa im Template mit {$el} ausgeben.

Version: 4.x