PageRenderTime 52ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/libraries/joomla/document/html/html.php

http://github.com/joomla/joomla-platform
PHP | 710 lines | 480 code | 58 blank | 172 comment | 47 complexity | cfaa3b0b6e242e96f5a78a633cf55168 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1
  1. <?php
  2. /**
  3. * @package Joomla.Platform
  4. * @subpackage Document
  5. *
  6. * @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
  7. * @license GNU General Public License version 2 or later; see LICENSE
  8. */
  9. defined('JPATH_PLATFORM') or die;
  10. jimport('joomla.utilities.utility');
  11. /**
  12. * DocumentHTML class, provides an easy interface to parse and display a HTML document
  13. *
  14. * @package Joomla.Platform
  15. * @subpackage Document
  16. * @since 11.1
  17. */
  18. class JDocumentHTML extends JDocument
  19. {
  20. /**
  21. * Array of Header <link> tags
  22. *
  23. * @var array
  24. * @since 11.1
  25. */
  26. public $_links = array();
  27. /**
  28. * Array of custom tags
  29. *
  30. * @var array
  31. * @since 11.1
  32. */
  33. public $_custom = array();
  34. /**
  35. * Name of the template
  36. *
  37. * @var string
  38. * @since 11.1
  39. */
  40. public $template = null;
  41. /**
  42. * Base url
  43. *
  44. * @var string
  45. * @since 11.1
  46. */
  47. public $baseurl = null;
  48. /**
  49. * Array of template parameters
  50. *
  51. * @var array
  52. * @since 11.1
  53. */
  54. public $params = null;
  55. /**
  56. * File name
  57. *
  58. * @var array
  59. * @since 11.1
  60. */
  61. public $_file = null;
  62. /**
  63. * String holding parsed template
  64. *
  65. * @var string
  66. * @since 11.1
  67. */
  68. protected $_template = '';
  69. /**
  70. * Array of parsed template JDoc tags
  71. *
  72. * @var array
  73. * @since 11.1
  74. */
  75. protected $_template_tags = array();
  76. /**
  77. * Integer with caching setting
  78. *
  79. * @var integer
  80. * @since 11.1
  81. */
  82. protected $_caching = null;
  83. /**
  84. * Set to true when the document should be output as HTML5
  85. *
  86. * @var boolean
  87. * @since 12.1
  88. */
  89. private $_html5 = null;
  90. /**
  91. * Class constructor
  92. *
  93. * @param array $options Associative array of options
  94. *
  95. * @since 11.1
  96. */
  97. public function __construct($options = array())
  98. {
  99. parent::__construct($options);
  100. // Set document type
  101. $this->_type = 'html';
  102. // Set default mime type and document metadata (meta data syncs with mime type by default)
  103. $this->setMimeEncoding('text/html');
  104. }
  105. /**
  106. * Get the HTML document head data
  107. *
  108. * @return array The document head data in array form
  109. *
  110. * @since 11.1
  111. */
  112. public function getHeadData()
  113. {
  114. $data = array();
  115. $data['title'] = $this->title;
  116. $data['description'] = $this->description;
  117. $data['link'] = $this->link;
  118. $data['metaTags'] = $this->_metaTags;
  119. $data['links'] = $this->_links;
  120. $data['styleSheets'] = $this->_styleSheets;
  121. $data['style'] = $this->_style;
  122. $data['scripts'] = $this->_scripts;
  123. $data['script'] = $this->_script;
  124. $data['custom'] = $this->_custom;
  125. return $data;
  126. }
  127. /**
  128. * Set the HTML document head data
  129. *
  130. * @param array $data The document head data in array form
  131. *
  132. * @return JDocumentHTML instance of $this to allow chaining
  133. *
  134. * @since 11.1
  135. */
  136. public function setHeadData($data)
  137. {
  138. if (empty($data) || !is_array($data))
  139. {
  140. return;
  141. }
  142. $this->title = (isset($data['title']) && !empty($data['title'])) ? $data['title'] : $this->title;
  143. $this->description = (isset($data['description']) && !empty($data['description'])) ? $data['description'] : $this->description;
  144. $this->link = (isset($data['link']) && !empty($data['link'])) ? $data['link'] : $this->link;
  145. $this->_metaTags = (isset($data['metaTags']) && !empty($data['metaTags'])) ? $data['metaTags'] : $this->_metaTags;
  146. $this->_links = (isset($data['links']) && !empty($data['links'])) ? $data['links'] : $this->_links;
  147. $this->_styleSheets = (isset($data['styleSheets']) && !empty($data['styleSheets'])) ? $data['styleSheets'] : $this->_styleSheets;
  148. $this->_style = (isset($data['style']) && !empty($data['style'])) ? $data['style'] : $this->_style;
  149. $this->_scripts = (isset($data['scripts']) && !empty($data['scripts'])) ? $data['scripts'] : $this->_scripts;
  150. $this->_script = (isset($data['script']) && !empty($data['script'])) ? $data['script'] : $this->_script;
  151. $this->_custom = (isset($data['custom']) && !empty($data['custom'])) ? $data['custom'] : $this->_custom;
  152. return $this;
  153. }
  154. /**
  155. * Merge the HTML document head data
  156. *
  157. * @param array $data The document head data in array form
  158. *
  159. * @return JDocumentHTML instance of $this to allow chaining
  160. *
  161. * @since 11.1
  162. */
  163. public function mergeHeadData($data)
  164. {
  165. if (empty($data) || !is_array($data))
  166. {
  167. return;
  168. }
  169. $this->title = (isset($data['title']) && !empty($data['title']) && !stristr($this->title, $data['title']))
  170. ? $this->title . $data['title']
  171. : $this->title;
  172. $this->description = (isset($data['description']) && !empty($data['description']) && !stristr($this->description, $data['description']))
  173. ? $this->description . $data['description']
  174. : $this->description;
  175. $this->link = (isset($data['link'])) ? $data['link'] : $this->link;
  176. if (isset($data['metaTags']))
  177. {
  178. foreach ($data['metaTags'] as $type1 => $data1)
  179. {
  180. $booldog = $type1 == 'http-equiv' ? true : false;
  181. foreach ($data1 as $name2 => $data2)
  182. {
  183. $this->setMetaData($name2, $data2, $booldog);
  184. }
  185. }
  186. }
  187. $this->_links = (isset($data['links']) && !empty($data['links']) && is_array($data['links']))
  188. ? array_unique(array_merge($this->_links, $data['links']))
  189. : $this->_links;
  190. $this->_styleSheets = (isset($data['styleSheets']) && !empty($data['styleSheets']) && is_array($data['styleSheets']))
  191. ? array_merge($this->_styleSheets, $data['styleSheets'])
  192. : $this->_styleSheets;
  193. if (isset($data['style']))
  194. {
  195. foreach ($data['style'] as $type => $stdata)
  196. {
  197. if (!isset($this->_style[strtolower($type)]) || !stristr($this->_style[strtolower($type)], $stdata))
  198. {
  199. $this->addStyleDeclaration($stdata, $type);
  200. }
  201. }
  202. }
  203. $this->_scripts = (isset($data['scripts']) && !empty($data['scripts']) && is_array($data['scripts']))
  204. ? array_merge($this->_scripts, $data['scripts'])
  205. : $this->_scripts;
  206. if (isset($data['script']))
  207. {
  208. foreach ($data['script'] as $type => $sdata)
  209. {
  210. if (!isset($this->_script[strtolower($type)]) || !stristr($this->_script[strtolower($type)], $sdata))
  211. {
  212. $this->addScriptDeclaration($sdata, $type);
  213. }
  214. }
  215. }
  216. $this->_custom = (isset($data['custom']) && !empty($data['custom']) && is_array($data['custom']))
  217. ? array_unique(array_merge($this->_custom, $data['custom']))
  218. : $this->_custom;
  219. return $this;
  220. }
  221. /**
  222. * Adds <link> tags to the head of the document
  223. *
  224. * $relType defaults to 'rel' as it is the most common relation type used.
  225. * ('rev' refers to reverse relation, 'rel' indicates normal, forward relation.)
  226. * Typical tag: <link href="index.php" rel="Start">
  227. *
  228. * @param string $href The link that is being related.
  229. * @param string $relation Relation of link.
  230. * @param string $relType Relation type attribute. Either rel or rev (default: 'rel').
  231. * @param array $attribs Associative array of remaining attributes.
  232. *
  233. * @return JDocumentHTML instance of $this to allow chaining
  234. *
  235. * @since 11.1
  236. */
  237. public function addHeadLink($href, $relation, $relType = 'rel', $attribs = array())
  238. {
  239. $this->_links[$href]['relation'] = $relation;
  240. $this->_links[$href]['relType'] = $relType;
  241. $this->_links[$href]['attribs'] = $attribs;
  242. return $this;
  243. }
  244. /**
  245. * Adds a shortcut icon (favicon)
  246. *
  247. * This adds a link to the icon shown in the favorites list or on
  248. * the left of the url in the address bar. Some browsers display
  249. * it on the tab, as well.
  250. *
  251. * @param string $href The link that is being related.
  252. * @param string $type File type
  253. * @param string $relation Relation of link
  254. *
  255. * @return JDocumentHTML instance of $this to allow chaining
  256. *
  257. * @since 11.1
  258. */
  259. public function addFavicon($href, $type = 'image/vnd.microsoft.icon', $relation = 'shortcut icon')
  260. {
  261. $href = str_replace('\\', '/', $href);
  262. $this->addHeadLink($href, $relation, 'rel', array('type' => $type));
  263. return $this;
  264. }
  265. /**
  266. * Adds a custom HTML string to the head block
  267. *
  268. * @param string $html The HTML to add to the head
  269. *
  270. * @return JDocumentHTML instance of $this to allow chaining
  271. *
  272. * @since 11.1
  273. */
  274. public function addCustomTag($html)
  275. {
  276. $this->_custom[] = trim($html);
  277. return $this;
  278. }
  279. /**
  280. * Returns whether the document is set up to be output as HTML5
  281. *
  282. * @return Boolean true when HTML5 is used
  283. *
  284. * @since 12.1
  285. */
  286. public function isHtml5()
  287. {
  288. return $this->_html5;
  289. }
  290. /**
  291. * Sets whether the document should be output as HTML5
  292. *
  293. * @param bool $state True when HTML5 should be output
  294. *
  295. * @return JDocumentHTML instance of $this to allow chaining
  296. *
  297. * @since 12.1
  298. */
  299. public function setHtml5($state)
  300. {
  301. if (is_bool($state))
  302. {
  303. $this->_html5 = $state;
  304. }
  305. return $this;
  306. }
  307. /**
  308. * Get the contents of a document include
  309. *
  310. * @param string $type The type of renderer
  311. * @param string $name The name of the element to render
  312. * @param array $attribs Associative array of remaining attributes.
  313. *
  314. * @return The output of the renderer
  315. *
  316. * @since 11.1
  317. */
  318. public function getBuffer($type = null, $name = null, $attribs = array())
  319. {
  320. // If no type is specified, return the whole buffer
  321. if ($type === null)
  322. {
  323. return parent::$_buffer;
  324. }
  325. $title = (isset($attribs['title'])) ? $attribs['title'] : null;
  326. if (isset(parent::$_buffer[$type][$name][$title]))
  327. {
  328. return parent::$_buffer[$type][$name][$title];
  329. }
  330. $renderer = $this->loadRenderer($type);
  331. if ($this->_caching == true && $type == 'modules')
  332. {
  333. $cache = JFactory::getCache('com_modules', '');
  334. $hash = md5(serialize(array($name, $attribs, null, $renderer)));
  335. $cbuffer = $cache->get('cbuffer_' . $type);
  336. if (isset($cbuffer[$hash]))
  337. {
  338. return JCache::getWorkarounds($cbuffer[$hash], array('mergehead' => 1));
  339. }
  340. else
  341. {
  342. $options = array();
  343. $options['nopathway'] = 1;
  344. $options['nomodules'] = 1;
  345. $options['modulemode'] = 1;
  346. $this->setBuffer($renderer->render($name, $attribs, null), $type, $name);
  347. $data = parent::$_buffer[$type][$name][$title];
  348. $tmpdata = JCache::setWorkarounds($data, $options);
  349. $cbuffer[$hash] = $tmpdata;
  350. $cache->store($cbuffer, 'cbuffer_' . $type);
  351. }
  352. }
  353. else
  354. {
  355. $this->setBuffer($renderer->render($name, $attribs, null), $type, $name, $title);
  356. }
  357. return parent::$_buffer[$type][$name][$title];
  358. }
  359. /**
  360. * Set the contents a document includes
  361. *
  362. * @param string $content The content to be set in the buffer.
  363. * @param array $options Array of optional elements.
  364. *
  365. * @return JDocumentHTML instance of $this to allow chaining
  366. *
  367. * @since 11.1
  368. */
  369. public function setBuffer($content, $options = array())
  370. {
  371. // The following code is just for backward compatibility.
  372. if (func_num_args() > 1 && !is_array($options))
  373. {
  374. $args = func_get_args();
  375. $options = array();
  376. $options['type'] = $args[1];
  377. $options['name'] = (isset($args[2])) ? $args[2] : null;
  378. $options['title'] = (isset($args[3])) ? $args[3] : null;
  379. }
  380. parent::$_buffer[$options['type']][$options['name']][$options['title']] = $content;
  381. return $this;
  382. }
  383. /**
  384. * Parses the template and populates the buffer
  385. *
  386. * @param array $params Parameters for fetching the template
  387. *
  388. * @return JDocumentHTML instance of $this to allow chaining
  389. *
  390. * @since 11.1
  391. */
  392. public function parse($params = array())
  393. {
  394. return $this->_fetchTemplate($params)->_parseTemplate();
  395. }
  396. /**
  397. * Outputs the template to the browser.
  398. *
  399. * @param boolean $caching If true, cache the output
  400. * @param array $params Associative array of attributes
  401. *
  402. * @return The rendered data
  403. *
  404. * @since 11.1
  405. */
  406. public function render($caching = false, $params = array())
  407. {
  408. $this->_caching = $caching;
  409. if (!empty($this->_template))
  410. {
  411. $data = $this->_renderTemplate();
  412. }
  413. else
  414. {
  415. $this->parse($params);
  416. $data = $this->_renderTemplate();
  417. }
  418. parent::render();
  419. return $data;
  420. }
  421. /**
  422. * Count the modules based on the given condition
  423. *
  424. * @param string $condition The condition to use
  425. *
  426. * @return integer Number of modules found
  427. *
  428. * @since 11.1
  429. */
  430. public function countModules($condition)
  431. {
  432. $operators = '(\+|\-|\*|\/|==|\!=|\<\>|\<|\>|\<=|\>=|and|or|xor)';
  433. $words = preg_split('# ' . $operators . ' #', $condition, null, PREG_SPLIT_DELIM_CAPTURE);
  434. if (count($words) === 1)
  435. {
  436. $name = strtolower($words[0]);
  437. $result = ((isset(parent::$_buffer['modules'][$name])) && (parent::$_buffer['modules'][$name] === false))
  438. ? 0 : count(JModuleHelper::getModules($name));
  439. return $result;
  440. }
  441. JLog::add('Using an expression in JDocumentHtml::countModules() is deprecated.', JLog::WARNING, 'deprecated');
  442. for ($i = 0, $n = count($words); $i < $n; $i += 2)
  443. {
  444. // Odd parts (modules)
  445. $name = strtolower($words[$i]);
  446. $words[$i] = ((isset(parent::$_buffer['modules'][$name])) && (parent::$_buffer['modules'][$name] === false))
  447. ? 0
  448. : count(JModuleHelper::getModules($name));
  449. }
  450. $str = 'return ' . implode(' ', $words) . ';';
  451. return eval($str);
  452. }
  453. /**
  454. * Count the number of child menu items
  455. *
  456. * @return integer Number of child menu items
  457. *
  458. * @since 11.1
  459. */
  460. public function countMenuChildren()
  461. {
  462. static $children;
  463. if (!isset($children))
  464. {
  465. $dbo = JFactory::getDbo();
  466. $app = JFactory::getApplication();
  467. $menu = $app->getMenu();
  468. $active = $menu->getActive();
  469. if ($active)
  470. {
  471. $query = $dbo->getQuery(true);
  472. $query->select('COUNT(*)');
  473. $query->from('#__menu');
  474. $query->where('parent_id = ' . $active->id);
  475. $query->where('published = 1');
  476. $dbo->setQuery($query);
  477. $children = $dbo->loadResult();
  478. }
  479. else
  480. {
  481. $children = 0;
  482. }
  483. }
  484. return $children;
  485. }
  486. /**
  487. * Load a template file
  488. *
  489. * @param string $directory The name of the template
  490. * @param string $filename The actual filename
  491. *
  492. * @return string The contents of the template
  493. *
  494. * @since 11.1
  495. */
  496. protected function _loadTemplate($directory, $filename)
  497. {
  498. // @todo remove code: $component = JApplicationHelper::getComponentName();
  499. $contents = '';
  500. // Check to see if we have a valid template file
  501. if (file_exists($directory . '/' . $filename))
  502. {
  503. // Store the file path
  504. $this->_file = $directory . '/' . $filename;
  505. // Get the file content
  506. ob_start();
  507. require $directory . '/' . $filename;
  508. $contents = ob_get_contents();
  509. ob_end_clean();
  510. }
  511. // Try to find a favicon by checking the template and root folder
  512. $path = $directory . '/';
  513. $dirs = array($path, JPATH_BASE . '/');
  514. foreach ($dirs as $dir)
  515. {
  516. $icon = $dir . 'favicon.ico';
  517. if (file_exists($icon))
  518. {
  519. $path = str_replace(JPATH_BASE . '/', '', $dir);
  520. $path = str_replace('\\', '/', $path);
  521. $this->addFavicon(JURI::base(true) . '/' . $path . 'favicon.ico');
  522. break;
  523. }
  524. }
  525. return $contents;
  526. }
  527. /**
  528. * Fetch the template, and initialise the params
  529. *
  530. * @param array $params Parameters to determine the template
  531. *
  532. * @return JDocumentHTML instance of $this to allow chaining
  533. *
  534. * @since 11.1
  535. */
  536. protected function _fetchTemplate($params = array())
  537. {
  538. // Check
  539. $directory = isset($params['directory']) ? $params['directory'] : 'templates';
  540. $filter = JFilterInput::getInstance();
  541. $template = $filter->clean($params['template'], 'cmd');
  542. $file = $filter->clean($params['file'], 'cmd');
  543. if (!file_exists($directory . '/' . $template . '/' . $file))
  544. {
  545. $template = 'system';
  546. }
  547. // Load the language file for the template
  548. $lang = JFactory::getLanguage();
  549. // 1.5 or core then 1.6
  550. $lang->load('tpl_' . $template, JPATH_BASE, null, false, false)
  551. || $lang->load('tpl_' . $template, $directory . '/' . $template, null, false, false)
  552. || $lang->load('tpl_' . $template, JPATH_BASE, $lang->getDefault(), false, false)
  553. || $lang->load('tpl_' . $template, $directory . '/' . $template, $lang->getDefault(), false, false);
  554. // Assign the variables
  555. $this->template = $template;
  556. $this->baseurl = JURI::base(true);
  557. $this->params = isset($params['params']) ? $params['params'] : new JRegistry;
  558. // Load
  559. $this->_template = $this->_loadTemplate($directory . '/' . $template, $file);
  560. return $this;
  561. }
  562. /**
  563. * Parse a document template
  564. *
  565. * @return JDocumentHTML instance of $this to allow chaining
  566. *
  567. * @since 11.1
  568. */
  569. protected function _parseTemplate()
  570. {
  571. $matches = array();
  572. if (preg_match_all('#<jdoc:include\ type="([^"]+)" (.*)\/>#iU', $this->_template, $matches))
  573. {
  574. $template_tags_first = array();
  575. $template_tags_last = array();
  576. // Step through the jdocs in reverse order.
  577. for ($i = count($matches[0]) - 1; $i >= 0; $i--)
  578. {
  579. $type = $matches[1][$i];
  580. $attribs = empty($matches[2][$i]) ? array() : JUtility::parseAttributes($matches[2][$i]);
  581. $name = isset($attribs['name']) ? $attribs['name'] : null;
  582. // Separate buffers to be executed first and last
  583. if ($type == 'module' || $type == 'modules')
  584. {
  585. $template_tags_first[$matches[0][$i]] = array('type' => $type, 'name' => $name, 'attribs' => $attribs);
  586. }
  587. else
  588. {
  589. $template_tags_last[$matches[0][$i]] = array('type' => $type, 'name' => $name, 'attribs' => $attribs);
  590. }
  591. }
  592. // Reverse the last array so the jdocs are in forward order.
  593. $template_tags_last = array_reverse($template_tags_last);
  594. $this->_template_tags = $template_tags_first + $template_tags_last;
  595. }
  596. return $this;
  597. }
  598. /**
  599. * Render pre-parsed template
  600. *
  601. * @return string rendered template
  602. *
  603. * @since 11.1
  604. */
  605. protected function _renderTemplate()
  606. {
  607. $replace = array();
  608. $with = array();
  609. foreach ($this->_template_tags as $jdoc => $args)
  610. {
  611. $replace[] = $jdoc;
  612. $with[] = $this->getBuffer($args['type'], $args['name'], $args['attribs']);
  613. }
  614. return str_replace($replace, $with, $this->_template);
  615. }
  616. }