Thanks to visit codestin.com
Credit goes to doc.nette.org

Elementy HTML

Klasa Nette\Utils\Html jest pomocnikiem do generowania kodu HTML, który zapobiega powstawaniu podatności Cross Site Scripting (XSS).

Działa tak, że jej obiekty reprezentują elementy HTML, którym ustawiamy parametry i pozwalamy je wyrenderować:

$el = Html::el('img');  // tworzy element <img>
$el->src = 'image.jpg'; // ustawia atrybut src
echo $el;               // wypisuje '<img src="image.jpg">'

Instalacja:

composer require nette/utils

Wszystkie przykłady zakładają, że został utworzony alias:

use Nette\Utils\Html;

Tworzenie elementu HTML

Element tworzymy metodą Html::el():

$el = Html::el('img'); // tworzy element <img>

Oprócz nazwy możesz podać również inne atrybuty w składni HTML:

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

Lub przekazać je jako tablicę asocjacyjną drugim parametrem:

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

Zmiana i zwrócenie nazwy elementu:

$el->setName('img');
$el->getName(); // 'img'
$el->isEmpty(); // true, ponieważ <img> jest pustym elementem

Atrybuty HTML

Poszczególne atrybuty HTML możemy zmieniać i odczytywać na trzy sposoby, zależy od Ciebie, który bardziej Ci się spodoba. Pierwszy z nich to poprzez właściwości (properties):

$el->src = 'image.jpg'; // ustawia atrybut src

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

unset($el->src);  // usuwa atrybut
// lub $el->src = null;

Drugim sposobem jest wywoływanie metod, które w przeciwieństwie do ustawiania właściwości możemy łączyć w łańcuch:

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

$el->alt(null); // usunięcie atrybutu

A trzeci sposób jest najbardziej rozbudowany:

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

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

$el->removeAttribute('alt');

Zbiorczo można ustawić atrybuty za pomocą addAttributes(array $attrs) i usunąć za pomocą removeAttributes(array $attrNames).

Wartością atrybutu nie musi być tylko ciąg znaków, można używać również wartości logicznych dla atrybutów logicznych:

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

Atrybutem może być również tablica wartości, które zostaną wypisane oddzielone spacjami, co przydaje się na przykład dla klas CSS:

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

Alternatywą jest tablica asocjacyjna, gdzie wartości mówią, czy klucz ma być wypisany:

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

Style CSS można zapisywać w formie tablic asocjacyjnych:

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

Teraz używaliśmy właściwości, ale to samo można zapisać za pomocą metod:

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

Lub nawet najbardziej rozbudowanym sposobem:

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

Jeszcze drobiazg na koniec: metoda href() potrafi ułatwić składanie parametrów query w URL:

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

Atrybuty danych (Data attributes)

Specjalne wsparcie mają atrybuty danych. Ponieważ ich nazwy zawierają myślniki, dostęp przez właściwości i metody nie jest tak elegancki, dlatego istnieje metoda data():

$el = Html::el('input');
$el->{'data-max-size'} = '500x300'; // nie jest tak eleganckie
$el->data('max-size', '500x300'); // jest eleganckie
echo $el; // '<input data-max-size="500x300">'

Jeśli wartością atrybutu danych jest tablica, automatycznie serializuje się do JSON:

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

Zawartość elementu

Wewnętrzną zawartość elementu ustawiamy metodami setHtml() lub setText(). Pierwszej z nich używaj tylko w przypadku, gdy wiesz, że w parametrze przekazujesz niezawodnie bezpieczny ciąg HTML.

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

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

I odwrotnie, wewnętrzną zawartość uzyskamy metodami getHtml() lub getText(). Druga z nich usuwa z wyniku znaczniki HTML i konwertuje encje HTML na znaki.

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

Węzły podrzędne

Wnętrze elementu może być również tablicą węzłów podrzędnych (children). Każdy z nich może być albo ciągiem znaków, albo kolejnym elementem Html. Wstawiamy je za pomocą addHtml() lub addText():

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

Inny sposób na utworzenie i wstawienie nowego węzła Html:

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

Z węzłami można pracować tak samo, jakby były tablicą. Czyli uzyskiwać dostęp do poszczególnych z nich za pomocą nawiasów kwadratowych, liczyć je za pomocą count() i iterować po nich:

$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

Nowy węzeł można wstawić w konkretne miejsce za pomocą insert(?int $index, $child, bool $replace = false). Jeśli $replace = false, wstawia element na pozycję $index i przesuwa pozostałe. Jeśli $index = null, dodaje element na koniec.

// wstawia element na pierwszą pozycję i przesuwa pozostałe
$el->insert(0, Html::el('span'));

Wszystkie węzły uzyskamy metodą getChildren() i usuniemy je metodą removeChildren().

Tworzenie fragmentu dokumentu

Jeśli chcemy pracować z tablicą węzłów i nie interesuje nas element otaczający, możemy utworzyć tzw. fragment dokumentu, przekazując null zamiast nazwy elementu:

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

Szybszy sposób tworzenia fragmentu oferują metody fromHtml() i fromText():

$el = Html::fromHtml('hello<br>');
echo $el; // 'hello<br>'

$el = Html::fromText('10 < 20');
echo $el; // '10 &lt; 20'

Generowanie wyniku HTML

Najprostszym sposobem na wypisanie elementu HTML jest użycie echo lub rzutowanie obiektu na (string). Można również osobno wypisać znaczniki otwierające lub zamykające oraz atrybuty:

$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"'

Ważną cechą jest automatyczna ochrona przed Cross Site Scripting (XSS). Wszystkie wartości atrybutów lub zawartość wstawiona przez setText() lub addText() są niezawodnie eskejpowane:

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

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

Konwersja HTML ↔ tekst

Do konwersji HTML na tekst możesz użyć statycznej metody htmlToText():

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

HtmlStringable

Obiekt Nette\Utils\Html implementuje interfejs Nette\HtmlStringable, za pomocą którego na przykład Latte lub formularze rozróżniają obiekty, które mają metodę __toString() zwracającą kod HTML. Dzięki temu nie dojdzie do podwójnego eskejpowania, jeśli na przykład wypiszemy obiekt w szablonie za pomocą {$el}.

wersja: 4.x