Source for file html.php

Documentation is available at html.php

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

Documentation generated on Tue, 19 Nov 2013 15:04:54 +0100 by phpDocumentor 1.4.3