html.php

Go to the documentation of this file.
00001 <?php
00002 /* SVN FILE: $Id: html_8php-source.html 580 2008-07-01 14:45:49Z gwoo $ */
00003 /**
00004  * Html Helper class file.
00005  *
00006  * Simplifies the construction of HTML elements.
00007  *
00008  * CakePHP(tm) :  Rapid Development Framework <http://www.cakephp.org/>
00009  * Copyright 2005-2008, Cake Software Foundation, Inc.
00010  *                              1785 E. Sahara Avenue, Suite 490-204
00011  *                              Las Vegas, Nevada 89104
00012  *
00013  * Licensed under The MIT License
00014  * Redistributions of files must retain the above copyright notice.
00015  *
00016  * @filesource
00017  * @copyright       Copyright 2005-2008, Cake Software Foundation, Inc.
00018  * @link                http://www.cakefoundation.org/projects/info/cakephp CakePHP(tm) Project
00019  * @package         cake
00020  * @subpackage      cake.cake.libs.view.helpers
00021  * @since           CakePHP(tm) v 0.9.1
00022  * @version         $Revision: 580 $
00023  * @modifiedby      $LastChangedBy: gwoo $
00024  * @lastmodified    $Date: 2008-07-01 09:45:49 -0500 (Tue, 01 Jul 2008) $
00025  * @license         http://www.opensource.org/licenses/mit-license.php The MIT License
00026  */
00027 /**
00028  * Html Helper class for easy use of HTML widgets.
00029  *
00030  * HtmlHelper encloses all methods needed while working with HTML pages.
00031  *
00032  * @package     cake
00033  * @subpackage  cake.cake.libs.view.helpers
00034  */
00035 class HtmlHelper extends AppHelper {
00036 /*************************************************************************
00037  * Public variables
00038  *************************************************************************/
00039 /**#@+
00040  * @access public
00041  */
00042 /**
00043  * html tags used by this helper.
00044  *
00045  * @var array
00046  */
00047     var $tags = array(
00048         'meta' => '<meta%s/>',
00049         'metalink' => '<link href="%s"%s/>',
00050         'link' => '<a href="%s"%s>%s</a>',
00051         'mailto' => '<a href="mailto:%s" %s>%s</a>',
00052         'form' => '<form %s>',
00053         'formend' => '</form>',
00054         'input' => '<input name="%s" %s/>',
00055         'textarea' => '<textarea name="%s" %s>%s</textarea>',
00056         'hidden' => '<input type="hidden" name="%s" %s/>',
00057         'checkbox' => '<input type="checkbox" name="%s" %s/>',
00058         'checkboxmultiple' => '<input type="checkbox" name="%s[]"%s />',
00059         'radio' => '<input type="radio" name="%s" id="%s" %s />%s',
00060         'selectstart' => '<select name="%s"%s>',
00061         'selectmultiplestart' => '<select name="%s[]"%s>',
00062         'selectempty' => '<option value=""%s>&nbsp;</option>',
00063         'selectoption' => '<option value="%s"%s>%s</option>',
00064         'selectend' => '</select>',
00065         'optiongroup' => '<optgroup label="%s"%s>',
00066         'optiongroupend' => '</optgroup>',
00067         'checkboxmultiplestart' => '',
00068         'checkboxmultipleend' => '',
00069         'password' => '<input type="password" name="%s" %s/>',
00070         'file' => '<input type="file" name="%s" %s/>',
00071         'file_no_model' => '<input type="file" name="%s" %s/>',
00072         'submit' => '<input type="submit" %s/>',
00073         'submitimage' => '<input type="image" src="%s" %s/>',
00074         'button' => '<input type="%s" %s/>',
00075         'image' => '<img src="%s" %s/>',
00076         'tableheader' => '<th%s>%s</th>',
00077         'tableheaderrow' => '<tr%s>%s</tr>',
00078         'tablecell' => '<td%s>%s</td>',
00079         'tablerow' => '<tr%s>%s</tr>',
00080         'block' => '<div%s>%s</div>',
00081         'blockstart' => '<div%s>',
00082         'blockend' => '</div>',
00083         'tag' => '<%s%s>%s</%s>',
00084         'tagstart' => '<%s%s>',
00085         'tagend' => '</%s>',
00086         'para' => '<p%s>%s</p>',
00087         'parastart' => '<p%s>',
00088         'label' => '<label for="%s"%s>%s</label>',
00089         'fieldset' => '<fieldset%s>%s</fieldset>',
00090         'fieldsetstart' => '<fieldset><legend>%s</legend>',
00091         'fieldsetend' => '</fieldset>',
00092         'legend' => '<legend>%s</legend>',
00093         'css' => '<link rel="%s" type="text/css" href="%s" %s/>',
00094         'style' => '<style type="text/css"%s>%s</style>',
00095         'charset' => '<meta http-equiv="Content-Type" content="text/html; charset=%s" />',
00096         'ul' => '<ul%s>%s</ul>',
00097         'ol' => '<ol%s>%s</ol>',
00098         'li' => '<li%s>%s</li>',
00099         'error' => '<div%s>%s</div>'
00100     );
00101 /**
00102  * Base URL
00103  *
00104  * @var string
00105  */
00106     var $base = null;
00107 /**
00108  * URL to current action.
00109  *
00110  * @var string
00111  */
00112     var $here = null;
00113 /**
00114  * Parameter array.
00115  *
00116  * @var array
00117  */
00118     var $params = array();
00119 /**
00120  * Current action.
00121  *
00122  * @var string
00123  */
00124     var $action = null;
00125 /**
00126  * Enter description here...
00127  *
00128  * @var array
00129  */
00130     var $data = null;
00131 /**#@-*/
00132 /*************************************************************************
00133  * Private variables
00134  *************************************************************************/
00135 /**#@+
00136  * @access private
00137  */
00138 /**
00139  * Breadcrumbs.
00140  *
00141  * @var array
00142  * @access private
00143  */
00144     var $_crumbs = array();
00145 /**
00146  * Document type definitions
00147  *
00148  * @var array
00149  * @access private
00150  */
00151     var $__docTypes = array(
00152         'html4-strict'  => '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">',
00153         'html4-trans'  => '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">',
00154         'html4-frame'  => '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">',
00155         'xhtml-strict' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">',
00156         'xhtml-trans' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">',
00157         'xhtml-frame' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">',
00158         'xhtml11' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">'
00159     );
00160 /**
00161  * Adds a link to the breadcrumbs array.
00162  *
00163  * @param string $name Text for link
00164  * @param string $link URL for link (if empty it won't be a link)
00165  * @param mixed $options Link attributes e.g. array('id'=>'selected')
00166  */
00167     function addCrumb($name, $link = null, $options = null) {
00168         $this->_crumbs[] = array($name, $link, $options);
00169     }
00170 /**
00171  * Returns a doctype string.
00172  *
00173  * Possible doctypes:
00174  *   + html4-strict:  HTML4 Strict.
00175  *   + html4-trans:  HTML4 Transitional.
00176  *   + html4-frame:  HTML4 Frameset.
00177  *   + xhtml-strict: XHTML1 Strict.
00178  *   + xhtml-trans: XHTML1 Transitional.
00179  *   + xhtml-frame: XHTML1 Frameset.
00180  *   + xhtml11: XHTML1.1.
00181  *
00182  * @param  string $type Doctype to use.
00183  * @return string Doctype.
00184  */
00185     function docType($type = 'xhtml-strict') {
00186         if (isset($this->__docTypes[$type])) {
00187             return $this->output($this->__docTypes[$type]);
00188         }
00189         return null;
00190     }
00191 /**
00192  * Creates a link to an external resource and handles basic meta tags
00193  *
00194  * @param  string  $title The title of the external resource
00195  * @param  mixed   $url   The address of the external resource or string for content attribute
00196  * @param  array   $attributes Other attributes for the generated tag. If the type attribute is html, rss, atom, or icon, the mime-type is returned.
00197  * @param  boolean $inline If set to false, the generated tag appears in the head tag of the layout.
00198  * @return string
00199  */
00200     function meta($type, $url = null, $attributes = array(), $inline = true) {
00201         if (!is_array($type)) {
00202             $types = array(
00203                 'rss'   => array('type' => 'application/rss+xml', 'rel' => 'alternate', 'title' => $type, 'link' => $url),
00204                 'atom'  => array('type' => 'application/atom+xml', 'title' => $type, 'link' => $url),
00205                 'icon'  => array('type' => 'image/x-icon', 'rel' => 'icon', 'link' => $url),
00206                 'keywords' => array('name' => 'keywords', 'content' => $url),
00207                 'description' => array('name' => 'description', 'content' => $url),
00208             );
00209 
00210             if ($type === 'icon' && $url === null) {
00211                 $types['icon']['link'] = $this->webroot('favicon.ico');
00212             }
00213 
00214             if (isset($types[$type])) {
00215                 $type = $types[$type];
00216             } elseif (!isset($attributes['type']) && $url !== null) {
00217                 if (is_array($url) && isset($url['ext'])) {
00218                     $type = $types[$url['ext']];
00219                 } else {
00220                     $type = $types['rss'];
00221                 }
00222             } elseif (isset($attributes['type']) && isset($types[$attributes['type']])) {
00223                 $type = $types[$attributes['type']];
00224                 unset($attributes['type']);
00225             } else {
00226                 $type = array();
00227             }
00228         } elseif ($url !== null) {
00229             $inline = $url;
00230         }
00231         $attributes = array_merge($type, $attributes);
00232         $out = null;
00233 
00234         if (isset($attributes['link'])) {
00235             if (isset($attributes['rel']) && $attributes['rel'] === 'icon') {
00236                 $out = sprintf($this->tags['metalink'], $attributes['link'], $this->_parseAttributes($attributes, array('link')));
00237                 $attributes['rel'] = 'shortcut icon';
00238             } else {
00239                 $attributes['link'] = $this->url($attributes['link'], true);
00240             }
00241             $out .= sprintf($this->tags['metalink'], $attributes['link'], $this->_parseAttributes($attributes, array('link')));
00242         } else {
00243             $out = sprintf($this->tags['meta'], $this->_parseAttributes($attributes, array('type')));
00244         }
00245 
00246         if ($inline) {
00247             return $this->output($out);
00248         } else {
00249             $view =& ClassRegistry::getObject('view');
00250             $view->addScript($out);
00251         }
00252     }
00253 /**
00254  * Returns a charset META-tag.
00255  *
00256  * @param  string  $charset The character set to be used in the meta tag. Example: "utf-8".
00257  * @return string A meta tag containing the specified character set.
00258  */
00259     function charset($charset = null) {
00260         $charset = current(array_filter(array($charset, strtolower(Configure::read('App.encoding')), 'utf-8')));
00261         return $this->output(sprintf($this->tags['charset'], $charset));
00262     }
00263 /**
00264  * Creates an HTML link.
00265  *
00266  * If $url starts with "http://" this is treated as an external link. Else,
00267  * it is treated as a path to controller/action and parsed with the
00268  * HtmlHelper::url() method.
00269  *
00270  * If the $url is empty, $title is used instead.
00271  *
00272  * @param  string  $title The content to be wrapped by <a> tags.
00273  * @param  mixed   $url Cake-relative URL or array of URL parameters, or external URL (starts with http://)
00274  * @param  array   $htmlAttributes Array of HTML attributes.
00275  * @param  string  $confirmMessage JavaScript confirmation message.
00276  * @param  boolean $escapeTitle Whether or not $title should be HTML escaped.
00277  * @return string   An <a /> element.
00278  */
00279     function link($title, $url = null, $htmlAttributes = array(), $confirmMessage = false, $escapeTitle = true) {
00280         if ($url !== null) {
00281             $url = $this->url($url);
00282         } else {
00283             $url = $this->url($title);
00284             $title = $url;
00285             $escapeTitle = false;
00286         }
00287 
00288         if (isset($htmlAttributes['escape'])) {
00289             $escapeTitle = $htmlAttributes['escape'];
00290             unset($htmlAttributes['escape']);
00291         }
00292         if ($escapeTitle === true) {
00293             $title = htmlspecialchars($title, ENT_QUOTES);
00294         } elseif (is_string($escapeTitle)) {
00295             $title = htmlentities($title, ENT_QUOTES, $escapeTitle);
00296         }
00297 
00298         if (!empty($htmlAttributes['confirm'])) {
00299             $confirmMessage = $htmlAttributes['confirm'];
00300             unset($htmlAttributes['confirm']);
00301         }
00302         if ($confirmMessage) {
00303             $confirmMessage = str_replace("'", "\'", $confirmMessage);
00304             $confirmMessage = str_replace('"', '\"', $confirmMessage);
00305             $htmlAttributes['onclick'] = "return confirm('{$confirmMessage}');";
00306         } elseif (isset($htmlAttributes['default']) && $htmlAttributes['default'] == false) {
00307             if (isset($htmlAttributes['onclick'])) {
00308                 $htmlAttributes['onclick'] .= ' event.returnValue = false; return false;';
00309             } else {
00310                 $htmlAttributes['onclick'] = 'event.returnValue = false; return false;';
00311             }
00312             unset($htmlAttributes['default']);
00313         }
00314         return $this->output(sprintf($this->tags['link'], $url, $this->_parseAttributes($htmlAttributes), $title));
00315     }
00316 /**
00317  * Creates a link element for CSS stylesheets.
00318  *
00319  * @param mixed $path The name of a CSS style sheet in /app/webroot/css, or an array containing names of CSS stylesheets in that directory.
00320  * @param string $rel Rel attribute. Defaults to "stylesheet".
00321  * @param array $htmlAttributes Array of HTML attributes.
00322  * @param boolean $inline If set to false, the generated tag appears in the head tag of the layout.
00323  * @return string CSS <link /> or <style /> tag, depending on the type of link.
00324  */
00325     function css($path, $rel = null, $htmlAttributes = array(), $inline = true) {
00326         if (is_array($path)) {
00327             $out = '';
00328             foreach ($path as $i) {
00329                 $out .= "\n\t" . $this->css($i, $rel, $htmlAttributes, $inline);
00330             }
00331             if ($inline)  {
00332                 return $out . "\n";
00333             }
00334             return;
00335         }
00336 
00337         if (strpos($path, '://') !== false) {
00338             $url = $path;
00339         } else {
00340             if ($path{0} !== '/') {
00341                 $path = CSS_URL . $path;
00342             }
00343 
00344             if (strpos($path, '?') === false) {
00345                 if (strpos($path, '.css') === false) {
00346                     $path .= '.css';
00347                 }
00348                 if ((Configure::read('Asset.timestamp') === true && Configure::read() > 0) || Configure::read('Asset.timestamp') === 'force') {
00349                     $path .= '?' . @filemtime(WWW_ROOT . str_replace('/', DS, $path));
00350                 }
00351             }
00352 
00353             if (Configure::read('Asset.filter.css')) {
00354                 $path = str_replace(CSS_URL, 'ccss/', $path);
00355             }
00356             $url = $this->webroot($path);
00357         }
00358 
00359         if ($rel == 'import') {
00360             $out = sprintf($this->tags['style'], $this->_parseAttributes($htmlAttributes, null, '', ' '), '@import url(' . $url . ');');
00361         } else {
00362             if ($rel == null) {
00363                 $rel = 'stylesheet';
00364             }
00365             $out = sprintf($this->tags['css'], $rel, $url, $this->_parseAttributes($htmlAttributes, null, '', ' '));
00366         }
00367         $out = $this->output($out);
00368 
00369         if ($inline) {
00370             return $out;
00371         } else {
00372             $view =& ClassRegistry::getObject('view');
00373             $view->addScript($out);
00374         }
00375     }
00376 /**
00377  * Builds CSS style data from an array of CSS properties
00378  *
00379  * @param array $data
00380  * @return string CSS styling data
00381  */
00382     function style($data, $inline = true) {
00383         if (!is_array($data)) {
00384             return $data;
00385         }
00386         $out = array();
00387         foreach ($data as $key=> $value) {
00388             $out[] = $key.':'.$value.';';
00389         }
00390         if ($inline) {
00391             return join(' ', $out);
00392         }
00393         return join("\n", $out);
00394     }
00395 /**
00396  * Returns the breadcrumb trail as a sequence of &raquo;-separated links.
00397  *
00398  * @param  string  $separator Text to separate crumbs.
00399  * @param  string  $startText This will be the first crumb, if false it defaults to first crumb in array
00400  * @return string
00401  */
00402     function getCrumbs($separator = '&raquo;', $startText = false) {
00403         if (count($this->_crumbs)) {
00404             $out = array();
00405             if ($startText) {
00406                 $out[] = $this->link($startText, '/');
00407             }
00408 
00409             foreach ($this->_crumbs as $crumb) {
00410                 if (!empty($crumb[1])) {
00411                     $out[] = $this->link($crumb[0], $crumb[1], $crumb[2]);
00412                 } else {
00413                     $out[] = $crumb[0];
00414                 }
00415             }
00416             return $this->output(join($separator, $out));
00417         } else {
00418             return null;
00419         }
00420     }
00421 /**
00422  * Creates a formatted IMG element.
00423  *
00424  * @param string $path Path to the image file, relative to the app/webroot/img/ directory.
00425  * @param array $htmlAttributes Array of HTML attributes.
00426  * @return string
00427  */
00428     function image($path, $options = array()) {
00429         if (is_array($path)) {
00430             $path = $this->url($path);
00431         } elseif ($path{0} === '/') {
00432             $path = $this->webroot($path);
00433         } elseif (strpos($path, '://') !== false) {
00434             $path = $path;
00435         } else {
00436             if (Configure::read('Asset.timestamp') == true && Configure::read() > 0) {
00437                 $path .= '?' . @filemtime(str_replace('/', DS, WWW_ROOT . IMAGES_URL . $path));
00438             }
00439             $path = $this->webroot(IMAGES_URL . $path);
00440         }
00441 
00442         if (!isset($options['alt'])) {
00443             $options['alt'] = '';
00444         }
00445 
00446         $url = false;
00447         if (!empty($options['url'])) {
00448             $url = $options['url'];
00449             unset($options['url']);
00450         }
00451 
00452         $image = sprintf($this->tags['image'], $path, $this->_parseAttributes($options, null, '', ' '));
00453 
00454         if ($url) {
00455             return $this->output(sprintf($this->tags['link'], $this->url($url), null, $image));
00456         }
00457 
00458         return $this->output($image);
00459     }
00460 /**
00461  * Returns a row of formatted and named TABLE headers.
00462  *
00463  * @param array $names      Array of tablenames.
00464  * @param array $trOptions  HTML options for TR elements.
00465  * @param array $thOptions  HTML options for TH elements.
00466  * @return string
00467  */
00468     function tableHeaders($names, $trOptions = null, $thOptions = null) {
00469         $out = array();
00470         foreach ($names as $arg) {
00471             $out[] = sprintf($this->tags['tableheader'], $this->_parseAttributes($thOptions), $arg);
00472         }
00473         $data = sprintf($this->tags['tablerow'], $this->_parseAttributes($trOptions), join(' ', $out));
00474         return $this->output($data);
00475     }
00476 /**
00477  * Returns a formatted string of table rows (TR's with TD's in them).
00478  *
00479  * @param array $data       Array of table data
00480  * @param array $oddTrOptions HTML options for odd TR elements if true useCount is used
00481  * @param array $evenTrOptions HTML options for even TR elements
00482  * @param bool $useCount adds class "column-$i"
00483  * @param bool $continueOddEven If false, will use a non-static $count variable, so that the odd/even count is reset to zero just for that call
00484  * @return string   Formatted HTML
00485  */
00486     function tableCells($data, $oddTrOptions = null, $evenTrOptions = null, $useCount = false, $continueOddEven = true) {
00487         if (empty($data[0]) || !is_array($data[0])) {
00488             $data = array($data);
00489         }
00490 
00491         if ($oddTrOptions === true) {
00492             $useCount = true;
00493             $oddTrOptions = null;
00494         }
00495 
00496         if ($evenTrOptions === false) {
00497             $continueOddEven = false;
00498             $evenTrOptions = null;
00499         }
00500 
00501         if ($continueOddEven) {
00502             static $count = 0;
00503         } else {
00504             $count = 0;
00505         }
00506 
00507         foreach ($data as $line) {
00508             $count++;
00509             $cellsOut = array();
00510             $i = 0;
00511             foreach ($line as $cell) {
00512                 $cellOptions = array();
00513 
00514                 if (is_array($cell)) {
00515                     $cellOptions = $cell[1];
00516                     $cell = $cell[0];
00517                 } elseif ($useCount) {
00518                     $cellOptions['class'] = 'column-' . ++$i;
00519                 }
00520                 $cellsOut[] = sprintf($this->tags['tablecell'], $this->_parseAttributes($cellOptions), $cell);
00521             }
00522             $options = $this->_parseAttributes($count % 2 ? $oddTrOptions : $evenTrOptions);
00523             $out[] = sprintf($this->tags['tablerow'], $options, join(' ', $cellsOut));
00524         }
00525         return $this->output(join("\n", $out));
00526     }
00527 /**
00528  * Returns a formatted block tag, i.e DIV, SPAN, P.
00529  *
00530  * @param string $name Tag name.
00531  * @param string $text String content that will appear inside the div element.
00532  *          If null, only a start tag will be printed
00533  * @param array $attributes Additional HTML attributes of the DIV tag
00534  * @param boolean $escape If true, $text will be HTML-escaped
00535  * @return string The formatted tag element
00536  */
00537     function tag($name, $text = null, $attributes = array(), $escape = false) {
00538         if ($escape) {
00539             $text = h($text);
00540         }
00541         if (!is_array($attributes)) {
00542             $attributes = array('class' => $attributes);
00543         }
00544         if ($text === null) {
00545             $tag = 'tagstart';
00546         } else {
00547             $tag = 'tag';
00548         }
00549         return $this->output(sprintf($this->tags[$tag], $name, $this->_parseAttributes($attributes, null, ' ', ''), $text, $name));
00550     }
00551 /**
00552  * Returns a formatted DIV tag for HTML FORMs.
00553  *
00554  * @param string $class CSS class name of the div element.
00555  * @param string $text String content that will appear inside the div element.
00556  *          If null, only a start tag will be printed
00557  * @param array $attributes Additional HTML attributes of the DIV tag
00558  * @param boolean $escape If true, $text will be HTML-escaped
00559  * @return string The formatted DIV element
00560  */
00561     function div($class = null, $text = null, $attributes = array(), $escape = false) {
00562         if ($class != null && !empty($class)) {
00563             $attributes['class'] = $class;
00564         }
00565         return $this->tag('div', $text, $attributes, $escape);
00566     }
00567 /**
00568  * Returns a formatted P tag.
00569  *
00570  * @param string $class CSS class name of the p element.
00571  * @param string $text String content that will appear inside the p element.
00572  * @param array $attributes Additional HTML attributes of the P tag
00573  * @param boolean $escape If true, $text will be HTML-escaped
00574  * @return string The formatted P element
00575  */
00576     function para($class, $text, $attributes = array(), $escape = false) {
00577         if ($escape) {
00578             $text = h($text);
00579         }
00580         if ($class != null && !empty($class)) {
00581             $attributes['class'] = $class;
00582         }
00583         if ($text === null) {
00584             $tag = 'parastart';
00585         } else {
00586             $tag = 'para';
00587         }
00588         return $this->output(sprintf($this->tags[$tag], $this->_parseAttributes($attributes, null, ' ', ''), $text));
00589     }
00590 /**
00591  * Build a nested list (UL/OL) out of an associative array.
00592  *
00593  * @param array $list Set of elements to list
00594  * @param array $attributes Additional HTML attributes of the list (ol/ul) tag or if ul/ol use that as tag
00595  * @param array $itemAttributes Additional HTML attributes of the list item (LI) tag
00596  * @param string $tag Type of list tag to use (ol/ul)
00597  * @return string The nested list
00598  * @access public
00599  */
00600     function nestedList($list, $attributes = array(), $itemAttributes = array(), $tag = 'ul') {
00601         if (is_string($attributes)) {
00602             $tag = $attributes;
00603             $attributes = array();
00604         }
00605         $items = $this->__nestedListItem($list, $attributes, $itemAttributes, $tag);
00606         return sprintf($this->tags[$tag], $this->_parseAttributes($attributes, null, ' ', ''), $items);
00607     }
00608 /**
00609  * Internal function to build a nested list (UL/OL) out of an associative array.
00610  *
00611  * @param array $list Set of elements to list
00612  * @param array $attributes Additional HTML attributes of the list (ol/ul) tag
00613  * @param array $itemAttributes Additional HTML attributes of the list item (LI) tag
00614  * @param string $tag Type of list tag to use (ol/ul)
00615  * @return string The nested list element
00616  * @access private
00617  * @see nestedList()
00618  */
00619     function __nestedListItem($items, $attributes, $itemAttributes, $tag) {
00620         $out = '';
00621 
00622         $index = 1;
00623         foreach($items as $key => $item) {
00624             if (is_array($item)) {
00625                 $item = $key . $this->nestedList($item, $attributes, $itemAttributes, $tag);
00626             }
00627             if (isset($itemAttributes['even']) && $index % 2 == 0) {
00628                 $itemAttributes['class'] = $itemAttributes['even'];
00629             } else if (isset($itemAttributes['odd']) && $index % 2 != 0) {
00630                 $itemAttributes['class'] = $itemAttributes['odd'];
00631             }
00632             $out .= sprintf($this->tags['li'], $this->_parseAttributes(array_diff_key($itemAttributes, array_flip(array('even', 'odd'))), null, ' ', ''), $item);
00633             $index++;
00634         }
00635         return $out;
00636     }
00637 }
00638 ?>