source: Dev/branches/cakephp/cake/libs/view/helpers/html.php @ 126

Last change on this file since 126 was 126, checked in by fpvanagthoven, 14 years ago

Cakephp branch.

File size: 26.4 KB
Line 
1<?php
2/**
3 * Html Helper class file.
4 *
5 * Simplifies the construction of HTML elements.
6 *
7 * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
8 * Copyright 2005-2011, Cake Software Foundation, Inc. (http://cakefoundation.org)
9 *
10 * Licensed under The MIT License
11 * Redistributions of files must retain the above copyright notice.
12 *
13 * @copyright     Copyright 2005-2011, Cake Software Foundation, Inc. (http://cakefoundation.org)
14 * @link          http://cakephp.org CakePHP(tm) Project
15 * @package       cake
16 * @subpackage    cake.cake.libs.view.helpers
17 * @since         CakePHP(tm) v 0.9.1
18 * @license       MIT License (http://www.opensource.org/licenses/mit-license.php)
19 */
20/**
21 * Html Helper class for easy use of HTML widgets.
22 *
23 * HtmlHelper encloses all methods needed while working with HTML pages.
24 *
25 * @package       cake
26 * @subpackage    cake.cake.libs.view.helpers
27 * @link http://book.cakephp.org/view/1434/HTML
28 */
29class HtmlHelper extends AppHelper {
30/**
31 * html tags used by this helper.
32 *
33 * @var array
34 * @access public
35 */
36        var $tags = array(
37                'meta' => '<meta%s/>',
38                'metalink' => '<link href="%s"%s/>',
39                'link' => '<a href="%s"%s>%s</a>',
40                'mailto' => '<a href="mailto:%s" %s>%s</a>',
41                'form' => '<form %s>',
42                'formend' => '</form>',
43                'input' => '<input name="%s" %s/>',
44                'textarea' => '<textarea name="%s" %s>%s</textarea>',
45                'hidden' => '<input type="hidden" name="%s" %s/>',
46                'checkbox' => '<input type="checkbox" name="%s" %s/>',
47                'checkboxmultiple' => '<input type="checkbox" name="%s[]"%s />',
48                'radio' => '<input type="radio" name="%s" id="%s" %s />%s',
49                'selectstart' => '<select name="%s"%s>',
50                'selectmultiplestart' => '<select name="%s[]"%s>',
51                'selectempty' => '<option value=""%s>&nbsp;</option>',
52                'selectoption' => '<option value="%s"%s>%s</option>',
53                'selectend' => '</select>',
54                'optiongroup' => '<optgroup label="%s"%s>',
55                'optiongroupend' => '</optgroup>',
56                'checkboxmultiplestart' => '',
57                'checkboxmultipleend' => '',
58                'password' => '<input type="password" name="%s" %s/>',
59                'file' => '<input type="file" name="%s" %s/>',
60                'file_no_model' => '<input type="file" name="%s" %s/>',
61                'submit' => '<input %s/>',
62                'submitimage' => '<input type="image" src="%s" %s/>',
63                'button' => '<button type="%s"%s>%s</button>',
64                'image' => '<img src="%s" %s/>',
65                'tableheader' => '<th%s>%s</th>',
66                'tableheaderrow' => '<tr%s>%s</tr>',
67                'tablecell' => '<td%s>%s</td>',
68                'tablerow' => '<tr%s>%s</tr>',
69                'block' => '<div%s>%s</div>',
70                'blockstart' => '<div%s>',
71                'blockend' => '</div>',
72                'tag' => '<%s%s>%s</%s>',
73                'tagstart' => '<%s%s>',
74                'tagend' => '</%s>',
75                'para' => '<p%s>%s</p>',
76                'parastart' => '<p%s>',
77                'label' => '<label for="%s"%s>%s</label>',
78                'fieldset' => '<fieldset%s>%s</fieldset>',
79                'fieldsetstart' => '<fieldset><legend>%s</legend>',
80                'fieldsetend' => '</fieldset>',
81                'legend' => '<legend>%s</legend>',
82                'css' => '<link rel="%s" type="text/css" href="%s" %s/>',
83                'style' => '<style type="text/css"%s>%s</style>',
84                'charset' => '<meta http-equiv="Content-Type" content="text/html; charset=%s" />',
85                'ul' => '<ul%s>%s</ul>',
86                'ol' => '<ol%s>%s</ol>',
87                'li' => '<li%s>%s</li>',
88                'error' => '<div%s>%s</div>',
89                'javascriptblock' => '<script type="text/javascript"%s>%s</script>',
90                'javascriptstart' => '<script type="text/javascript">',
91                'javascriptlink' => '<script type="text/javascript" src="%s"%s></script>',
92                'javascriptend' => '</script>'
93        );
94
95/**
96 * Breadcrumbs.
97 *
98 * @var array
99 * @access protected
100 */
101        var $_crumbs = array();
102
103/**
104 * Names of script files that have been included once
105 *
106 * @var array
107 * @access private
108 */
109        var $__includedScripts = array();
110/**
111 * Options for the currently opened script block buffer if any.
112 *
113 * @var array
114 * @access protected
115 */
116        var $_scriptBlockOptions = array();
117/**
118 * Document type definitions
119 *
120 * @var array
121 * @access private
122 */
123        var $__docTypes = array(
124                'html4-strict'  => '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">',
125                'html4-trans'  => '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">',
126                'html4-frame'  => '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">',
127                'xhtml-strict' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">',
128                'xhtml-trans' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">',
129                'xhtml-frame' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">',
130                'xhtml11' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">'
131        );
132
133/**
134 * Adds a link to the breadcrumbs array.
135 *
136 * @param string $name Text for link
137 * @param string $link URL for link (if empty it won't be a link)
138 * @param mixed $options Link attributes e.g. array('id'=>'selected')
139 * @return void
140 * @see HtmlHelper::link() for details on $options that can be used.
141 * @access public
142 */
143        function addCrumb($name, $link = null, $options = null) {
144                $this->_crumbs[] = array($name, $link, $options);
145        }
146
147/**
148 * Returns a doctype string.
149 *
150 * Possible doctypes:
151 *
152 *  - html4-strict:  HTML4 Strict.
153 *  - html4-trans:  HTML4 Transitional.
154 *  - html4-frame:  HTML4 Frameset.
155 *  - xhtml-strict: XHTML1 Strict.
156 *  - xhtml-trans: XHTML1 Transitional.
157 *  - xhtml-frame: XHTML1 Frameset.
158 *  - xhtml11: XHTML1.1.
159 *
160 * @param string $type Doctype to use.
161 * @return string Doctype string
162 * @access public
163 * @link http://book.cakephp.org/view/1439/docType
164 */
165        function docType($type = 'xhtml-strict') {
166                if (isset($this->__docTypes[$type])) {
167                        return $this->__docTypes[$type];
168                }
169                return null;
170        }
171
172/**
173 * Creates a link to an external resource and handles basic meta tags
174 *
175 * ### Options
176 *
177 * - `inline` Whether or not the link element should be output inline, or in scripts_for_layout.
178 *
179 * @param string $type The title of the external resource
180 * @param mixed $url The address of the external resource or string for content attribute
181 * @param array $options Other attributes for the generated tag. If the type attribute is html,
182 *    rss, atom, or icon, the mime-type is returned.
183 * @return string A completed `<link />` element.
184 * @access public
185 * @link http://book.cakephp.org/view/1438/meta
186 */
187        function meta($type, $url = null, $options = array()) {
188                $inline = isset($options['inline']) ? $options['inline'] : true;
189                unset($options['inline']);
190
191                if (!is_array($type)) {
192                        $types = array(
193                                'rss'   => array('type' => 'application/rss+xml', 'rel' => 'alternate', 'title' => $type, 'link' => $url),
194                                'atom'  => array('type' => 'application/atom+xml', 'title' => $type, 'link' => $url),
195                                'icon'  => array('type' => 'image/x-icon', 'rel' => 'icon', 'link' => $url),
196                                'keywords' => array('name' => 'keywords', 'content' => $url),
197                                'description' => array('name' => 'description', 'content' => $url),
198                        );
199
200                        if ($type === 'icon' && $url === null) {
201                                $types['icon']['link'] = $this->webroot('favicon.ico');
202                        }
203
204                        if (isset($types[$type])) {
205                                $type = $types[$type];
206                        } elseif (!isset($options['type']) && $url !== null) {
207                                if (is_array($url) && isset($url['ext'])) {
208                                        $type = $types[$url['ext']];
209                                } else {
210                                        $type = $types['rss'];
211                                }
212                        } elseif (isset($options['type']) && isset($types[$options['type']])) {
213                                $type = $types[$options['type']];
214                                unset($options['type']);
215                        } else {
216                                $type = array();
217                        }
218                } elseif ($url !== null) {
219                        $inline = $url;
220                }
221                $options = array_merge($type, $options);
222                $out = null;
223
224                if (isset($options['link'])) {
225                        if (isset($options['rel']) && $options['rel'] === 'icon') {
226                                $out = sprintf($this->tags['metalink'], $options['link'], $this->_parseAttributes($options, array('link'), ' ', ' '));
227                                $options['rel'] = 'shortcut icon';
228                        } else {
229                                $options['link'] = $this->url($options['link'], true);
230                        }
231                        $out .= sprintf($this->tags['metalink'], $options['link'], $this->_parseAttributes($options, array('link'), ' ', ' '));
232                } else {
233                        $out = sprintf($this->tags['meta'], $this->_parseAttributes($options, array('type'), ' ', ' '));
234                }
235
236                if ($inline) {
237                        return $out;
238                } else {
239                        $view =& ClassRegistry::getObject('view');
240                        $view->addScript($out);
241                }
242        }
243
244/**
245 * Returns a charset META-tag.
246 *
247 * @param string $charset The character set to be used in the meta tag. If empty,
248 *  The App.encoding value will be used. Example: "utf-8".
249 * @return string A meta tag containing the specified character set.
250 * @access public
251 * @link http://book.cakephp.org/view/1436/charset
252 */
253        function charset($charset = null) {
254                if (empty($charset)) {
255                        $charset = strtolower(Configure::read('App.encoding'));
256                }
257                return sprintf($this->tags['charset'], (!empty($charset) ? $charset : 'utf-8'));
258        }
259
260/**
261 * Creates an HTML link.
262 *
263 * If $url starts with "http://" this is treated as an external link. Else,
264 * it is treated as a path to controller/action and parsed with the
265 * HtmlHelper::url() method.
266 *
267 * If the $url is empty, $title is used instead.
268 *
269 * ### Options
270 *
271 * - `escape` Set to false to disable escaping of title and attributes.
272 *
273 * @param string $title The content to be wrapped by <a> tags.
274 * @param mixed $url Cake-relative URL or array of URL parameters, or external URL (starts with http://)
275 * @param array $options Array of HTML attributes.
276 * @param string $confirmMessage JavaScript confirmation message.
277 * @return string An `<a />` element.
278 * @access public
279 * @link http://book.cakephp.org/view/1442/link
280 */
281        function link($title, $url = null, $options = array(), $confirmMessage = false) {
282                $escapeTitle = true;
283                if ($url !== null) {
284                        $url = $this->url($url);
285                } else {
286                        $url = $this->url($title);
287                        $title = $url;
288                        $escapeTitle = false;
289                }
290
291                if (isset($options['escape'])) {
292                        $escapeTitle = $options['escape'];
293                }
294
295                if ($escapeTitle === true) {
296                        $title = h($title);
297                } elseif (is_string($escapeTitle)) {
298                        $title = htmlentities($title, ENT_QUOTES, $escapeTitle);
299                }
300
301                if (!empty($options['confirm'])) {
302                        $confirmMessage = $options['confirm'];
303                        unset($options['confirm']);
304                }
305                if ($confirmMessage) {
306                        $confirmMessage = str_replace("'", "\'", $confirmMessage);
307                        $confirmMessage = str_replace('"', '\"', $confirmMessage);
308                        $options['onclick'] = "return confirm('{$confirmMessage}');";
309                } elseif (isset($options['default']) && $options['default'] == false) {
310                        if (isset($options['onclick'])) {
311                                $options['onclick'] .= ' event.returnValue = false; return false;';
312                        } else {
313                                $options['onclick'] = 'event.returnValue = false; return false;';
314                        }
315                        unset($options['default']);
316                }
317                return sprintf($this->tags['link'], $url, $this->_parseAttributes($options), $title);
318        }
319
320/**
321 * Creates a link element for CSS stylesheets.
322 *
323 * ### Options
324 *
325 * - `inline` If set to false, the generated tag appears in the head tag of the layout. Defaults to true
326 *
327 * @param mixed $path The name of a CSS style sheet or an array containing names of
328 *   CSS stylesheets. If `$path` is prefixed with '/', the path will be relative to the webroot
329 *   of your application. Otherwise, the path will be relative to your CSS path, usually webroot/css.
330 * @param string $rel Rel attribute. Defaults to "stylesheet". If equal to 'import' the stylesheet will be imported.
331 * @param array $options Array of HTML attributes.
332 * @return string CSS <link /> or <style /> tag, depending on the type of link.
333 * @access public
334 * @link http://book.cakephp.org/view/1437/css
335 */
336        function css($path, $rel = null, $options = array()) {
337                $options += array('inline' => true);
338                if (is_array($path)) {
339                        $out = '';
340                        foreach ($path as $i) {
341                                $out .= "\n\t" . $this->css($i, $rel, $options);
342                        }
343                        if ($options['inline'])  {
344                                return $out . "\n";
345                        }
346                        return;
347                }
348
349                if (strpos($path, '://') !== false) {
350                        $url = $path;
351                } else {
352                        if ($path[0] !== '/') {
353                                $path = CSS_URL . $path;
354                        }
355
356                        if (strpos($path, '?') === false) {
357                                if (substr($path, -4) !== '.css') {
358                                        $path .= '.css';
359                                }
360                        }
361                        $url = $this->assetTimestamp($this->webroot($path));
362
363                        if (Configure::read('Asset.filter.css')) {
364                                $pos = strpos($url, CSS_URL);
365                                if ($pos !== false) {
366                                        $url = substr($url, 0, $pos) . 'ccss/' . substr($url, $pos + strlen(CSS_URL));
367                                }
368                        }
369                }
370
371                if ($rel == 'import') {
372                        $out = sprintf($this->tags['style'], $this->_parseAttributes($options, array('inline'), '', ' '), '@import url(' . $url . ');');
373                } else {
374                        if ($rel == null) {
375                                $rel = 'stylesheet';
376                        }
377                        $out = sprintf($this->tags['css'], $rel, $url, $this->_parseAttributes($options, array('inline'), '', ' '));
378                }
379
380                if ($options['inline']) {
381                        return $out;
382                } else {
383                        $view =& ClassRegistry::getObject('view');
384                        $view->addScript($out);
385                }
386        }
387
388/**
389 * Returns one or many `<script>` tags depending on the number of scripts given.
390 *
391 * If the filename is prefixed with "/", the path will be relative to the base path of your
392 * application.  Otherwise, the path will be relative to your JavaScript path, usually webroot/js.
393 *
394 * Can include one or many Javascript files.
395 *
396 * ### Options
397 *
398 * - `inline` - Whether script should be output inline or into scripts_for_layout.
399 * - `once` - Whether or not the script should be checked for uniqueness. If true scripts will only be
400 *   included once, use false to allow the same script to be included more than once per request.
401 *
402 * @param mixed $url String or array of javascript files to include
403 * @param mixed $options Array of options, and html attributes see above. If boolean sets $options['inline'] = value
404 * @return mixed String of `<script />` tags or null if $inline is false or if $once is true and the file has been
405 *   included before.
406 * @access public
407 * @link http://book.cakephp.org/view/1589/script
408 */
409        function script($url, $options = array()) {
410                if (is_bool($options)) {
411                        list($inline, $options) = array($options, array());
412                        $options['inline'] = $inline;
413                }
414                $options = array_merge(array('inline' => true, 'once' => true), $options);
415                if (is_array($url)) {
416                        $out = '';
417                        foreach ($url as $i) {
418                                $out .= "\n\t" . $this->script($i, $options);
419                        }
420                        if ($options['inline'])  {
421                                return $out . "\n";
422                        }
423                        return null;
424                }
425                if ($options['once'] && isset($this->__includedScripts[$url])) {
426                        return null;
427                }
428                $this->__includedScripts[$url] = true;
429
430                if (strpos($url, '://') === false) {
431                        if ($url[0] !== '/') {
432                                $url = JS_URL . $url;
433                        }
434                        if (strpos($url, '?') === false && substr($url, -3) !== '.js') {
435                                $url .= '.js';
436                        }
437                        $url = $this->assetTimestamp($this->webroot($url));
438
439                        if (Configure::read('Asset.filter.js')) {
440                                $url = str_replace(JS_URL, 'cjs/', $url);
441                        }
442                }
443                $attributes = $this->_parseAttributes($options, array('inline', 'once'), ' ');
444                $out = sprintf($this->tags['javascriptlink'], $url, $attributes);
445
446                if ($options['inline']) {
447                        return $out;
448                } else {
449                        $view =& ClassRegistry::getObject('view');
450                        $view->addScript($out);
451                }
452        }
453
454/**
455 * Wrap $script in a script tag.
456 *
457 * ### Options
458 *
459 * - `safe` (boolean) Whether or not the $script should be wrapped in <![CDATA[ ]]>
460 * - `inline` (boolean) Whether or not the $script should be added to $scripts_for_layout or output inline
461 *
462 * @param string $script The script to wrap
463 * @param array $options The options to use.
464 * @return mixed string or null depending on the value of `$options['inline']`
465 * @access public
466 * @link http://book.cakephp.org/view/1604/scriptBlock
467 */
468        function scriptBlock($script, $options = array()) {
469                $options += array('safe' => true, 'inline' => true);
470                if ($options['safe']) {
471                        $script  = "\n" . '//<![CDATA[' . "\n" . $script . "\n" . '//]]>' . "\n";
472                }
473                $inline = $options['inline'];
474                unset($options['inline'], $options['safe']);
475                $attributes = $this->_parseAttributes($options, ' ', ' ');
476                if ($inline) {
477                        return sprintf($this->tags['javascriptblock'], $attributes, $script);
478                } else {
479                        $view =& ClassRegistry::getObject('view');
480                        $view->addScript(sprintf($this->tags['javascriptblock'], $attributes, $script));
481                        return null;
482                }
483        }
484
485/**
486 * Begin a script block that captures output until HtmlHelper::scriptEnd()
487 * is called. This capturing block will capture all output between the methods
488 * and create a scriptBlock from it.
489 *
490 * ### Options
491 *
492 * - `safe` Whether the code block should contain a CDATA
493 * - `inline` Should the generated script tag be output inline or in `$scripts_for_layout`
494 *
495 * @param array $options Options for the code block.
496 * @return void
497 * @access public
498 * @link http://book.cakephp.org/view/1605/scriptStart
499 */
500        function scriptStart($options = array()) {
501                $options += array('safe' => true, 'inline' => true);
502                $this->_scriptBlockOptions = $options;
503                ob_start();
504                return null;
505        }
506
507/**
508 * End a Buffered section of Javascript capturing.
509 * Generates a script tag inline or in `$scripts_for_layout` depending on the settings
510 * used when the scriptBlock was started
511 *
512 * @return mixed depending on the settings of scriptStart() either a script tag or null
513 * @access public
514 * @link http://book.cakephp.org/view/1606/scriptEnd
515 */
516        function scriptEnd() {
517                $buffer = ob_get_clean();
518                $options = $this->_scriptBlockOptions;
519                $this->_scriptBlockOptions = array();
520                return $this->scriptBlock($buffer, $options);
521        }
522
523/**
524 * Builds CSS style data from an array of CSS properties
525 *
526 * ### Usage:
527 *
528 * {{{
529 * echo $html->style(array('margin' => '10px', 'padding' => '10px'), true);
530 *
531 * // creates
532 * 'margin:10px;padding:10px;'
533 * }}}
534 *
535 * @param array $data Style data array, keys will be used as property names, values as property values.
536 * @param boolean $oneline Whether or not the style block should be displayed on one line.
537 * @return string CSS styling data
538 * @access public
539 * @link http://book.cakephp.org/view/1440/style
540 */
541        function style($data, $oneline = true) {
542                if (!is_array($data)) {
543                        return $data;
544                }
545                $out = array();
546                foreach ($data as $key=> $value) {
547                        $out[] = $key.':'.$value.';';
548                }
549                if ($oneline) {
550                        return join(' ', $out);
551                }
552                return implode("\n", $out);
553        }
554
555/**
556 * Returns the breadcrumb trail as a sequence of &raquo;-separated links.
557 *
558 * @param string $separator Text to separate crumbs.
559 * @param string $startText This will be the first crumb, if false it defaults to first crumb in array
560 * @return string Composed bread crumbs
561 * @access public
562 */
563        function getCrumbs($separator = '&raquo;', $startText = false) {
564                if (!empty($this->_crumbs)) {
565                        $out = array();
566                        if ($startText) {
567                                $out[] = $this->link($startText, '/');
568                        }
569
570                        foreach ($this->_crumbs as $crumb) {
571                                if (!empty($crumb[1])) {
572                                        $out[] = $this->link($crumb[0], $crumb[1], $crumb[2]);
573                                } else {
574                                        $out[] = $crumb[0];
575                                }
576                        }
577                        return join($separator, $out);
578                } else {
579                        return null;
580                }
581        }
582
583/**
584 * Creates a formatted IMG element. If `$options['url']` is provided, an image link will be
585 * generated with the link pointed at `$options['url']`.  This method will set an empty
586 * alt attribute if one is not supplied.
587 *
588 * ### Usage
589 *
590 * Create a regular image:
591 *
592 * `echo $html->image('cake_icon.png', array('alt' => 'CakePHP'));`
593 *
594 * Create an image link:
595 *
596 * `echo $html->image('cake_icon.png', array('alt' => 'CakePHP', 'url' => 'http://cakephp.org'));`
597 *
598 * @param string $path Path to the image file, relative to the app/webroot/img/ directory.
599 * @param array $options Array of HTML attributes.
600 * @return string completed img tag
601 * @access public
602 * @link http://book.cakephp.org/view/1441/image
603 */
604        function image($path, $options = array()) {
605                if (is_array($path)) {
606                        $path = $this->url($path);
607                } elseif (strpos($path, '://') === false) {
608                        if ($path[0] !== '/') {
609                                $path = IMAGES_URL . $path;
610                        }
611                        $path = $this->assetTimestamp($this->webroot($path));
612                }
613
614                if (!isset($options['alt'])) {
615                        $options['alt'] = '';
616                }
617
618                $url = false;
619                if (!empty($options['url'])) {
620                        $url = $options['url'];
621                        unset($options['url']);
622                }
623
624                $image = sprintf($this->tags['image'], $path, $this->_parseAttributes($options, null, '', ' '));
625
626                if ($url) {
627                        return sprintf($this->tags['link'], $this->url($url), null, $image);
628                }
629                return $image;
630        }
631
632/**
633 * Returns a row of formatted and named TABLE headers.
634 *
635 * @param array $names Array of tablenames.
636 * @param array $trOptions HTML options for TR elements.
637 * @param array $thOptions HTML options for TH elements.
638 * @return string Completed table headers
639 * @access public
640 * @link http://book.cakephp.org/view/1446/tableHeaders
641 */
642        function tableHeaders($names, $trOptions = null, $thOptions = null) {
643                $out = array();
644                foreach ($names as $arg) {
645                        $out[] = sprintf($this->tags['tableheader'], $this->_parseAttributes($thOptions), $arg);
646                }
647                return sprintf($this->tags['tablerow'], $this->_parseAttributes($trOptions), join(' ', $out));
648        }
649
650/**
651 * Returns a formatted string of table rows (TR's with TD's in them).
652 *
653 * @param array $data Array of table data
654 * @param array $oddTrOptions HTML options for odd TR elements if true useCount is used
655 * @param array $evenTrOptions HTML options for even TR elements
656 * @param bool $useCount adds class "column-$i"
657 * @param bool $continueOddEven If false, will use a non-static $count variable,
658 *    so that the odd/even count is reset to zero just for that call.
659 * @return string Formatted HTML
660 * @access public
661 * @link http://book.cakephp.org/view/1447/tableCells
662 */
663        function tableCells($data, $oddTrOptions = null, $evenTrOptions = null, $useCount = false, $continueOddEven = true) {
664                if (empty($data[0]) || !is_array($data[0])) {
665                        $data = array($data);
666                }
667
668                if ($oddTrOptions === true) {
669                        $useCount = true;
670                        $oddTrOptions = null;
671                }
672
673                if ($evenTrOptions === false) {
674                        $continueOddEven = false;
675                        $evenTrOptions = null;
676                }
677
678                if ($continueOddEven) {
679                        static $count = 0;
680                } else {
681                        $count = 0;
682                }
683
684                foreach ($data as $line) {
685                        $count++;
686                        $cellsOut = array();
687                        $i = 0;
688                        foreach ($line as $cell) {
689                                $cellOptions = array();
690
691                                if (is_array($cell)) {
692                                        $cellOptions = $cell[1];
693                                        $cell = $cell[0];
694                                } elseif ($useCount) {
695                                        $cellOptions['class'] = 'column-' . ++$i;
696                                }
697                                $cellsOut[] = sprintf($this->tags['tablecell'], $this->_parseAttributes($cellOptions), $cell);
698                        }
699                        $options = $this->_parseAttributes($count % 2 ? $oddTrOptions : $evenTrOptions);
700                        $out[] = sprintf($this->tags['tablerow'], $options, implode(' ', $cellsOut));
701                }
702                return implode("\n", $out);
703        }
704
705/**
706 * Returns a formatted block tag, i.e DIV, SPAN, P.
707 *
708 * ### Options
709 *
710 * - `escape` Whether or not the contents should be html_entity escaped.
711 *
712 * @param string $name Tag name.
713 * @param string $text String content that will appear inside the div element.
714 *   If null, only a start tag will be printed
715 * @param array $options Additional HTML attributes of the DIV tag, see above.
716 * @return string The formatted tag element
717 * @access public
718 * @link http://book.cakephp.org/view/1443/tag
719 */
720        function tag($name, $text = null, $options = array()) {
721                if (is_array($options) && isset($options['escape']) && $options['escape']) {
722                        $text = h($text);
723                        unset($options['escape']);
724                }
725                if (!is_array($options)) {
726                        $options = array('class' => $options);
727                }
728                if ($text === null) {
729                        $tag = 'tagstart';
730                } else {
731                        $tag = 'tag';
732                }
733                return sprintf($this->tags[$tag], $name, $this->_parseAttributes($options, null, ' ', ''), $text, $name);
734        }
735
736/**
737 * Returns a formatted DIV tag for HTML FORMs.
738 *
739 * ### Options
740 *
741 * - `escape` Whether or not the contents should be html_entity escaped.
742 *
743 * @param string $class CSS class name of the div element.
744 * @param string $text String content that will appear inside the div element.
745 *   If null, only a start tag will be printed
746 * @param array $options Additional HTML attributes of the DIV tag
747 * @return string The formatted DIV element
748 * @access public
749 * @link http://book.cakephp.org/view/1444/div
750 */
751        function div($class = null, $text = null, $options = array()) {
752                if (!empty($class)) {
753                        $options['class'] = $class;
754                }
755                return $this->tag('div', $text, $options);
756        }
757
758/**
759 * Returns a formatted P tag.
760 *
761 * ### Options
762 *
763 * - `escape` Whether or not the contents should be html_entity escaped.
764 *
765 * @param string $class CSS class name of the p element.
766 * @param string $text String content that will appear inside the p element.
767 * @param array $options Additional HTML attributes of the P tag
768 * @return string The formatted P element
769 * @access public
770 * @link http://book.cakephp.org/view/1445/para
771 */
772        function para($class, $text, $options = array()) {
773                if (isset($options['escape'])) {
774                        $text = h($text);
775                }
776                if ($class != null && !empty($class)) {
777                        $options['class'] = $class;
778                }
779                if ($text === null) {
780                        $tag = 'parastart';
781                } else {
782                        $tag = 'para';
783                }
784                return sprintf($this->tags[$tag], $this->_parseAttributes($options, null, ' ', ''), $text);
785        }
786
787/**
788 * Build a nested list (UL/OL) out of an associative array.
789 *
790 * @param array $list Set of elements to list
791 * @param array $options Additional HTML attributes of the list (ol/ul) tag or if ul/ol use that as tag
792 * @param array $itemOptions Additional HTML attributes of the list item (LI) tag
793 * @param string $tag Type of list tag to use (ol/ul)
794 * @return string The nested list
795 * @access public
796 */
797        function nestedList($list, $options = array(), $itemOptions = array(), $tag = 'ul') {
798                if (is_string($options)) {
799                        $tag = $options;
800                        $options = array();
801                }
802                $items = $this->__nestedListItem($list, $options, $itemOptions, $tag);
803                return sprintf($this->tags[$tag], $this->_parseAttributes($options, null, ' ', ''), $items);
804        }
805
806/**
807 * Internal function to build a nested list (UL/OL) out of an associative array.
808 *
809 * @param array $items Set of elements to list
810 * @param array $options Additional HTML attributes of the list (ol/ul) tag
811 * @param array $itemOptions Additional HTML attributes of the list item (LI) tag
812 * @param string $tag Type of list tag to use (ol/ul)
813 * @return string The nested list element
814 * @access private
815 * @see HtmlHelper::nestedList()
816 */
817        function __nestedListItem($items, $options, $itemOptions, $tag) {
818                $out = '';
819
820                $index = 1;
821                foreach ($items as $key => $item) {
822                        if (is_array($item)) {
823                                $item = $key . $this->nestedList($item, $options, $itemOptions, $tag);
824                        }
825                        if (isset($itemOptions['even']) && $index % 2 == 0) {
826                                $itemOptions['class'] = $itemOptions['even'];
827                        } else if (isset($itemOptions['odd']) && $index % 2 != 0) {
828                                $itemOptions['class'] = $itemOptions['odd'];
829                        }
830                        $out .= sprintf($this->tags['li'], $this->_parseAttributes($itemOptions, array('even', 'odd'), ' ', ''), $item);
831                        $index++;
832                }
833                return $out;
834        }
835}
Note: See TracBrowser for help on using the repository browser.