HTML elementi

Razred Nette\Utils\Html je pomočnik za generiranje HTML kode, ki preprečuje nastanek ranljivosti Cross Site Scripting (XSS).

Deluje tako, da njegovi objekti predstavljajo HTML elemente, katerim nastavimo parametre in jih pustimo izrisati:

$el = Html::el('img');  // ustvari element <img>
$el->src = 'image.jpg'; // nastavi atribut src
echo $el;               // izpiše '<img src="image.jpg">'

Namestitev:

composer require nette/utils

Vsi primeri predpostavljajo ustvarjen vzdevek:

use Nette\Utils\Html;

Ustvarjanje HTML elementa

Element ustvarimo z metodo Html::el():

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

Poleg imena lahko navedete tudi druge atribute v HTML sintaksi:

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

Ali pa jih posredujete kot asociativno polje kot drugi parameter:

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

Sprememba in vrnitev imena elementa:

$el->setName('img');
$el->getName(); // 'img'
$el->isEmpty(); // true, ker je <img> prazen element

HTML atributi

Posamezne HTML atribute lahko spreminjamo in beremo na tri načine, odvisno od vas, kateri vam bo bolj všeč. Prvi je preko lastnosti (properties):

$el->src = 'image.jpg'; // nastavi atribut src

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

unset($el->src);  // prekliče atribut
// ali $el->src = null;

Drugi način je klicanje metod, ki jih za razliko od nastavljanja lastnosti lahko verižimo:

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

$el->alt(null); // preklic atributa

In tretji način je najbolj zgovoren:

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

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

$el->removeAttribute('alt');

Množično lahko atribute nastavite z addAttributes(array $attrs) in odstranite z removeAttributes(array $attrNames).

Vrednost atributa ni nujno samo niz, lahko uporabljate tudi logične vrednosti za logične atribute:

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

Atribut je lahko tudi polje vrednosti, ki se izpišejo ločene s presledki, kar je uporabno na primer za CSS razrede:

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

Alternativa je asociativno polje, kjer vrednosti povedo, ali naj se ključ izpiše:

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

CSS stile je mogoče zapisati v obliki asociativnih polj:

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

Zdaj smo uporabljali lastnosti, vendar se enako lahko zapiše z metodami:

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

Ali celo na najbolj zgovoren način:

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

Še majhna podrobnost za konec: metoda href() lahko olajša sestavljanje query parametrov v URL:

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

Data atributi

Posebno podporo imajo podatkovni atributi (data attributes). Ker njihova imena vsebujejo vezaje, dostop preko lastnosti in metod ni tako eleganten, zato obstaja metoda data():

$el = Html::el('input');
$el->{'data-max-size'} = '500x300'; // ni tako elegantno
$el->data('max-size', '500x300'); // je elegantno
echo $el; // '<input data-max-size="500x300">'

Če je vrednost podatkovnega atributa polje, se samodejno serializira v JSON:

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

Vsebina elementa

Notranjo vsebino elementa nastavimo z metodama setHtml() ali setText(). Prvo uporabite samo v primeru, da veste, da v parametru posredujete zanesljivo varen HTML niz.

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

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

In obratno, notranjo vsebino dobimo z metodama getHtml() ali getText(). Druga odstrani iz izpisa HTML oznake in HTML entitete pretvori v znake.

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

Podrejeni vozli

Notranjost elementa je lahko tudi polje podrejenih (children) vozlov. Vsak izmed njih je lahko bodisi niz ali drug Html element. Vstavljamo jih z addHtml() ali addText():

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

Drug način za ustvarjanje in vstavljanje novega Html vozla:

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

Z vozli lahko delamo enako, kot da bi šlo za polje. Torej dostopati do posameznih z oglatimi oklepaji, jih prešteti z count() in iterirati nad njimi:

$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 vozel lahko vstavite na določeno mesto z insert(?int $index, $child, bool $replace = false). Če je $replace = false, vstavi element na pozicijo $index in ostale premakne. Če je $index = null, doda element na konec.

// vstavi element na prvo pozicijo in ostale premakne
$el->insert(0, Html::el('span'));

Vse vozle dobimo z metodo getChildren() in jih odstranimo z metodo removeChildren().

Ustvarjanje fragmenta dokumenta

Če želimo delati s poljem vozlov in nas ne zanima ovojni element, lahko ustvarimo t.i. document fragment s posredovanjem null namesto imena elementa:

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

Hitrejši način ustvarjanja fragmenta ponujata metodi fromHtml() in fromText():

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

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

Generiranje HTML izpisa

Najenostavnejši način za izpis HTML elementa je uporaba echo ali pretvorba objekta v (string). Lahko tudi ločeno izpišete odpiralne ali zapiralne oznake in atribute:

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

Pomembna značilnost je samodejna zaščita pred Cross Site Scripting (XSS). Vse vrednosti atributov ali vsebina, vstavljena preko setText() ali addText(), se zanesljivo ubežijo (escape):

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

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

Pretvorba HTML ↔ besedilo

Za pretvorbo HTML v besedilo lahko uporabite statično metodo htmlToText():

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

HtmlStringable

Objekt Nette\Utils\Html implementira vmesnik Nette\HtmlStringable, s katerim na primer Latte ali obrazci razlikujejo objekte, ki imajo metodo __toString(), ki vrača HTML kodo. Tako ne pride do dvojnega ubežanja (escaping), če na primer objekt izpišemo v predlogi z {$el}.

različica: 4.0