Στοιχεία 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 Attributes

Μπορείτε να ορίσετε και να λάβετε μεμονωμένα χαρακτηριστικά 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">

Ένα attribute μπορεί επίσης να είναι ένας πίνακας από tokens, τα οποία παρατίθενται χωρισμένα με κενά διαστήματα, κάτι που είναι κατάλληλο για παράδειγμα για κλάσεις CSS:

$el = Html::el('input');
$el->class[] = 'active';
$el->class[] = null; // το null αγνοείται
$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"></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"'

Ένα σημαντικό χαρακτηριστικό είναι η αυτόματη προστασία από Cross Site Scripting (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 ↔ Κείμενο

Μπορείτε να χρησιμοποιήσετε τη στατική μέθοδο htmlToText() για να μετατρέψετε την HTML σε κείμενο:

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

HtmlStringable

Το αντικείμενο Nette\Utils\Html υλοποιεί τη διεπαφή Nette\HtmlStringable, την οποία, για παράδειγμα, χρησιμοποιούν οι Latte ή οι φόρμες για να διακρίνουν τα αντικείμενα που έχουν μια μέθοδο __toString() που επιστρέφει κώδικα HTML. Έτσι, η διπλή διαφυγή δεν εμφανίζεται αν, για παράδειγμα, εκτυπώσουμε το αντικείμενο στο πρότυπο χρησιμοποιώντας το {$el}.