-
-
Notifications
You must be signed in to change notification settings - Fork 277
Expand file tree
/
Copy pathhtml-elements.texy
More file actions
316 lines (222 loc) · 11.6 KB
/
html-elements.texy
File metadata and controls
316 lines (222 loc) · 11.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
HTML-элементы
*************
.[perex]
Класс [api:Nette\Utils\Html] является помощником для генерации HTML-кода, который предотвращает возникновение уязвимости Cross Site Scripting (XSS).
Принцип работы заключается в том, что его объекты представляют HTML-элементы, которым мы устанавливаем параметры и затем отображаем их:
```php
$el = Html::el('img'); // создает элемент <img>
$el->src = 'image.jpg'; // устанавливает атрибут src
echo $el; // выводит '<img src="image.jpg">'
```
Установка:
```shell
composer require nette/utils
```
Все примеры предполагают, что создан псевдоним:
```php
use Nette\Utils\Html;
```
Создание HTML-элемента
======================
Элемент создаем методом `Html::el()`:
```php
$el = Html::el('img'); // создает элемент <img>
```
Кроме имени, вы можете указать и другие атрибуты в синтаксисе HTML:
```php
$el = Html::el('input type=text class="red important"');
```
Или передать их как ассоциативный массив вторым параметром:
```php
$el = Html::el('input', [
'type' => 'text',
'class' => 'important',
]);
```
Изменение и возврат имени элемента:
```php
$el->setName('img');
$el->getName(); // 'img'
$el->isEmpty(); // true, поскольку <img> является пустым элементом (void element)
```
HTML-атрибуты
=============
Отдельные HTML-атрибуты мы можем изменять и читать тремя способами, какой из них вам больше понравится, зависит от вас. Первый — через свойства:
```php
$el->src = 'image.jpg'; // устанавливает атрибут src
echo $el->src; // 'image.jpg'
unset($el->src); // удаляет атрибут
// или $el->src = null;
```
Второй путь — вызов методов, которые, в отличие от установки свойств, мы можем вызывать цепочкой:
```php
$el = Html::el('img')->src('image.jpg')->alt('photo');
// <img src="image.jpg" alt="photo">
$el->alt(null); // удаление атрибута
```
И третий способ — самый многословный:
```php
$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)`.
Значением атрибута не обязательно должна быть только строка, можно использовать и логические значения для логических атрибутов (boolean attributes):
```php
$checkbox = Html::el('input')->type('checkbox');
$checkbox->checked = true; // <input type=
8000
"checkbox" checked>
$checkbox->checked = false; // <input type="checkbox">
```
Атрибутом может быть и массив значений, которые выводятся разделенными пробелами, что подходит, например, для CSS-классов:
```php
$el = Html::el('input');
$el->class[] = 'active';
$el->class[] = null; // null игнорируется
$el->class[] = 'top';
echo $el; // '<input class="active top">'
```
Альтернативой является ассоциативный массив, где значения `true`/`false` указывают, должен ли ключ быть выведен:
```php
$el = Html::el('input');
$el->class['active'] = true;
$el->class['top'] = false;
echo $el; // '<input class="active">'
```
CSS-стили можно записывать в виде ассоциативных массивов:
```php
$el = Html::el('input');
$el->style['color'] = 'green';
$el->style['display'] = 'block';
echo $el; // '<input style="color: green; display: block">'
```
Сейчас мы использовали свойства, но то же самое можно записать с помощью методов:
```php
$el = Html::el('input');
$el->style('color', 'green');
$el->style('display', 'block');
echo $el; // '<input style="color: green; display: block">'
```
Или даже самым многословным способом:
```php
$el = Html::el('input');
$el->appendAttribute('style', 'color', 'green');
$el->appendAttribute('style', 'display', 'block');
echo $el; // '<input style="color: green; display: block">'
```
Еще одна мелочь напоследок: метод `href()` умеет упрощать составление query-параметров в URL:
```php
echo Html::el('a')->href('index.php', [
'id' => 10,
'lang' => 'en',
]);
// '<a href="index.php?id=10&lang=en"></a>'
```
Data-атрибуты
-------------
Особую поддержку имеют data-атрибуты (`data-*`). Поскольку их имена содержат дефисы, доступ через свойства и методы не так элегантен, поэтому существует метод `data()`:
```php
$el = Html::el('input');
$el->{'data-max-size'} = '500x300'; // не так элегантно
$el->data('max-size', '500x300'); // элегантно
echo $el; // '<input data-max-size="500x300">'
```
Если значением data-атрибута является массив, он автоматически сериализуется в JSON:
```php
$el = Html::el('input');
$el->data('items', [1,2,3]);
echo $el; // '<input data-items="[1,2,3]">'
```
Содержимое элемента
===================
Внутреннее содержимое элемента устанавливаем методами `setHtml()` или `setText()`. Первый из них используйте только в случае, если вы уверены, что в параметре передаете надежно безопасную HTML-строку.
```php
echo Html::el('span')->setHtml('hello<br>');
// '<span>hello<br></span>'
echo Html::el('span')->setText('10 < 20');
// '<span>10 < 20</span>'
```
И наоборот, внутреннее содержимое получаем методами `getHtml()` или `getText()`. Вторая из них удаляет из вывода HTML-теги и преобразует HTML-сущности в символы.
```php
echo $el->getHtml(); // '10 < 20'
echo $el->getText(); // '10 < 20'
```
Дочерние узлы
-------------
Внутреннее содержимое элемента может быть также массивом дочерних узлов. Каждый из них может быть либо строкой, либо другим `Html` элементом. Вставляем их с помощью `addHtml()` или `addText()`:
```php
$el = Html::el('span')
->addHtml('hello<br>')
->addText('10 < 20')
->addHtml( Html::el('br') );
// <span>hello<br>10 < 20<br></span>
```
Другой способ создания и вставки нового `Html` узла:
```php
$ul = Html::el('ul');
$ul->create('li', ['class' => 'first'])
->setText('první');
// <ul><li class="first">první</li></ul>
```
С узлами можно работать так же, как если бы это был массив. То есть получать доступ к отдельным из них с помощью квадратных скобок, посчитать их с помощью `count()` и итерировать по ним:
```php
$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`, добавляет элемент в конец.
```php
// вставляет элемент на первую позицию и сдвигает остальные
$el->insert(0, Html::el('span'));
```
Все узлы получаем методом `getChildren()` и удаляем их методом `removeChildren()`.
Создание document fragment
--------------------------
Если мы хотим работать с массивом узлов и нас не интересует обрамляющий элемент, мы можем создать так называемый *document fragment*, передав `null` вместо имени элемента:
```php
$el = Html::el(null)
->addHtml('hello<br>')
->addText('10 < 20')
->addHtml( Html::el('br') );
// hello<br>10 < 20<br>
```
Более быстрый способ создания фрагмента предлагают методы `fromHtml()` и `fromText()`:
```php
$el = Html::fromHtml('hello<br>');
echo $el; // 'hello<br>'
$el = Html::fromText('10 < 20');
echo $el; // '10 < 20'
```
Генерация HTML-вывода
=====================
Самый простой способ вывести HTML-элемент — использовать `echo` или преобразовать объект в `(string)`. Можно также отдельно вывести открывающие или закрывающие теги и атрибуты:
```php
$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"'
```
Важной особенностью является автоматическая защита от [Cross Site Scripting (XSS) |nette:glossary#Cross-Site Scripting XSS]. Все значения атрибутов или содержимое, вставленное через `setText()` или `addText()`, надежно экранируются:
```php
echo Html::el('div')
->title('" onmouseover="bad()')
->setText('<script>bad()</script>');
// <div title='" onmouseover="bad()'><script>bad()</script></div>
```
Преобразование HTML ↔ текст
===========================
Для преобразования HTML в текст вы можете использовать статический метод `htmlToText()`:
```php
echo Html::htmlToText('<span>One & Two</span>'); // 'One & Two'
```
HtmlStringable
==============
Объект `Nette\Utils\Html` реализует интерфейс `Nette\HtmlStringable`, с помощью которого, например, Latte или формы различают объекты, имеющие метод `__toString()`, возвращающий HTML-код. Таким образом, не произойдет двойного экранирования, если, например, мы выведем объект в шаблоне с помощью `{$el}`.