PageRenderTime 56ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/cake/libs/view/helpers/html.php

https://github.com/mariuz/firetube
PHP | 648 lines | 503 code | 7 blank | 138 comment | 27 complexity | a888d4e3b331bf0356c5b51c38e875dd MD5 | raw file
Possible License(s): LGPL-2.1
  1. <?php
  2. /* SVN FILE: $Id$ */
  3. /**
  4. * Html Helper class file.
  5. *
  6. * Simplifies the construction of HTML elements.
  7. *
  8. * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
  9. * Copyright 2005-2011, Cake Software Foundation, Inc. (http://cakefoundation.org)
  10. *
  11. * Licensed under The MIT License
  12. * Redistributions of files must retain the above copyright notice.
  13. *
  14. * @copyright Copyright 2005-2011, Cake Software Foundation, Inc. (http://cakefoundation.org)
  15. * @link http://cakephp.org CakePHP(tm) Project
  16. * @package cake
  17. * @subpackage cake.cake.libs.view.helpers
  18. * @since CakePHP(tm) v 0.9.1
  19. * @version $Revision$
  20. * @modifiedby $LastChangedBy$
  21. * @lastmodified $Date$
  22. * @license http://www.opensource.org/licenses/mit-license.php The MIT License
  23. */
  24. /**
  25. * Html Helper class for easy use of HTML widgets.
  26. *
  27. * HtmlHelper encloses all methods needed while working with HTML pages.
  28. *
  29. * @package cake
  30. * @subpackage cake.cake.libs.view.helpers
  31. */
  32. class HtmlHelper extends AppHelper {
  33. /*************************************************************************
  34. * Public variables
  35. *************************************************************************/
  36. /**#@+
  37. * @access public
  38. */
  39. /**
  40. * html tags used by this helper.
  41. *
  42. * @var array
  43. */
  44. var $tags = array(
  45. 'meta' => '<meta%s/>',
  46. 'metalink' => '<link href="%s"%s/>',
  47. 'link' => '<a href="%s"%s>%s</a>',
  48. 'mailto' => '<a href="mailto:%s" %s>%s</a>',
  49. 'form' => '<form %s>',
  50. 'formend' => '</form>',
  51. 'input' => '<input name="%s" %s/>',
  52. 'textarea' => '<textarea name="%s" %s>%s</textarea>',
  53. 'hidden' => '<input type="hidden" name="%s" %s/>',
  54. 'checkbox' => '<input type="checkbox" name="%s" %s/>',
  55. 'checkboxmultiple' => '<input type="checkbox" name="%s[]"%s />',
  56. 'radio' => '<input type="radio" name="%s" id="%s" %s />%s',
  57. 'selectstart' => '<select name="%s"%s>',
  58. 'selectmultiplestart' => '<select name="%s[]"%s>',
  59. 'selectempty' => '<option value=""%s>&nbsp;</option>',
  60. 'selectoption' => '<option value="%s"%s>%s</option>',
  61. 'selectend' => '</select>',
  62. 'optiongroup' => '<optgroup label="%s"%s>',
  63. 'optiongroupend' => '</optgroup>',
  64. 'checkboxmultiplestart' => '',
  65. 'checkboxmultipleend' => '',
  66. 'password' => '<input type="password" name="%s" %s/>',
  67. 'file' => '<input type="file" name="%s" %s/>',
  68. 'file_no_model' => '<input type="file" name="%s" %s/>',
  69. 'submit' => '<input type="submit" %s/>',
  70. 'submitimage' => '<input type="image" src="%s" %s/>',
  71. 'button' => '<input type="%s" %s/>',
  72. 'image' => '<img src="%s" %s/>',
  73. 'tableheader' => '<th%s>%s</th>',
  74. 'tableheaderrow' => '<tr%s>%s</tr>',
  75. 'tablecell' => '<td%s>%s</td>',
  76. 'tablerow' => '<tr%s>%s</tr>',
  77. 'block' => '<div%s>%s</div>',
  78. 'blockstart' => '<div%s>',
  79. 'blockend' => '</div>',
  80. 'tag' => '<%s%s>%s</%s>',
  81. 'tagstart' => '<%s%s>',
  82. 'tagend' => '</%s>',
  83. 'para' => '<p%s>%s</p>',
  84. 'parastart' => '<p%s>',
  85. 'label' => '<label for="%s"%s>%s</label>',
  86. 'fieldset' => '<fieldset%s>%s</fieldset>',
  87. 'fieldsetstart' => '<fieldset><legend>%s</legend>',
  88. 'fieldsetend' => '</fieldset>',
  89. 'legend' => '<legend>%s</legend>',
  90. 'css' => '<link rel="%s" type="text/css" href="%s" %s/>',
  91. 'style' => '<style type="text/css"%s>%s</style>',
  92. 'charset' => '<meta http-equiv="Content-Type" content="text/html; charset=%s" />',
  93. 'ul' => '<ul%s>%s</ul>',
  94. 'ol' => '<ol%s>%s</ol>',
  95. 'li' => '<li%s>%s</li>',
  96. 'error' => '<div%s>%s</div>'
  97. );
  98. /**
  99. * Base URL
  100. *
  101. * @var string
  102. */
  103. var $base = null;
  104. /**
  105. * URL to current action.
  106. *
  107. * @var string
  108. */
  109. var $here = null;
  110. /**
  111. * Parameter array.
  112. *
  113. * @var array
  114. */
  115. var $params = array();
  116. /**
  117. * Current action.
  118. *
  119. * @var string
  120. */
  121. var $action = null;
  122. /**
  123. * Enter description here...
  124. *
  125. * @var array
  126. */
  127. var $data = null;
  128. /**#@-*/
  129. /*************************************************************************
  130. * Private variables
  131. *************************************************************************/
  132. /**#@+
  133. * @access private
  134. */
  135. /**
  136. * Breadcrumbs.
  137. *
  138. * @var array
  139. * @access private
  140. */
  141. var $_crumbs = array();
  142. /**
  143. * Document type definitions
  144. *
  145. * @var array
  146. * @access private
  147. */
  148. var $__docTypes = array(
  149. 'html4-strict' => '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">',
  150. 'html4-trans' => '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">',
  151. 'html4-frame' => '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">',
  152. 'xhtml-strict' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">',
  153. 'xhtml-trans' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">',
  154. 'xhtml-frame' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">',
  155. 'xhtml11' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">'
  156. );
  157. /**
  158. * Adds a link to the breadcrumbs array.
  159. *
  160. * @param string $name Text for link
  161. * @param string $link URL for link (if empty it won't be a link)
  162. * @param mixed $options Link attributes e.g. array('id'=>'selected')
  163. */
  164. function addCrumb($name, $link = null, $options = null) {
  165. $this->_crumbs[] = array($name, $link, $options);
  166. }
  167. /**
  168. * Returns a doctype string.
  169. *
  170. * Possible doctypes:
  171. * + html4-strict: HTML4 Strict.
  172. * + html4-trans: HTML4 Transitional.
  173. * + html4-frame: HTML4 Frameset.
  174. * + xhtml-strict: XHTML1 Strict.
  175. * + xhtml-trans: XHTML1 Transitional.
  176. * + xhtml-frame: XHTML1 Frameset.
  177. * + xhtml11: XHTML1.1.
  178. *
  179. * @param string $type Doctype to use.
  180. * @return string Doctype.
  181. */
  182. function docType($type = 'xhtml-strict') {
  183. if (isset($this->__docTypes[$type])) {
  184. return $this->output($this->__docTypes[$type]);
  185. }
  186. return null;
  187. }
  188. /**
  189. * Creates a link to an external resource and handles basic meta tags
  190. *
  191. * @param string $type The title of the external resource
  192. * @param mixed $url The address of the external resource or string for content attribute
  193. * @param array $attributes Other attributes for the generated tag. If the type attribute is html, rss, atom, or icon, the mime-type is returned.
  194. * @param boolean $inline If set to false, the generated tag appears in the head tag of the layout.
  195. * @return string
  196. */
  197. function meta($type, $url = null, $attributes = array(), $inline = true) {
  198. if (!is_array($type)) {
  199. $types = array(
  200. 'rss' => array('type' => 'application/rss+xml', 'rel' => 'alternate', 'title' => $type, 'link' => $url),
  201. 'atom' => array('type' => 'application/atom+xml', 'title' => $type, 'link' => $url),
  202. 'icon' => array('type' => 'image/x-icon', 'rel' => 'icon', 'link' => $url),
  203. 'keywords' => array('name' => 'keywords', 'content' => $url),
  204. 'description' => array('name' => 'description', 'content' => $url),
  205. );
  206. if ($type === 'icon' && $url === null) {
  207. $types['icon']['link'] = $this->webroot('favicon.ico');
  208. }
  209. if (isset($types[$type])) {
  210. $type = $types[$type];
  211. } elseif (!isset($attributes['type']) && $url !== null) {
  212. if (is_array($url) && isset($url['ext'])) {
  213. $type = $types[$url['ext']];
  214. } else {
  215. $type = $types['rss'];
  216. }
  217. } elseif (isset($attributes['type']) && isset($types[$attributes['type']])) {
  218. $type = $types[$attributes['type']];
  219. unset($attributes['type']);
  220. } else {
  221. $type = array();
  222. }
  223. } elseif ($url !== null) {
  224. $inline = $url;
  225. }
  226. $attributes = array_merge($type, $attributes);
  227. $out = null;
  228. if (isset($attributes['link'])) {
  229. if (isset($attributes['rel']) && $attributes['rel'] === 'icon') {
  230. $out = sprintf($this->tags['metalink'], $attributes['link'], $this->_parseAttributes($attributes, array('link'), ' ', ' '));
  231. $attributes['rel'] = 'shortcut icon';
  232. } else {
  233. $attributes['link'] = $this->url($attributes['link'], true);
  234. }
  235. $out .= sprintf($this->tags['metalink'], $attributes['link'], $this->_parseAttributes($attributes, array('link'), ' ', ' '));
  236. } else {
  237. $out = sprintf($this->tags['meta'], $this->_parseAttributes($attributes, array('type'), ' ', ' '));
  238. }
  239. if ($inline) {
  240. return $this->output($out);
  241. } else {
  242. $view =& ClassRegistry::getObject('view');
  243. $view->addScript($out);
  244. }
  245. }
  246. /**
  247. * Returns a charset META-tag.
  248. *
  249. * @param string $charset The character set to be used in the meta tag. Example: "utf-8".
  250. * @return string A meta tag containing the specified character set.
  251. */
  252. function charset($charset = null) {
  253. if (empty($charset)) {
  254. $charset = strtolower(Configure::read('App.encoding'));
  255. }
  256. return $this->output(sprintf($this->tags['charset'], (!empty($charset) ? $charset : 'utf-8')));
  257. }
  258. /**
  259. * Creates an HTML link.
  260. *
  261. * If $url starts with "http://" this is treated as an external link. Else,
  262. * it is treated as a path to controller/action and parsed with the
  263. * HtmlHelper::url() method.
  264. *
  265. * If the $url is empty, $title is used instead.
  266. *
  267. * @param string $title The content to be wrapped by <a> tags.
  268. * @param mixed $url Cake-relative URL or array of URL parameters, or external URL (starts with http://)
  269. * @param array $htmlAttributes Array of HTML attributes.
  270. * @param string $confirmMessage JavaScript confirmation message.
  271. * @param boolean $escapeTitle Whether or not $title should be HTML escaped.
  272. * @return string An <a /> element.
  273. */
  274. function link($title, $url = null, $htmlAttributes = array(), $confirmMessage = false, $escapeTitle = true) {
  275. if ($url !== null) {
  276. $url = $this->url($url);
  277. } else {
  278. $url = $this->url($title);
  279. $title = $url;
  280. $escapeTitle = false;
  281. }
  282. if (isset($htmlAttributes['escape']) && $escapeTitle == true) {
  283. $escapeTitle = $htmlAttributes['escape'];
  284. }
  285. if ($escapeTitle === true) {
  286. $title = h($title);
  287. } elseif (is_string($escapeTitle)) {
  288. $title = htmlentities($title, ENT_QUOTES, $escapeTitle);
  289. }
  290. if (!empty($htmlAttributes['confirm'])) {
  291. $confirmMessage = $htmlAttributes['confirm'];
  292. unset($htmlAttributes['confirm']);
  293. }
  294. if ($confirmMessage) {
  295. $confirmMessage = str_replace("'", "\'", $confirmMessage);
  296. $confirmMessage = str_replace('"', '\"', $confirmMessage);
  297. $htmlAttributes['onclick'] = "return confirm('{$confirmMessage}');";
  298. } elseif (isset($htmlAttributes['default']) && $htmlAttributes['default'] == false) {
  299. if (isset($htmlAttributes['onclick'])) {
  300. $htmlAttributes['onclick'] .= ' event.returnValue = false; return false;';
  301. } else {
  302. $htmlAttributes['onclick'] = 'event.returnValue = false; return false;';
  303. }
  304. unset($htmlAttributes['default']);
  305. }
  306. return $this->output(sprintf($this->tags['link'], $url, $this->_parseAttributes($htmlAttributes), $title));
  307. }
  308. /**
  309. * Creates a link element for CSS stylesheets.
  310. *
  311. * @param mixed $path The name of a CSS style sheet or an array containing names of
  312. * CSS stylesheets. If `$path` is prefixed with '/', the path will be relative to the webroot
  313. * of your application. Otherwise, the path will be relative to your CSS path, usually webroot/css.
  314. * @param string $rel Rel attribute. Defaults to "stylesheet". If equal to 'import' the stylesheet will be imported.
  315. * @param array $htmlAttributes Array of HTML attributes.
  316. * @param boolean $inline If set to false, the generated tag appears in the head tag of the layout.
  317. * @return string CSS <link /> or <style /> tag, depending on the type of link.
  318. */
  319. function css($path, $rel = null, $htmlAttributes = array(), $inline = true) {
  320. if (is_array($path)) {
  321. $out = '';
  322. foreach ($path as $i) {
  323. $out .= "\n\t" . $this->css($i, $rel, $htmlAttributes, $inline);
  324. }
  325. if ($inline) {
  326. return $out . "\n";
  327. }
  328. return;
  329. }
  330. if (strpos($path, '://') !== false) {
  331. $url = $path;
  332. } else {
  333. if ($path[0] !== '/') {
  334. $path = CSS_URL . $path;
  335. }
  336. if (strpos($path, '?') === false) {
  337. if (!preg_match('/.*\.(css|php)$/i', $path)) {
  338. $path .= '.css';
  339. }
  340. }
  341. $timestampEnabled = (
  342. (Configure::read('Asset.timestamp') === true && Configure::read() > 0) ||
  343. Configure::read('Asset.timestamp') === 'force'
  344. );
  345. $url = $this->webroot($path);
  346. if (strpos($path, '?') === false && $timestampEnabled) {
  347. $url .= '?' . @filemtime(WWW_ROOT . str_replace('/', DS, $path));
  348. }
  349. if (Configure::read('Asset.filter.css')) {
  350. $pos = strpos($url, CSS_URL);
  351. if ($pos !== false) {
  352. $url = substr($url, 0, $pos) . 'ccss/' . substr($url, $pos + strlen(CSS_URL));
  353. }
  354. }
  355. }
  356. if ($rel == 'import') {
  357. $out = sprintf($this->tags['style'], $this->_parseAttributes($htmlAttributes, null, '', ' '), '@import url(' . $url . ');');
  358. } else {
  359. if ($rel == null) {
  360. $rel = 'stylesheet';
  361. }
  362. $out = sprintf($this->tags['css'], $rel, $url, $this->_parseAttributes($htmlAttributes, null, '', ' '));
  363. }
  364. $out = $this->output($out);
  365. if ($inline) {
  366. return $out;
  367. } else {
  368. $view =& ClassRegistry::getObject('view');
  369. $view->addScript($out);
  370. }
  371. }
  372. /**
  373. * Builds CSS style data from an array of CSS properties
  374. *
  375. * @param array $data Style data array
  376. * @param boolean $inline Whether or not the style block should be displayed inline
  377. * @return string CSS styling data
  378. */
  379. function style($data, $inline = true) {
  380. if (!is_array($data)) {
  381. return $data;
  382. }
  383. $out = array();
  384. foreach ($data as $key=> $value) {
  385. $out[] = $key.':'.$value.';';
  386. }
  387. if ($inline) {
  388. return implode(' ', $out);
  389. }
  390. return implode("\n", $out);
  391. }
  392. /**
  393. * Returns the breadcrumb trail as a sequence of &raquo;-separated links.
  394. *
  395. * @param string $separator Text to separate crumbs.
  396. * @param string $startText This will be the first crumb, if false it defaults to first crumb in array
  397. * @return string
  398. */
  399. function getCrumbs($separator = '&raquo;', $startText = false) {
  400. if (!empty($this->_crumbs)) {
  401. $out = array();
  402. if ($startText) {
  403. $out[] = $this->link($startText, '/');
  404. }
  405. foreach ($this->_crumbs as $crumb) {
  406. if (!empty($crumb[1])) {
  407. $out[] = $this->link($crumb[0], $crumb[1], $crumb[2]);
  408. } else {
  409. $out[] = $crumb[0];
  410. }
  411. }
  412. return $this->output(implode($separator, $out));
  413. } else {
  414. return null;
  415. }
  416. }
  417. /**
  418. * Creates a formatted IMG element.
  419. *
  420. * @param string $path Path to the image file, relative to the app/webroot/img/ directory.
  421. * @param array $options Array of HTML attributes.
  422. * @return string
  423. */
  424. function image($path, $options = array()) {
  425. if (is_array($path)) {
  426. $path = $this->url($path);
  427. } elseif (strpos($path, '://') === false) {
  428. if ($path[0] !== '/') {
  429. $path = IMAGES_URL . $path;
  430. }
  431. if ((Configure::read('Asset.timestamp') == true && Configure::read() > 0) || Configure::read('Asset.timestamp') === 'force') {
  432. $path = $this->webroot($path) . '?' . @filemtime(WWW_ROOT . str_replace('/', DS, $path));
  433. } else {
  434. $path = $this->webroot($path);
  435. }
  436. }
  437. if (!isset($options['alt'])) {
  438. $options['alt'] = '';
  439. }
  440. $url = false;
  441. if (!empty($options['url'])) {
  442. $url = $options['url'];
  443. unset($options['url']);
  444. }
  445. $image = sprintf($this->tags['image'], $path, $this->_parseAttributes($options, null, '', ' '));
  446. if ($url) {
  447. return $this->output(sprintf($this->tags['link'], $this->url($url), null, $image));
  448. }
  449. return $this->output($image);
  450. }
  451. /**
  452. * Returns a row of formatted and named TABLE headers.
  453. *
  454. * @param array $names Array of tablenames.
  455. * @param array $trOptions HTML options for TR elements.
  456. * @param array $thOptions HTML options for TH elements.
  457. * @return string
  458. */
  459. function tableHeaders($names, $trOptions = null, $thOptions = null) {
  460. $out = array();
  461. foreach ($names as $arg) {
  462. $out[] = sprintf($this->tags['tableheader'], $this->_parseAttributes($thOptions), $arg);
  463. }
  464. $data = sprintf($this->tags['tablerow'], $this->_parseAttributes($trOptions), implode(' ', $out));
  465. return $this->output($data);
  466. }
  467. /**
  468. * Returns a formatted string of table rows (TR's with TD's in them).
  469. *
  470. * @param array $data Array of table data
  471. * @param array $oddTrOptions HTML options for odd TR elements if true useCount is used
  472. * @param array $evenTrOptions HTML options for even TR elements
  473. * @param bool $useCount adds class "column-$i"
  474. * @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
  475. * @return string Formatted HTML
  476. */
  477. function tableCells($data, $oddTrOptions = null, $evenTrOptions = null, $useCount = false, $continueOddEven = true) {
  478. if (empty($data[0]) || !is_array($data[0])) {
  479. $data = array($data);
  480. }
  481. if ($oddTrOptions === true) {
  482. $useCount = true;
  483. $oddTrOptions = null;
  484. }
  485. if ($evenTrOptions === false) {
  486. $continueOddEven = false;
  487. $evenTrOptions = null;
  488. }
  489. if ($continueOddEven) {
  490. static $count = 0;
  491. } else {
  492. $count = 0;
  493. }
  494. foreach ($data as $line) {
  495. $count++;
  496. $cellsOut = array();
  497. $i = 0;
  498. foreach ($line as $cell) {
  499. $cellOptions = array();
  500. if (is_array($cell)) {
  501. $cellOptions = $cell[1];
  502. $cell = $cell[0];
  503. } elseif ($useCount) {
  504. $cellOptions['class'] = 'column-' . ++$i;
  505. }
  506. $cellsOut[] = sprintf($this->tags['tablecell'], $this->_parseAttributes($cellOptions), $cell);
  507. }
  508. $options = $this->_parseAttributes($count % 2 ? $oddTrOptions : $evenTrOptions);
  509. $out[] = sprintf($this->tags['tablerow'], $options, implode(' ', $cellsOut));
  510. }
  511. return $this->output(implode("\n", $out));
  512. }
  513. /**
  514. * Returns a formatted block tag, i.e DIV, SPAN, P.
  515. *
  516. * @param string $name Tag name.
  517. * @param string $text String content that will appear inside the div element.
  518. * If null, only a start tag will be printed
  519. * @param array $attributes Additional HTML attributes of the DIV tag
  520. * @param boolean $escape If true, $text will be HTML-escaped
  521. * @return string The formatted tag element
  522. */
  523. function tag($name, $text = null, $attributes = array(), $escape = false) {
  524. if ($escape) {
  525. $text = h($text);
  526. }
  527. if (!is_array($attributes)) {
  528. $attributes = array('class' => $attributes);
  529. }
  530. if ($text === null) {
  531. $tag = 'tagstart';
  532. } else {
  533. $tag = 'tag';
  534. }
  535. return $this->output(sprintf($this->tags[$tag], $name, $this->_parseAttributes($attributes, null, ' ', ''), $text, $name));
  536. }
  537. /**
  538. * Returns a formatted DIV tag for HTML FORMs.
  539. *
  540. * @param string $class CSS class name of the div element.
  541. * @param string $text String content that will appear inside the div element.
  542. * If null, only a start tag will be printed
  543. * @param array $attributes Additional HTML attributes of the DIV tag
  544. * @param boolean $escape If true, $text will be HTML-escaped
  545. * @return string The formatted DIV element
  546. */
  547. function div($class = null, $text = null, $attributes = array(), $escape = false) {
  548. if ($class != null && !empty($class)) {
  549. $attributes['class'] = $class;
  550. }
  551. return $this->tag('div', $text, $attributes, $escape);
  552. }
  553. /**
  554. * Returns a formatted P tag.
  555. *
  556. * @param string $class CSS class name of the p element.
  557. * @param string $text String content that will appear inside the p element.
  558. * @param array $attributes Additional HTML attributes of the P tag
  559. * @param boolean $escape If true, $text will be HTML-escaped
  560. * @return string The formatted P element
  561. */
  562. function para($class, $text, $attributes = array(), $escape = false) {
  563. if ($escape) {
  564. $text = h($text);
  565. }
  566. if ($class != null && !empty($class)) {
  567. $attributes['class'] = $class;
  568. }
  569. if ($text === null) {
  570. $tag = 'parastart';
  571. } else {
  572. $tag = 'para';
  573. }
  574. return $this->output(sprintf($this->tags[$tag], $this->_parseAttributes($attributes, null, ' ', ''), $text));
  575. }
  576. /**
  577. * Build a nested list (UL/OL) out of an associative array.
  578. *
  579. * @param array $list Set of elements to list
  580. * @param array $attributes Additional HTML attributes of the list (ol/ul) tag or if ul/ol use that as tag
  581. * @param array $itemAttributes Additional HTML attributes of the list item (LI) tag
  582. * @param string $tag Type of list tag to use (ol/ul)
  583. * @return string The nested list
  584. * @access public
  585. */
  586. function nestedList($list, $attributes = array(), $itemAttributes = array(), $tag = 'ul') {
  587. if (is_string($attributes)) {
  588. $tag = $attributes;
  589. $attributes = array();
  590. }
  591. $items = $this->__nestedListItem($list, $attributes, $itemAttributes, $tag);
  592. return sprintf($this->tags[$tag], $this->_parseAttributes($attributes, null, ' ', ''), $items);
  593. }
  594. /**
  595. * Internal function to build a nested list (UL/OL) out of an associative array.
  596. *
  597. * @param array $list Set of elements to list
  598. * @param array $attributes Additional HTML attributes of the list (ol/ul) tag
  599. * @param array $itemAttributes Additional HTML attributes of the list item (LI) tag
  600. * @param string $tag Type of list tag to use (ol/ul)
  601. * @return string The nested list element
  602. * @access private
  603. * @see nestedList()
  604. */
  605. function __nestedListItem($items, $attributes, $itemAttributes, $tag) {
  606. $out = '';
  607. $index = 1;
  608. foreach ($items as $key => $item) {
  609. if (is_array($item)) {
  610. $item = $key . $this->nestedList($item, $attributes, $itemAttributes, $tag);
  611. }
  612. if (isset($itemAttributes['even']) && $index % 2 == 0) {
  613. $itemAttributes['class'] = $itemAttributes['even'];
  614. } else if (isset($itemAttributes['odd']) && $index % 2 != 0) {
  615. $itemAttributes['class'] = $itemAttributes['odd'];
  616. }
  617. $out .= sprintf($this->tags['li'], $this->_parseAttributes(array_diff_key($itemAttributes, array_flip(array('even', 'odd'))), null, ' ', ''), $item);
  618. $index++;
  619. }
  620. return $out;
  621. }
  622. }
  623. ?>