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>
Výstup je možné přepnout do XHTML nastavením statické proměnné Html::$xhtml
na true:
$el = Html::el('input')->disabled(true);
echo $el; // '<input disabled>'
Html::$xhtml = true;
echo $el; // '<input disabled="disabled" />'
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}
.
V nette/utils před verzí 3.2 se rozhraní jmenovalo Nette\Utils\IHtmlString
.