0, 'format.eol' => "\n", 'format.indent' => "\t"); /** * An array to hold included paths * * @var string[] * @since 1.5 */ protected static $includePaths = array(); /** * An array to hold method references * * @var callable[] * @since 1.6 */ protected static $registry = array(); /** * Method to extract a key * * @param string $key The name of helper method to load, (prefix).(class).function * prefix and class are optional and can be used to load custom html helpers. * * @return array Contains lowercase key, prefix, file, function. * * @since 1.6 */ protected static function extract($key) { $key = preg_replace('#[^A-Z0-9_\.]#i', '', $key); // Check to see whether we need to load a helper file $parts = explode('.', $key); $prefix = (count($parts) == 3 ? array_shift($parts) : 'JHtml'); $file = (count($parts) == 2 ? array_shift($parts) : ''); $func = array_shift($parts); return array(strtolower($prefix . '.' . $file . '.' . $func), $prefix, $file, $func); } /** * Class loader method * * Additional arguments may be supplied and are passed to the sub-class. * Additional include paths are also able to be specified for third-party use * * @param string $key The name of helper method to load, (prefix).(class).function * prefix and class are optional and can be used to load custom * html helpers. * * @return mixed Result of JHtml::call($function, $args) * * @since 1.5 * @throws InvalidArgumentException */ public static function _($key) { list($key, $prefix, $file, $func) = static::extract($key); if (array_key_exists($key, static::$registry)) { $function = static::$registry[$key]; $args = func_get_args(); // Remove function name from arguments array_shift($args); return static::call($function, $args); } $className = $prefix . ucfirst($file); if (!class_exists($className)) { $path = JPath::find(static::$includePaths, strtolower($file) . '.php'); if (!$path) { throw new InvalidArgumentException(sprintf('%s %s not found.', $prefix, $file), 500); } JLoader::register($className, $path); if (!class_exists($className)) { throw new InvalidArgumentException(sprintf('%s not found.', $className), 500); } } $toCall = array($className, $func); if (!is_callable($toCall)) { throw new InvalidArgumentException(sprintf('%s::%s not found.', $className, $func), 500); } static::register($key, $toCall); $args = func_get_args(); // Remove function name from arguments array_shift($args); return static::call($toCall, $args); } /** * Registers a function to be called with a specific key * * @param string $key The name of the key * @param string $function Function or method * * @return boolean True if the function is callable * * @since 1.6 */ public static function register($key, $function) { list($key) = static::extract($key); if (is_callable($function)) { static::$registry[$key] = $function; return true; } return false; } /** * Removes a key for a method from registry. * * @param string $key The name of the key * * @return boolean True if a set key is unset * * @since 1.6 */ public static function unregister($key) { list($key) = static::extract($key); if (isset(static::$registry[$key])) { unset(static::$registry[$key]); return true; } return false; } /** * Test if the key is registered. * * @param string $key The name of the key * * @return boolean True if the key is registered. * * @since 1.6 */ public static function isRegistered($key) { list($key) = static::extract($key); return isset(static::$registry[$key]); } /** * Function caller method * * @param callable $function Function or method to call * @param array $args Arguments to be passed to function * * @return mixed Function result or false on error. * * @see https://secure.php.net/manual/en/function.call-user-func-array.php * @since 1.6 * @throws InvalidArgumentException */ protected static function call($function, $args) { if (!is_callable($function)) { throw new InvalidArgumentException('Function not supported', 500); } // PHP 5.3 workaround $temp = array(); foreach ($args as &$arg) { $temp[] = &$arg; } return call_user_func_array($function, $temp); } /** * Write a `` element * * @param string $url The relative URL to use for the href attribute * @param string $text The target attribute to use * @param array|string $attribs Attributes to be added to the `` element * * @return string * * @since 1.5 */ public static function link($url, $text, $attribs = null) { if (is_array($attribs)) { $attribs = ArrayHelper::toString($attribs); } return '' . $text . ''; } /** * Write a `'; } /** * Include version with MD5SUM file in path. * * @param string $path Folder name to search into (images, css, js, ...). * * @return string Query string to add. * * @since 3.7.0 * * @deprecated 4.0 Usage of MD5SUM files is deprecated, use version instead. */ protected static function getMd5Version($path) { $md5 = dirname($path) . '/MD5SUM'; if (file_exists($md5)) { JLog::add('Usage of MD5SUM files is deprecated, use version instead.', JLog::WARNING, 'deprecated'); return '?' . file_get_contents($md5); } return ''; } /** * Compute the files to be included * * @param string $folder Folder name to search in (i.e. images, css, js). * @param string $file Path to file. * @param boolean $relative Flag if the path to the file is relative to the /media folder (and searches in template). * @param boolean $detect_browser Flag if the browser should be detected to include specific browser files. * @param boolean $detect_debug Flag if debug mode is enabled to include uncompressed files if debug is on. * * @return array files to be included. * * @see JBrowser * @since 1.6 */ protected static function includeRelativeFiles($folder, $file, $relative, $detect_browser, $detect_debug) { // If http is present in filename just return it as an array if (strpos($file, 'http') === 0 || strpos($file, '//') === 0) { return array($file); } // Extract extension and strip the file $strip = JFile::stripExt($file); $ext = JFile::getExt($file); // Prepare array of files $includes = array(); // Detect browser and compute potential files if ($detect_browser) { $navigator = JBrowser::getInstance(); $browser = $navigator->getBrowser(); $major = $navigator->getMajor(); $minor = $navigator->getMinor(); // Try to include files named filename.ext, filename_browser.ext, filename_browser_major.ext, filename_browser_major_minor.ext // where major and minor are the browser version names $potential = array( $strip, $strip . '_' . $browser, $strip . '_' . $browser . '_' . $major, $strip . '_' . $browser . '_' . $major . '_' . $minor, ); } else { $potential = array($strip); } // If relative search in template directory or media directory if ($relative) { // Get the template $template = JFactory::getApplication()->getTemplate(); // For each potential files foreach ($potential as $strip) { $files = array(); // Detect debug mode if ($detect_debug && JFactory::getConfig()->get('debug')) { /* * Detect if we received a file in the format name.min.ext * If so, strip the .min part out, otherwise append -uncompressed */ if (strlen($strip) > 4 && preg_match('#\.min$#', $strip)) { $files[] = preg_replace('#\.min$#', '.', $strip) . $ext; } else { $files[] = $strip . '-uncompressed.' . $ext; } } $files[] = $strip . '.' . $ext; /* * Loop on 1 or 2 files and break on first found. * Add the content of the MD5SUM file located in the same folder to URL to ensure cache browser refresh * This MD5SUM file must represent the signature of the folder content */ foreach ($files as $file) { // If the file is in the template folder $path = JPATH_THEMES . "/$template/$folder/$file"; if (file_exists($path)) { $includes[] = JUri::base(true) . "/templates/$template/$folder/$file" . static::getMd5Version($path); break; } else { // If the file contains any /: it can be in an media extension subfolder if (strpos($file, '/')) { // Divide the file extracting the extension as the first part before / list($extension, $file) = explode('/', $file, 2); // If the file yet contains any /: it can be a plugin if (strpos($file, '/')) { // Divide the file extracting the element as the first part before / list($element, $file) = explode('/', $file, 2); // Try to deal with plugins group in the media folder $path = JPATH_ROOT . "/media/$extension/$element/$folder/$file"; if (file_exists($path)) { $includes[] = JUri::root(true) . "/media/$extension/$element/$folder/$file" . static::getMd5Version($path); break; } // Try to deal with classical file in a media subfolder called element $path = JPATH_ROOT . "/media/$extension/$folder/$element/$file"; if (file_exists($path)) { $includes[] = JUri::root(true) . "/media/$extension/$folder/$element/$file" . static::getMd5Version($path); break; } // Try to deal with system files in the template folder $path = JPATH_THEMES . "/$template/$folder/system/$element/$file"; if (file_exists($path)) { $includes[] = JUri::root(true) . "/templates/$template/$folder/system/$element/$file" . static::getMd5Version($path); break; } // Try to deal with system files in the media folder $path = JPATH_ROOT . "/media/system/$folder/$element/$file"; if (file_exists($path)) { $includes[] = JUri::root(true) . "/media/system/$folder/$element/$file" . static::getMd5Version($path); break; } } else { // Try to deals in the extension media folder $path = JPATH_ROOT . "/media/$extension/$folder/$file"; if (file_exists($path)) { $includes[] = JUri::root(true) . "/media/$extension/$folder/$file" . static::getMd5Version($path); break; } // Try to deal with system files in the template folder $path = JPATH_THEMES . "/$template/$folder/system/$file"; if (file_exists($path)) { $includes[] = JUri::root(true) . "/templates/$template/$folder/system/$file" . static::getMd5Version($path); break; } // Try to deal with system files in the media folder $path = JPATH_ROOT . "/media/system/$folder/$file"; if (file_exists($path)) { $includes[] = JUri::root(true) . "/media/system/$folder/$file" . static::getMd5Version($path); break; } } } // Try to deal with system files in the media folder else { $path = JPATH_ROOT . "/media/system/$folder/$file"; if (file_exists($path)) { $includes[] = JUri::root(true) . "/media/system/$folder/$file" . static::getMd5Version($path); break; } } } } } } // If not relative and http is not present in filename else { foreach ($potential as $strip) { $files = array(); // Detect debug mode if ($detect_debug && JFactory::getConfig()->get('debug')) { /* * Detect if we received a file in the format name.min.ext * If so, strip the .min part out, otherwise append -uncompressed */ if (strlen($strip) > 4 && preg_match('#\.min$#', $strip)) { $files[] = preg_replace('#\.min$#', '.', $strip) . $ext; } else { $files[] = $strip . '-uncompressed.' . $ext; } } $files[] = $strip . '.' . $ext; /* * Loop on 1 or 2 files and break on first found. * Add the content of the MD5SUM file located in the same folder to URL to ensure cache browser refresh * This MD5SUM file must represent the signature of the folder content */ foreach ($files as $file) { $path = JPATH_ROOT . "/$file"; if (file_exists($path)) { $includes[] = JUri::root(true) . "/$file" . static::getMd5Version($path); break; } } } } return $includes; } /** * Write a `` element * * @param string $file The relative or absolute URL to use for the src attribute. * @param string $alt The alt text. * @param array|string $attribs Attributes to be added to the `` element * @param boolean $relative Flag if the path to the file is relative to the /media folder (and searches in template). * @param integer $returnPath Defines the return value for the method: * -1: Returns a `` tag without looking for relative files * 0: Returns a `` tag while searching for relative files * 1: Returns the file path to the image while searching for relative files * * @return string * * @since 1.5 */ public static function image($file, $alt, $attribs = null, $relative = false, $returnPath = 0) { $returnPath = (int) $returnPath; if ($returnPath !== -1) { $includes = static::includeRelativeFiles('images', $file, $relative, false, false); $file = count($includes) ? $includes[0] : null; } // If only path is required if ($returnPath) { return $file; } return '' . $alt . ''; } /** * Write a `` element to load a CSS file * * @param string $file Path to file * @param array $options Array of options. Example: array('version' => 'auto', 'conditional' => 'lt IE 9') * @param array $attribs Array of attributes. Example: array('id' => 'scriptid', 'async' => 'async', 'data-test' => 1) * * @return array|string|null nothing if $returnPath is false, null, path or array of path if specific CSS browser files were detected * * @see JBrowser * @since 1.5 * @deprecated 4.0 The (file, attribs, relative, pathOnly, detectBrowser, detectDebug) method signature is deprecated, * use (file, options, attributes) instead. */ public static function stylesheet($file, $options = array(), $attribs = array()) { // B/C before 3.7.0 if (!is_array($attribs)) { JLog::add('The stylesheet method signature used has changed, use (file, options, attributes) instead.', JLog::WARNING, 'deprecated'); $argList = func_get_args(); $options = array(); // Old parameters. $attribs = isset($argList[1]) ? $argList[1] : array(); $options['relative'] = isset($argList[2]) ? $argList[2] : false; $options['pathOnly'] = isset($argList[3]) ? $argList[3] : false; $options['detectBrowser'] = isset($argList[4]) ? $argList[4] : true; $options['detectDebug'] = isset($argList[5]) ? $argList[5] : true; } else { $options['relative'] = isset($options['relative']) ? $options['relative'] : false; $options['pathOnly'] = isset($options['pathOnly']) ? $options['pathOnly'] : false; $options['detectBrowser'] = isset($options['detectBrowser']) ? $options['detectBrowser'] : true; $options['detectDebug'] = isset($options['detectDebug']) ? $options['detectDebug'] : true; } $includes = static::includeRelativeFiles('css', $file, $options['relative'], $options['detectBrowser'], $options['detectDebug']); // If only path is required if ($options['pathOnly']) { if (count($includes) === 0) { return; } if (count($includes) === 1) { return $includes[0]; } return $includes; } // If inclusion is required $document = JFactory::getDocument(); foreach ($includes as $include) { // If there is already a version hash in the script reference (by using deprecated MD5SUM). if ($pos = strpos($include, '?') !== false) { $options['version'] = substr($include, $pos + 1); } $document->addStyleSheet($include, $options, $attribs); } } /** * Write a `