PageRenderTime 80ms CodeModel.GetById 19ms RepoModel.GetById 5ms app.codeStats 0ms

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

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