source: includes/NHtml.php

Last change on this file was 1, checked in by george, 16 years ago

Prvnotní import původních kódů z wowresource.

File size: 10.0 KB
Line 
1<?php
2
3/**
4 * This file is part of the Nette Framework (http://nette.texy.info/)
5 *
6 * @author David Grudl
7 * @copyright Copyright (c) 2004-2007 David Grudl aka -dgx- (http://www.dgx.cz)
8 * @license New BSD License
9 * @version $Revision: 80 $ $Date: 2007-07-04 02:51:27 +0200 (st, 04 VII 2007) $
10 * @category Nette
11 * @package Nette-Html
12 */
13
14
15
16/**
17 * HTML helper
18 *
19 * usage:
20 * $anchor = NHtml::el('a')->href($link)->setText('Nette');
21 * $el->class = 'myclass';
22 * echo $el;
23 *
24 * echo $el->startTag(), $el->endTag();
25 *
26 * Requirements:
27 * - PHP 5.0.0
28 * - NetteException
29 * - optionally NApplication
30 *
31 * @property mixed element's attributes
32 */
33class NHtml
34{
35 /** @var string element's name */
36 private $name;
37
38 /** @var bool is element empty? */
39 private $isEmpty;
40
41 /**
42 * @var mixed element's content
43 * array of NHtml - child nodes
44 * string - content as string (text-node)
45 */
46 public $children;
47
48 /** @var array element's attributes */
49 public $attrs = array();
50
51 /** @var bool use XHTML syntax? */
52 public static $xhtml = TRUE;
53
54 /** @var array empty elements */
55 public static $emptyTags = array('img'=>1,'hr'=>1,'br'=>1,'input'=>1,'meta'=>1,'area'=>1,
56 'base'=>1,'col'=>1,'link'=>1,'param'=>1,'basefont'=>1,'frame'=>1,'isindex'=>1,'wbr'=>1,'embed'=>1);
57
58
59
60 /**
61 * Static factory
62 * @param string element name (or NULL)
63 * @param array element's attributes
64 * @throws NHtmlException
65 * @return NHtml
66 */
67 public static function el($name = NULL, $attrs = NULL)
68 {
69 $el = new self;
70
71 if ($name !== NULL)
72 $el->setName($name);
73
74 if ($attrs !== NULL) {
75 if (!is_array($attrs))
76 throw new NHtmlException('Attributes must be array');
77
78 $el->attrs = $attrs;
79 }
80
81 return $el;
82 }
83
84
85 /**
86 * Static factory for textual element
87 * @param string
88 * @return NHtml
89 */
90 public static function text($text)
91 {
92 $el = new self;
93 $el->setText($text);
94 return $el;
95 }
96
97
98 /**
99 * Changes element's name
100 * @param string
101 * @throws NHtmlException
102 * @return NHtml provides a fluent interface
103 */
104 public function setName($name)
105 {
106 if ($name !== NULL && !is_string($name))
107 throw new NHtmlException("Element's name must string or NULL");
108
109 $this->name = $name;
110 $this->isEmpty = isset(self::$emptyTags[$name]);
111 return $this;
112 }
113
114
115 /**
116 * Returns element's name
117 * @return string
118 */
119 public function getName()
120 {
121 return $this->name;
122 }
123
124
125 /**
126 * Is element empty?
127 * @param optional setter
128 * @return bool
129 */
130 public function isEmpty($value = NULL)
131 {
132 if (is_bool($value)) $this->isEmpty = $value;
133 return $this->isEmpty;
134 }
135
136
137 /**
138 * Sets element's textual content
139 * @param string
140 * @param bool is the string HTML encoded yet?
141 * @throws NHtmlException
142 * @return NHtml provides a fluent interface
143 */
144 public function setText($text, $isHtml = FALSE)
145 {
146 if ($text === NULL)
147 $text = '';
148 elseif (!is_scalar($text))
149 throw new NHtmlException("Textual content must be a scalar");
150
151 if (!$isHtml)
152 $text = str_replace(array('&', '<', '>'), array('&amp;', '&lt;', '&gt;'), $text);
153
154 $this->children = $text;
155 return $this;
156 }
157
158
159
160 /**
161 * Gets element's textual content
162 * @return string
163 */
164 public function getText()
165 {
166 if (is_array($this->children)) return FALSE;
167
168 return $this->children;
169 }
170
171
172
173 /**
174 * Adds new element's child
175 * @param NHtml object
176 * @return NHtml provides a fluent interface
177 */
178 public function addChild(NHtml $child)
179 {
180 $this->children[] = $child;
181 return $this;
182 }
183
184
185 /**
186 * Returns child node
187 * @param mixed index
188 * @return NHtml
189 */
190 public function getChild($index)
191 {
192 if (isset($this->children[$index]))
193 return $this->children[$index];
194
195 return NULL;
196 }
197
198
199 /**
200 * Adds and creates new NHtml child
201 * @param string elements's name
202 * @param string optional textual content
203 * @return NHtml
204 */
205 public function add($name, $text = NULL)
206 {
207 $child = new self;
208 $child->setName($name);
209 if ($text !== NULL) $child->setText($text);
210 return $this->children[] = $child;
211 }
212
213
214 /**
215 * Overloaded setter for element's attribute
216 * @param string property name
217 * @param mixed property value
218 * @return void
219 */
220 public function __set($name, $value)
221 {
222 $this->attrs[$name] = $value;
223 }
224
225
226 /**
227 * Overloaded getter for element's attribute
228 * @param string property name
229 * @return mixed property value
230 */
231 public function &__get($name)
232 {
233 return $this->attrs[$name];
234 }
235
236
237 /**
238 * Overloaded setter for element's attribute
239 * @param string attribute name
240 * @param array value
241 * @return NHtml provides a fluent interface
242 */
243 public function __call($m, $args)
244 {
245 $this->attrs[$m] = $args[0];
246 return $this;
247 }
248
249
250
251 /**
252 * Special setter for element's attribute
253 * @param string path
254 * @param array query
255 * @return NHtml provides a fluent interface
256 */
257 public function href($path, $query = NULL)
258 {
259 // for Nette framework
260 if (class_exists('NApplication', FALSE)) {
261 if (substr($path, 0, 6) === 'event:') {
262 if ($query === NULL) $query = array();
263 $this->attrs['href'] = NApplication::getPage()->constructEvent(substr($path, 6), $query)->constructUrl();
264 return $this;
265
266 } elseif (substr($path, 0, 5) === 'page:') {
267 if ($query === NULL) $query = array();
268 $this->attrs['href'] = NApplication::getPage()->forwardArgs(substr($path, 5), $query)->constructUrl();
269 return $this;
270 }
271 }
272
273 if ($query) {
274 $query = http_build_query($query, NULL, '&');
275 if ($query !== '') $path .= '?' . $query;
276 }
277 $this->attrs['href'] = $path;
278 return $this;
279 }
280
281
282 /**
283 * Renders element's start tag, content and end tag
284 * @return string
285 */
286 public function render()
287 {
288 $s = $this->startTag();
289
290 // empty elements are finished now
291 if ($this->isEmpty) return $s;
292
293 // add content
294 if (is_array($this->children)) {
295 foreach ($this->children as $value)
296 $s .= $value->__toString();
297
298 } else {
299 $s .= $this->children;
300 }
301
302 // add end tag
303 return $s . $this->endTag();
304 }
305
306
307 /**
308 * Returns element's start tag
309 * @return string
310 */
311 public function startTag()
312 {
313 if (!$this->name) return '';
314
315 $s = '<' . $this->name;
316
317 if (is_array($this->attrs)) {
318 foreach ($this->attrs as $key => $value)
319 {
320 // skip NULLs and false boolean attributes
321 if ($value === NULL || $value === FALSE) continue;
322
323 // true boolean attribute
324 if ($value === TRUE) {
325 // in XHTML must use unminimized form
326 if (self::$xhtml) $s .= ' ' . $key . '="' . $key . '"';
327 // in HTML should use minimized form
328 else $s .= ' ' . $key;
329 continue;
330
331 } elseif (is_array($value)) {
332
333 // prepare into temporary array
334 $tmp = NULL;
335 foreach ($value as $k => $v) {
336 // skip NULLs & empty string; composite 'style' vs. 'others'
337 if ($v == NULL) continue;
338
339 if (is_string($k)) $tmp[] = $k . ':' . $v;
340 else $tmp[] = $v;
341 }
342
343 if (!$tmp) continue;
344 $value = implode($key === 'style' ? ';' : ' ', $tmp);
345
346 } elseif ($key === 'href' && substr($value, 0, 7) === 'mailto:') {
347 // email-obfuscate hack
348 $tmp = '';
349 for ($i = 0; $i<strlen($value); $i++) $tmp .= '&#' . ord($value[$i]) . ';'; // WARNING: no utf support
350 $s .= ' href="' . $tmp . '"';
351 continue;
352 }
353
354 // add new attribute
355 $s .= ' ' . $key . '="'
356 . str_replace(array('&', '"', '<', '>'), array('&amp;', '&quot;', '&lt;', '&gt;'), $value)
357 . '"';
358 }
359 }
360
361 // finish start tag
362 if (self::$xhtml && $this->isEmpty) return $s . ' />';
363 return $s . '>';
364 }
365
366
367 public function __toString()
368 {
369 return $this->render();
370 }
371
372
373 /**
374 * Returns element's end tag
375 * @return string
376 */
377 public function endTag()
378 {
379 if ($this->name && !$this->isEmpty)
380 return '</' . $this->name . '>';
381 return '';
382 }
383
384
385 /**
386 * Is element textual node?
387 * @return bool
388 */
389 public function isTextual()
390 {
391 return !$this->isEmpty && is_scalar($this->children);
392 }
393
394
395 /**
396 * Clones all children too
397 */
398 public function __clone()
399 {
400 if (is_array($this->children)) {
401 foreach ($this->children as $key => $value)
402 $this->children[$key] = clone $value;
403 }
404 }
405
406}
Note: See TracBrowser for help on using the repository browser.