Елементи на HTML

Класът Nette\Utils\Html е помощно средство за генериране на HTML код, който не позволява уязвимости от типа Cross Site Scripting (XSS).

Начинът, по който тя работи, е, че нейните обекти са HTML елементи, на които задаваме параметри и позволяваме да бъдат визуализирани:

$el = Html::el('img'); // създава елемент <img>
$el->src = 'image.jpg'; // задава атрибута src
echo $el; // отпечатва '<img src='image.jpg'>'

Настройка:

composer require nette/utils

Всички примери предполагат, че псевдонимът вече е създаден:

use Nette\Utils\Html;

Създаване на HTML елемент

Създаване на елемент чрез метода Html::el():

$el = Html::el('img'); // създава елемент <img>

В допълнение към името можете да зададете и други атрибути в синтаксиса на HTML:

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

Или ги предайте като асоциативно поле с втори параметър:

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

Промяна и връщане на името на елемента:

$el->setName('img');
$el->getName(); // 'img'
$el->isEmpty(); // true, тъй като <img> е празен елемент

Атрибути на HTML

Съществуват три начина за промяна и четене на отделни атрибути на HTML и вие трябва да решите кой от тях предпочитате. Първата е чрез собственост:

$el->src = 'image.jpg'; // задава атрибута src

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

unset($el->src); // премахване на атрибута
// или $el->src = null;

Вторият начин е чрез извикване на методи, които, за разлика от задаването на свойства, могат да бъдат верижно свързани:

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

$el->alt(null); // отмяна на атрибут

Третият метод е най-многословен:

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

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

$el->removeAttribute('alt');

Атрибутите могат да се задават масово с addAttributes(array $attrs) и да се премахват с removeAttributes(array $attrNames).

Стойността на атрибута не е задължително да бъде низ, можете също така да използвате булеви стойности за логически атрибути:

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

Атрибутът може да бъде и масив от стойности, които се изобразяват след интервали, което е полезно например за CSS класове:

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

Алтернативата е асоциативен масив, в който стойностите определят дали ключът трябва да бъде визуализиран:

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

CSS стиловете могат да бъдат записани като асоциативни полета:

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

Сега използвахме свойство, но същото може да се напише и с помощта на методи:

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

Или дори в най-кратката форма:

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

Последна подробност: методът href() може да улесни съставянето на параметри на заявката в URL адреса:

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

Атрибути на данните

Атрибутите на данни имат специална поддръжка. Тъй като имената им съдържат тирета, достъпът чрез свойства и методи не е толкова елегантен, затова има метод data():

$el = Html::el('input');
$el->{'data-max-size'} = '500x300'; // не е толкова елегантно
$el->data('max-size', '500x300'); // е елегантно
echo $el; // '<input data-max-size="500x300">'

Ако стойността на атрибут за данни е масив, тя автоматично се сериализира в JSON:

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

Съдържание на елемента

Задайте вътрешното съдържание на елемента, като използвате методите setHtml() или setText(). Използвайте първата опция само ако знаете, че в параметъра се предава защитен HTML низ.

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

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

Обратно, използвайте методите getHtml() или getText(), за да получите вътрешното съдържание. Последният метод премахва HTML таговете от изхода и преобразува HTML същностите в символи.

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

Дъщерни възли

В рамките на един елемент може да има и масив от дъщерни възли. Всеки от тях може да бъде низ или друг елемент Html. Те се поставят с помощта на addHtml() или addText():

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

Друг начин за създаване и вмъкване на нов възел Html:

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

Можете да работите с възли, сякаш са масиви. Тоест адресирайте всеки от тях с квадратни скоби, пребройте ги с count() и извършете итерация:

$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

Нов възел може да бъде вмъкнат на определено място с помощта на insert(?int $index, $child, bool $replace = false). Ако тя е $replace = false, елементът ще бъде вмъкнат в позицията $index, а останалите ще бъдат преместени. Ако тя е $index = null, елементът се добавя последен.

// вмъква елемента на първа позиция и измества останалите
$el->insert(0, Html::el('span'));

Всички възли се извличат по метода getChildren() и се премахват по метода removeChildren().

Създаване на фрагмент от документ

Ако искаме да работим с масив от възли и не се интересуваме от обгръщащ елемент, можем да създадем фрагмент на документ, като подадем null вместо името на елемента:

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

Методите fromHtml() и fromText() предлагат по-бърз начин за създаване на фрагмент:

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

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

Генериране на HTML изход

Най-лесният начин за извеждане на HTML елемент е да използвате echo или да пренапишете обекта на (string). Можете също така да извеждате отделно отварящи или затварящи тагове и атрибути:

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

Важна функция е автоматичната защита срещу скриптиране на кръстосани сайтове (XSS). Всички стойности на атрибути или съдържание, вмъкнати чрез setText() или addText(), се ескапират по сигурен начин:

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

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

Преобразуване на HTML ↔ текст

За да преобразувате HTML в текст, можете да използвате статичния метод htmlToText():

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

HtmlStringable

Обектът Nette\Utils\Html имплементира интерфейса Nette\HtmlStringable, който например Latte или Forms използват, за да разграничат обектите, които имат метод __toString(), който връща HTML код. Така че няма да има двойна проверка, ако например изброим обект в шаблон, използвайки {$el}.

версия: 4.0