Overview

Packages

  • Jyxo_Beholder
  • Jyxo_Charset
  • Jyxo_Color
  • Jyxo_Css
  • Jyxo_ErrorHandling
  • Jyxo_FirePhp
  • Jyxo_Gettext
    • Parser
  • Jyxo_Html
  • Jyxo_Input
    • Chain
    • Filter
    • Validator
  • Jyxo_Mail
    • Email
    • Parser
    • Sender
  • Jyxo_Rpc
    • Json
    • Xml
  • Jyxo_Shell
  • Jyxo_SpamFilter
  • Jyxo_Spl
  • Jyxo_String
  • Jyxo_Svn
  • Jyxo_Time
  • Jyxo_Timer
  • Jyxo_Webdav
  • Jyxo_XmlReader
  • PHP

Classes

  • Jyxo_Html
  • Jyxo_HtmlTag
  • Overview
  • Package
  • Class
  • Tree
  • Deprecated
  1: <?php
  2: 
  3: /**
  4:  * Jyxo PHP Library
  5:  *
  6:  * LICENSE
  7:  *
  8:  * This source file is subject to the new BSD license that is bundled
  9:  * with this package in the file license.txt.
 10:  * It is also available through the world-wide-web at this URL:
 11:  * https://github.com/jyxo/php/blob/master/license.txt
 12:  */
 13: 
 14: /**
 15:  * Class for generating (x)HTML source code.
 16:  * Allows creating HTML tags and its attributes.
 17:  *
 18:  * Example:
 19:  * <code>
 20:  * $p = Jyxo_HtmlTag::create('p')->setClass('buttons');
 21:  * </code>
 22: 
 23:  * The magic __call() method ensures attributes settings.
 24:  *
 25:  * <code>
 26:  * $p->render();
 27:  * </code>
 28:  *
 29:  * The render() method creates the HTML output.
 30:  *
 31:  * @category Jyxo
 32:  * @package Jyxo_Html
 33:  * @copyright Copyright (c) 2005-2011 Jyxo, s.r.o.
 34:  * @license https://github.com/jyxo/php/blob/master/license.txt
 35:  * @author Roman Řáha
 36:  * @author Štěpán Svoboda
 37:  */
 38: final class Jyxo_HtmlTag
 39: {
 40:     /**
 41:      * Is XHTML output turned on?
 42:      *
 43:      * @var boolean
 44:      */
 45:     private $xhtml = true;
 46: 
 47:     /**
 48:      * Element name.
 49:      *
 50:      * @var string
 51:      */
 52:     private $tag = '';
 53: 
 54:     /**
 55:      * Is the element self closing?
 56:      *
 57:      * @var boolean
 58:      */
 59:     private $isEmptyElement = false;
 60: 
 61:     /**
 62:      * Element attributes.
 63:      *
 64:      * @var array
 65:      */
 66:     private $attributes = array();
 67: 
 68:     /**
 69:      * Array of child elements.
 70:      *
 71:      * @var array
 72:      */
 73:     private $children = array();
 74: 
 75:     /**
 76:      * Array of elements whose value will not be escaped.
 77:      *
 78:      * @var array
 79:      */
 80:     private $noEncode = array();
 81: 
 82:     /**
 83:      * Renders only the contents, not the opening and closing tag.
 84:      *
 85:      * @var boolean
 86:      */
 87:     private $contentOnly = FALSE;
 88: 
 89:     /**
 90:      * List of element attributes.
 91:      *
 92:      * @var array
 93:      */
 94:     private static $attrs = array(
 95:         'accesskey' => true, 'action' => true, 'alt' => true, 'cellpadding' => true, 'cellspacing' => true, 'checked' => true, 'class' => true,
 96:         'cols' => true, 'disabled' => true, 'for' => true, 'href' => true, 'id' => true, 'label' => true, 'method' => true, 'name' => true, 'onblur' => true,
 97:         'onchange' => true, 'onclick' => true, 'onfocus' => true, 'onkeyup' => true, 'onsubmit' => true, 'readonly' => true, 'rel' => true,
 98:         'rows' => true, 'selected' => true, 'size' => true, 'src' => true, 'style' => true, 'tabindex' => true, 'title' => true, 'type' => true,
 99:         'value' => true, 'width' => true,
100:     );
101: 
102:     /**
103:      * List of self closing elements.
104:      *
105:      * @var array
106:      */
107:     private $emptyElements = array(
108:         'br' => true, 'hr' => true, 'img' => true, 'input' => true, 'meta' => true, 'link' => true
109:     );
110: 
111:     /**
112:      * List of mandatory attributes that will be rendered even if empty.
113:      *
114:      * @var array
115:      */
116:     private $requiredAttrs = array(
117:         'option' => 'value',
118:         'optgroup' => 'label'
119:     );
120: 
121:     /**
122:      * Constructor.
123:      *
124:      * Sets the element name.
125:      *
126:      * @param string $tag
127:      */
128:     private function __construct($tag)
129:     {
130:         $this->tag = (string) $tag;
131:     }
132: 
133:     /**
134:      * Creates an element instance.
135:      *
136:      * @param string $tag HTML element name
137:      * @return Jyxo_HtmlTag
138:      */
139:     public static function create($tag)
140:     {
141:         return new self($tag);
142:     }
143: 
144:     /**
145:      * Returns an element instance from the given source.
146:      * The first and last tag will be used as the opening and closing tag respectively.
147:      * Anything between those tags will be used as contents.
148:      *
149:      * @param string $html HTML source code
150:      * @return Jyxo_HtmlTag
151:      * @throws InvalidArgumentException If an invalid HTML source was given
152:      */
153:     public static function createFromSource($html)
154:     {
155:         if (preg_match('~<(\w+)(\s[^>]*)+>(.*)((<[^>]+>)?[^>]*)$~', $html, $matches)) {
156:             $tag = new self($matches[1]);
157:             if ('' !== $matches[3]) {
158:                 // @todo Maybe some kind of recursion to create a tree of elements
159:                 $tag->setText($matches[3]);
160:             }
161:             if (preg_match_all('/(\w+)\s*=\s*"([^"]+)"/', $matches[2], $submatches, PREG_PATTERN_ORDER)) {
162:                 $attrs = array_combine($submatches[1], $submatches[2]);
163:                 $tag->setAttributes($attrs);
164:             }
165:             return $tag;
166:         }
167:         throw new InvalidArgumentException('Zadaný text neobsahuje validní html');
168:     }
169: 
170:     /**
171:      * Creates and returns the opening tag.
172:      *
173:      * @return string
174:      */
175:     public function open()
176:     {
177:         if (TRUE === $this->contentOnly) {
178:             return '';
179:         }
180:         $this->isEmptyElement = isset($this->emptyElements[$this->tag]);
181:         $buff = '';
182:         foreach ($this->attributes as $name => $value) {
183:             if (isset(self::$attrs[$name])) {
184:                 if (($name === 'selected' || $name === 'checked' || $name === 'readonly' || $name === 'disabled') && $value) {
185:                     $value = $name;
186:                 }
187:                 $notEmpty = $value !== null && $value !== '' && $value !== false;
188:                 if ($this->isRequiredAttr($this->tag, $name) || $notEmpty) {
189:                     // For not empty attributes and the value attribute by the <option> tag
190:                     if (!isset($this->noEncode[$name])) {
191:                         $value = Jyxo_String::escape($value);
192:                     }
193:                     $attrString = sprintf(' %s="%s"', $name, $value);
194:                     if ($name === 'value') {
195:                         if ($this->tag === 'textarea') {
196:                             $buff .= '';
197:                         } else {
198:                             $buff .= $attrString;
199:                         }
200:                     } else {
201:                         $buff .= $attrString;
202:                     }
203:                 }
204:             }
205:         }
206:         $buff = '<' . $this->tag . $buff . ($this->xhtml ? $this->isEmptyElement ? ' />' : '>' : '>');
207:         return $buff;
208:     }
209: 
210:     /**
211:      * Creates and returns element's contents.
212:      *
213:      * @return string
214:      */
215:     public function content()
216:     {
217:         $buff = '';
218:         if (!$this->isEmptyElement) {
219: 
220:             $hasValue = isset($this->attributes['value']);
221:             $hasText = isset($this->attributes['text']);
222:             if ($hasValue || $hasText) {
223:                 $text = $hasText ? $this->attributes['text'] : $this->attributes['value'];
224:                 $noEncode = isset($this->noEncode['value']) || isset($this->noEncode['text']);
225:                 // <script> contents are not escaped
226:                 $noEncode = 'script' === $this->tag ? true : $noEncode;
227:                 $buff .= $noEncode ? $text : Jyxo_String::escape($text);
228:             }
229:         }
230:         if (!$this->isEmptyElement && !empty($this->children)) {
231:             foreach ($this->children as $element) {
232:                 $buff .= $element->render();
233:             }
234:         }
235:         return $buff;
236:     }
237: 
238:     /**
239:      * Creates and returns the closing tag.
240:      *
241:      * @return string
242:      */
243:     public function close()
244:     {
245:         if (true === $this->contentOnly) {
246:             return '';
247:         }
248:         $close = '</' . $this->tag . '>';
249:         if ($this->xhtml) {
250:             $buff = !$this->isEmptyElement ? $close : '';
251:         } else {
252:             $buff = $close;
253:         }
254:         $buff .= "\n";
255:         return $buff;
256:     }
257: 
258:     /**
259:      * Renders the element.
260:      *
261:      * @return string
262:      */
263:     public function render()
264:     {
265:         return $this->open() . $this->content() . $this->close();
266:     }
267: 
268:     /**
269:      * Adds a child element.
270:      *
271:      * @param Jyxo_HtmlTag $element Child element to be added
272:      * @return Jyxo_HtmlTag
273:      */
274:     public function addChild(Jyxo_HtmlTag $element)
275:     {
276:         $this->children[] = $element;
277:         return $this;
278:     }
279: 
280:     /**
281:      * Adds multiple child elements.
282:      *
283:      * @param array $elements Array of child elements
284:      * @return Jyxo_HtmlTag
285:      */
286:     public function addChildren(array $elements)
287:     {
288:         foreach ($elements as $element) {
289:             $this->addChild($element);
290:         }
291:         return $this;
292:     }
293: 
294:     /**
295:      * Imports attributes from the given array.
296:      *
297:      * @param array $attributes Associative array of attributes and their values
298:      * @return Jyxo_HtmlTag
299:      */
300:     public function setAttributes(array $attributes)
301:     {
302:         foreach ($attributes as $name => $value) {
303:             $this->attributes[strtolower($name)] = $value;
304:         }
305:         return $this;
306:     }
307: 
308:     /**
309:      * Sets an attribute to not be espaced on output.
310:      *
311:      * @param string $attribute Attribute name
312:      * @return Jyxo_HtmlTag
313:      */
314:     public function setNoEncode($attribute)
315:     {
316:         $this->noEncode[$attribute] = true;
317: 
318:         return $this;
319:     }
320: 
321:     /**
322:      * Sets if only the contents should be rendered.
323:      *
324:      * @param boolean $contentOnly Should only the contents be rendered
325:      * @return Jyxo_HtmlTag
326:      */
327:     public function setContentOnly($contentOnly)
328:     {
329:         $this->contentOnly = (bool) $contentOnly;
330:         return $this;
331:     }
332: 
333:     /**
334:      * Renders the HTML element.
335:      *
336:      * @return string
337:      */
338:     public function __toString()
339:     {
340:         return $this->render();
341:     }
342: 
343:     /**
344:      * Sets or returns the attribute.
345:      *
346:      * @param string $method Method name
347:      * @param array $args Method attributes
348:      * @return mixed string|Jyxo_HtmlTag
349:      */
350:     public function __call($method, $args)
351:     {
352:         $type = $method[0] === 's' ? 'set' : 'get';
353:         if ($type === 'set') {
354:             $this->attributes[strtolower(substr($method, 3))] = $args[0];
355:             return $this;
356:         } else {
357:             if (isset($this->attributes[strtolower(substr($method, 3))])) {
358:                 return $this->attributes[strtolower(substr($method, 3))];
359:             }
360:             return '';
361:         }
362:     }
363: 
364:     /**
365:      * Returns an attribute value.
366:      *
367:      * @param string $name Attribute name
368:      * @return mixed string|null
369:      */
370:     public function __get($name)
371:     {
372:         // An empty attribute is always null
373:         return isset($this->attributes[$name]) ? $this->attributes[$name] : null;
374:     }
375: 
376:     /**
377:      * Returns if the given attribute is mandatory.
378:      *
379:      * @param string $tag HTML tag name
380:      * @param string $attr Attribute name
381:      * @return boolean
382:      */
383:     private function isRequiredAttr($tag, $attr)
384:     {
385:         if (isset($this->requiredAttrs[$tag])) {
386:             if (is_array($this->requiredAttrs[$tag])) {
387:                 return in_array($attr, $this->requiredAttrs[$tag]);
388:             }
389:             return $attr == $this->requiredAttrs[$tag];
390:         }
391:         return false;
392:     }
393: }
394: 
Jyxo PHP Library API documentation generated by ApiGen 2.3.0