HTML elementy
Třída Nette\Utils\Html je pomocník pro generování HTML kódu, který nedovolí vznik zranitelnosti Cross Site Scripting (XSS).
Funguje tak, že jeho objekty představují HTML elementy, kterým nastavíme parametry a necháme je vykreslit:
$el = Html::el('img'); // vytvoří element <img> $el->src = 'image.jpg'; // nastaví atribut src echo $el; // vypíše '<img src="image.jpg">'
Instalace:
composer require nette/utils
Všechny příklady předpokládají vytvořený alias:
use Nette\Utils\Html;
Vyvoření HTML elementu
Element vytvoříme metodou Html::el()
:
$el = Html::el('img'); // vytvoří element <img>
Kromě názvu můžete zadat i další atributy v HTML syntaxi:
$el = Html::el('input type=text class="red important"');
Nebo je předat jako asociativní pole druhým parametrem:
$el = Html::el('input', [ 'type' => 'text', 'class' => 'important', ]);
Změna a vrácení názvu elementu:
$el->setName('img'); $el->getName(); // 'img' $el->isEmpty(); // true, jelikož <img> je prázdný element
HTML atributy
Jednotlivé HTML atributy můžeme měnit a číst třemi způsoby, záleží na vás, který se vám bude líbit víc. První z nich je skrze property:
$el->src = 'image.jpg'; // nastaví atribut src echo $el->src; // 'image.jpg' unset($el->src); // zruší atribut // nebo $el->src = null;
Druhou cestou je volání metod, které oproti nastavování properties můžeme za sebe řetězit:
$el = Html::el('img')->src('image.jpg')->alt('photo'); // <img src="image.jpg" alt="photo"> $el->alt(null); // zrušení atributu
A třetí způsob je nejvíce upovídaný:
$el = Html::el('img') ->setAttribute('src', 'image.jpg') ->setAttribute('alt', 'photo'); echo $el->getAttribute('src'); // 'image.jpg' $el->removeAttribute('alt');
Hromadně lze atributy nastavit pomocí addAttributes(array $attrs)
a odstranit pomocí removeAttributes(array $attrNames)
.
Hodnotou atributu nemusí být jen řetězec, lze používat i logické hodnoty pro logické atributy:
$checkbox = Html::el('input')->type('checkbox'); $checkbox->checked = true; // <input type="checkbox" checked> $checkbox->checked = false; // <input type="checkbox">
Atributem může být i pole hodnot, které se vypíší oddělené mezerami, což se hodí například pro CSS třídy:
$el = Html::el('input'); $el->class[] = 'active'; $el->class[] = null; // null se ignoruje $el->class[] = 'top'; echo $el; // '<input class="active top">'
Alternativou je asociativní pole, kde hodnoty říkají, zda má být klíč vypsán:
$el = Html::el('input'); $el->class['active'] = true; $el->class['top'] = false; echo $el; // '<input class="active">'
CSS styly lze zapisovat ve formě asociativních polí:
$el = Html::el('input'); $el->style['color'] = 'green'; $el->style['display'] = 'block'; echo $el; // '<input style="color: green; display: block">'
Nyní jsme používali property, ale totéž se dá zapsat pomocí metod:
$el = Html::el('input'); $el->style('color', 'green'); $el->style('display', 'block'); echo $el; // '<input style="color: green; display: block">'
Nebo i tím nejvíce upovídaným způsobem:
$el = Html::el('input'); $el->appendAttribute('style', 'color', 'green'); $el->appendAttribute('style', 'display', 'block'); echo $el; // '<input style="color: green; display: block">'
Ještě drobnost na závěr: metoda href()
umí usnadnit skládání query parametrů v URL:
echo Html::el('a')->href('index.php', [ 'id' => 10, 'lang' => 'en', ]); // '<a href="index.php?id=10&lang=en"></a>'
Data attributy
Speciální podporu mají datové atributy. Protože jejich názvy obsahují pomlčky, není přístup přes property a metody tak elegantní, proto existuje metoda data()
:
$el = Html::el('input'); $el->{'data-max-size'} = '500x300'; // není tolik elegantní $el->data('max-size', '500x300'); // je elegatní echo $el; // '<input data-max-size="500x300">'
Pokud je hodnotou datového attributu pole, automaticky se serializuje do JSONu:
$el = Html::el('input'); $el->data('items', [1,2,3]); echo $el; // '<input data-items="[1,2,3]">'
Obsah elementu
Vnitřní obsah elementu nastavíme metodami setHtml()
či setText()
. První z nich použijte jen v případě, že víte, že v parametru předáváte spolehlivě bezpečný HTML řetězec.
echo Html::el('span')->setHtml('hello<br>'); // '<span>hello<br></span>' echo Html::el('span')->setText('10 < 20'); // '<span>10 < 20</span>'
A obráceně vnitřní obsah získáme metodami getHtml()
či getText()
. Druhá z nich odstraní z výstupu HTML značky a HTML entity převede na znaky.
echo $el->getHtml(); // '10 < 20' echo $el->getText(); // '10 < 20'
Podřízené uzly
Vnitřek elementu může být také pole podřízených (children) uzlů. Každý z nich může být buď řetězec, nebo další Html
element. Vkládáme je pomocí addHtml()
či addText()
:
$el = Html::el('span') ->addHtml('hello<br>') ->addText('10 < 20') ->addHtml( Html::el('br') ); // <span>hello<br>10 < 20<br></span>
Další způsob pro vytvoření a vložení nového Html
uzlu:
$ul = Html::el('ul'); $ul->create('li', ['class' => 'first']) ->setText('první'); // <ul><li class="first">první</li></ul>
S uzly lze pracovat stejně, jako by se jednalo o pole. Tedy přistupovat k jednotlivým z nich pomocí hranatých závorek, spočítat je pomocí count()
a iterovat nad nimi:
$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
Nový uzel lze na konkrétní místo vložit pomocí insert(?int $index, $child, bool $replace = false)
. Pokud je $replace = false
, vloží prvek na pozici $index
a ostatní posune. Pokud je $index = null
, přidá prvek nakonec.
// vloží prvek na první pozici a ostatní posune $el->insert(0, Html::el('span'));
Všechny uzly získáme metodou getChildren()
a odstraníme je metodou removeChildren()
.
Vytvoření document fragment
Pokud chceme pracovat s polem uzlů a nezajímá nás obalovací element, můžeme vytvořit tzv. document fragment předáním null
místo jména elementu:
$el = Html::el(null) ->addHtml('hello<br>') ->addText('10 < 20') ->addHtml( Html::el('br') ); // hello<br>10 < 20<br>
Rychlejší způsob vytvoření fragmentu nabízí metody fromHtml()
a fromText()
:
$el = Html::fromHtml('hello<br>'); echo $el; // 'hello<br>' $el = Html::fromText('10 < 20'); echo $el; // '10 < 20'
Generování HTML výstupu
Nejjednodušším způsobem, jak vypsat HTML element, je použít echo
nebo objekt přetypovat na (string)
. Lze také samostatně vypsat otevírací nebo uzavírací značky a atributy:
$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"'
Důležitým rysem je automatická ochrana proti Cross Site Scriptingu (XSS). Všechny hodnoty atributů nebo obsah vložený přes setText()
či addText()
se spolehlivě escapuje:
echo Html::el('div') ->title('" onmouseover="bad()') ->setText('<script>bad()</script>'); // <div title='" onmouseover="bad()'><script>bad()</script></div>
Konverze HTML ↔ text
Pro převod HTML do textu můžete využít statickou metodu htmlToText()
:
echo Html::htmlToText('<span>One & Two</span>'); // 'One & Two'
HtmlStringable
Objekt Nette\Utils\Html
implementuje rozhraní Nette\HtmlStringable
, kterým například Latte nebo formuláře rozlišují objekty, které mají metodu __toString()
vracející HTML kód. Takže nedojde k dvojímu escapování, pokud třeba objekt vypíšeme v šabloně pomocí {$el}
.