[ Index ]

PHP Cross Reference of Joomla 4.2.2 documentation

title

Body

[close]

/libraries/src/HTML/ -> HTMLHelper.php (source)

   1  <?php
   2  
   3  /**
   4   * Joomla! Content Management System
   5   *
   6   * @copyright  (C) 2005 Open Source Matters, Inc. <https://www.joomla.org>
   7   * @license    GNU General Public License version 2 or later; see LICENSE.txt
   8   */
   9  
  10  namespace Joomla\CMS\HTML;
  11  
  12  use Joomla\CMS\Environment\Browser;
  13  use Joomla\CMS\Factory;
  14  use Joomla\CMS\Filesystem\File;
  15  use Joomla\CMS\Filesystem\Path;
  16  use Joomla\CMS\Language\Text;
  17  use Joomla\CMS\Layout\LayoutHelper;
  18  use Joomla\CMS\Uri\Uri;
  19  use Joomla\Utilities\ArrayHelper;
  20  
  21  // phpcs:disable PSR1.Files.SideEffects
  22  \defined('JPATH_PLATFORM') or die;
  23  // phpcs:enable PSR1.Files.SideEffects
  24  
  25  /**
  26   * Utility class for all HTML drawing classes
  27   *
  28   * @since  1.5
  29   */
  30  abstract class HTMLHelper
  31  {
  32      /**
  33       * Option values related to the generation of HTML output. Recognized
  34       * options are:
  35       *     fmtDepth, integer. The current indent depth.
  36       *     fmtEol, string. The end of line string, default is linefeed.
  37       *     fmtIndent, string. The string to use for indentation, default is
  38       *     tab.
  39       *
  40       * @var    array
  41       * @since  1.5
  42       */
  43      public static $formatOptions = array('format.depth' => 0, 'format.eol' => "\n", 'format.indent' => "\t");
  44  
  45      /**
  46       * An array to hold included paths
  47       *
  48       * @var    string[]
  49       * @since  1.5
  50       * @deprecated  5.0
  51       */
  52      protected static $includePaths = array();
  53  
  54      /**
  55       * An array to hold method references
  56       *
  57       * @var    callable[]
  58       * @since  1.6
  59       * @deprecated  5.0
  60       */
  61      protected static $registry = array();
  62  
  63      /**
  64       * The service registry for custom and overridden JHtml helpers
  65       *
  66       * @var    Registry
  67       * @since  4.0.0
  68       */
  69      protected static $serviceRegistry;
  70  
  71      /**
  72       * Method to extract a key
  73       *
  74       * @param   string  $key  The name of helper method to load, (prefix).(class).function
  75       *                        prefix and class are optional and can be used to load custom html helpers.
  76       *
  77       * @return  array  Contains lowercase key, prefix, file, function.
  78       *
  79       * @since       1.6
  80       * @deprecated  5.0 Use the service registry instead
  81       */
  82      protected static function extract($key)
  83      {
  84          $key = preg_replace('#[^A-Z0-9_\.]#i', '', $key);
  85  
  86          // Check to see whether we need to load a helper file
  87          $parts = explode('.', $key);
  88  
  89          if (\count($parts) === 3) {
  90              @trigger_error(
  91                  'Support for a three segment service key is deprecated and will be removed in Joomla 5.0, use the service registry instead',
  92                  E_USER_DEPRECATED
  93              );
  94          }
  95  
  96          $prefix = \count($parts) === 3 ? array_shift($parts) : 'JHtml';
  97          $file   = \count($parts) === 2 ? array_shift($parts) : '';
  98          $func   = array_shift($parts);
  99  
 100          return array(strtolower($prefix . '.' . $file . '.' . $func), $prefix, $file, $func);
 101      }
 102  
 103      /**
 104       * Class loader method
 105       *
 106       * Additional arguments may be supplied and are passed to the sub-class.
 107       * Additional include paths are also able to be specified for third-party use
 108       *
 109       * @param   string  $key         The name of helper method to load, (prefix).(class).function
 110       *                               prefix and class are optional and can be used to load custom
 111       *                               html helpers.
 112       * @param   array   $methodArgs  The arguments to pass forward to the method being called
 113       *
 114       * @return  mixed  Result of HTMLHelper::call($function, $args)
 115       *
 116       * @since   1.5
 117       * @throws  \InvalidArgumentException
 118       */
 119      final public static function _(string $key, ...$methodArgs)
 120      {
 121          list($key, $prefix, $file, $func) = static::extract($key);
 122  
 123          if (\array_key_exists($key, static::$registry)) {
 124              $function = static::$registry[$key];
 125  
 126              return static::call($function, $methodArgs);
 127          }
 128  
 129          /*
 130           * Support fetching services from the registry if a custom class prefix was not given (a three segment key),
 131           * the service comes from a class other than this one, and a service has been registered for the file.
 132           */
 133          if ($prefix === 'JHtml' && $file !== '' && static::getServiceRegistry()->hasService($file)) {
 134              $service = static::getServiceRegistry()->getService($file);
 135  
 136              $toCall = array($service, $func);
 137  
 138              if (!\is_callable($toCall)) {
 139                  throw new \InvalidArgumentException(sprintf('%s::%s not found.', $file, $func), 500);
 140              }
 141  
 142              static::register($key, $toCall);
 143  
 144              return static::call($toCall, $methodArgs);
 145          }
 146  
 147          $className = $prefix . ucfirst($file);
 148  
 149          if (!class_exists($className)) {
 150              $path = Path::find(static::$includePaths, strtolower($file) . '.php');
 151  
 152              if (!$path) {
 153                  throw new \InvalidArgumentException(sprintf('%s %s not found.', $prefix, $file), 500);
 154              }
 155  
 156              \JLoader::register($className, $path);
 157  
 158              if (!class_exists($className)) {
 159                  throw new \InvalidArgumentException(sprintf('%s not found.', $className), 500);
 160              }
 161          }
 162  
 163          // If calling a method from this class, do not allow access to internal methods
 164          if ($className === __CLASS__) {
 165              if (!((new \ReflectionMethod($className, $func))->isPublic())) {
 166                  throw new \InvalidArgumentException('Access to internal class methods is not allowed.');
 167              }
 168          }
 169  
 170          $toCall = array($className, $func);
 171  
 172          if (!\is_callable($toCall)) {
 173              throw new \InvalidArgumentException(sprintf('%s::%s not found.', $className, $func), 500);
 174          }
 175  
 176          static::register($key, $toCall);
 177  
 178          return static::call($toCall, $methodArgs);
 179      }
 180  
 181      /**
 182       * Registers a function to be called with a specific key
 183       *
 184       * @param   string    $key       The name of the key
 185       * @param   callable  $function  Function or method
 186       *
 187       * @return  boolean  True if the function is callable
 188       *
 189       * @since       1.6
 190       * @deprecated  5.0 Use the service registry instead
 191       */
 192      public static function register($key, callable $function)
 193      {
 194          @trigger_error(
 195              'Support for registering functions is deprecated and will be removed in Joomla 5.0, use the service registry instead',
 196              E_USER_DEPRECATED
 197          );
 198  
 199          list($key) = static::extract($key);
 200  
 201          static::$registry[$key] = $function;
 202  
 203          return true;
 204      }
 205  
 206      /**
 207       * Removes a key for a method from registry.
 208       *
 209       * @param   string  $key  The name of the key
 210       *
 211       * @return  boolean  True if a set key is unset
 212       *
 213       * @since       1.6
 214       * @deprecated  5.0 Use the service registry instead
 215       */
 216      public static function unregister($key)
 217      {
 218          @trigger_error(
 219              'Support for registering functions is deprecated and will be removed in Joomla 5.0, use the service registry instead',
 220              E_USER_DEPRECATED
 221          );
 222  
 223          list($key) = static::extract($key);
 224  
 225          if (isset(static::$registry[$key])) {
 226              unset(static::$registry[$key]);
 227  
 228              return true;
 229          }
 230  
 231          return false;
 232      }
 233  
 234      /**
 235       * Test if the key is registered.
 236       *
 237       * @param   string  $key  The name of the key
 238       *
 239       * @return  boolean  True if the key is registered.
 240       *
 241       * @since   1.6
 242       */
 243      public static function isRegistered($key)
 244      {
 245          list($key) = static::extract($key);
 246  
 247          return isset(static::$registry[$key]);
 248      }
 249  
 250      /**
 251       * Retrieves the service registry.
 252       *
 253       * @return  Registry
 254       *
 255       * @since   4.0.0
 256       */
 257      public static function getServiceRegistry(): Registry
 258      {
 259          if (!static::$serviceRegistry) {
 260              static::$serviceRegistry = Factory::getContainer()->get(Registry::class);
 261          }
 262  
 263          return static::$serviceRegistry;
 264      }
 265  
 266      /**
 267       * Function caller method
 268       *
 269       * @param   callable  $function  Function or method to call
 270       * @param   array     $args      Arguments to be passed to function
 271       *
 272       * @return  mixed   Function result or false on error.
 273       *
 274       * @link    https://www.php.net/manual/en/function.call-user-func-array.php
 275       * @since   1.6
 276       * @throws  \InvalidArgumentException
 277       */
 278      protected static function call(callable $function, $args)
 279      {
 280          // Workaround to allow calling helper methods have arguments passed by reference
 281          $temp = [];
 282  
 283          foreach ($args as &$arg) {
 284              $temp[] = &$arg;
 285          }
 286  
 287          return \call_user_func_array($function, $temp);
 288      }
 289  
 290      /**
 291       * Write a `<a>` element
 292       *
 293       * @param   string        $url      The relative URL to use for the href attribute
 294       * @param   string        $text     The target attribute to use
 295       * @param   array|string  $attribs  Attributes to be added to the `<a>` element
 296       *
 297       * @return  string
 298       *
 299       * @since   1.5
 300       */
 301      public static function link($url, $text, $attribs = null)
 302      {
 303          if (\is_array($attribs)) {
 304              $attribs = ArrayHelper::toString($attribs);
 305          }
 306  
 307          return '<a href="' . $url . '" ' . $attribs . '>' . $text . '</a>';
 308      }
 309  
 310      /**
 311       * Write a `<iframe>` element
 312       *
 313       * @param   string        $url       The relative URL to use for the src attribute.
 314       * @param   string        $name      The target attribute to use.
 315       * @param   array|string  $attribs   Attributes to be added to the `<iframe>` element
 316       * @param   string        $noFrames  The message to display if the iframe tag is not supported.
 317       *
 318       * @return  string
 319       *
 320       * @since   1.5
 321       */
 322      public static function iframe($url, $name, $attribs = null, $noFrames = '')
 323      {
 324          if (\is_array($attribs)) {
 325              $attribs = ArrayHelper::toString($attribs);
 326          }
 327  
 328          return '<iframe src="' . $url . '" ' . $attribs . ' name="' . $name . '">' . $noFrames . '</iframe>';
 329      }
 330  
 331      /**
 332       * Compute the files to be included
 333       *
 334       * @param   string   $folder         Folder name to search in (i.e. images, css, js).
 335       * @param   string   $file           Path to file.
 336       * @param   boolean  $relative       Flag if the path to the file is relative to the /media folder (and searches in template).
 337       * @param   boolean  $detectBrowser  Flag if the browser should be detected to include specific browser files.
 338       * @param   boolean  $detectDebug    Flag if debug mode is enabled to include uncompressed files if debug is on.
 339       *
 340       * @return  array    files to be included.
 341       *
 342       * @see     Browser
 343       * @since   1.6
 344       */
 345      protected static function includeRelativeFiles($folder, $file, $relative, $detectBrowser, $detectDebug)
 346      {
 347          // Set debug flag
 348          $debugMode = false;
 349  
 350          // Detect debug mode
 351          if ($detectDebug && JDEBUG) {
 352              $debugMode = true;
 353          }
 354  
 355          // If http is present in filename
 356          if (strpos($file, 'http') === 0 || strpos($file, '//') === 0) {
 357              $includes = [$file];
 358          } else {
 359              // Extract extension and strip the file
 360              $strip = File::stripExt($file);
 361              $ext   = File::getExt($file);
 362  
 363              // Prepare array of files
 364              $includes = [];
 365  
 366              // Detect browser and compute potential files
 367              if ($detectBrowser) {
 368                  $navigator = Browser::getInstance();
 369                  $browser   = $navigator->getBrowser();
 370                  $major     = $navigator->getMajor();
 371                  $minor     = $navigator->getMinor();
 372                  $minExt    = '';
 373  
 374                  if (\strlen($strip) > 4 && preg_match('#\.min$#', $strip)) {
 375                      $minExt    = '.min';
 376                      $strip = preg_replace('#\.min$#', '', $strip);
 377                  }
 378  
 379                  // Try to include files named filename.ext, filename_browser.ext, filename_browser_major.ext, filename_browser_major_minor.ext
 380                  // where major and minor are the browser version names
 381                  $potential = [
 382                      $strip . $minExt,
 383                      $strip . '_' . $browser . $minExt,
 384                      $strip . '_' . $browser . '_' . $major . $minExt,
 385                      $strip . '_' . $browser . '_' . $major . '_' . $minor . $minExt,
 386                  ];
 387              } else {
 388                  $potential = [$strip];
 389              }
 390  
 391              // If relative search in template directory or media directory
 392              if ($relative) {
 393                  $app        = Factory::getApplication();
 394                  $template   = $app->getTemplate(true);
 395                  $templaPath = JPATH_THEMES;
 396  
 397                  if ($template->inheritable || !empty($template->parent)) {
 398                      $client     = $app->isClient('administrator') === true ? 'administrator' : 'site';
 399                      $templaPath = JPATH_ROOT . "/media/templates/$client";
 400                  }
 401  
 402                  // For each potential files
 403                  foreach ($potential as $strip) {
 404                      $files = [];
 405                      $files[] = $strip . '.' . $ext;
 406  
 407                      /**
 408                       * Loop on 1 or 2 files and break on first found.
 409                       * Add the content of the MD5SUM file located in the same folder to url to ensure cache browser refresh
 410                       * This MD5SUM file must represent the signature of the folder content
 411                       */
 412                      foreach ($files as $file) {
 413                          if (!empty($template->parent)) {
 414                              $found = static::addFileToBuffer("$templaPath/$template->template/$folder/$file", $ext, $debugMode);
 415  
 416                              if (empty($found)) {
 417                                  $found = static::addFileToBuffer("$templaPath/$template->parent/$folder/$file", $ext, $debugMode);
 418                              }
 419                          } else {
 420                              $found = static::addFileToBuffer("$templaPath/$template->template/$folder/$file", $ext, $debugMode);
 421                          }
 422  
 423                          if (!empty($found)) {
 424                              $includes[] = $found;
 425  
 426                              break;
 427                          } else {
 428                              // If the file contains any /: it can be in a media extension subfolder
 429                              if (strpos($file, '/')) {
 430                                  // Divide the file extracting the extension as the first part before /
 431                                  list($extension, $file) = explode('/', $file, 2);
 432  
 433                                  // If the file yet contains any /: it can be a plugin
 434                                  if (strpos($file, '/')) {
 435                                      // Divide the file extracting the element as the first part before /
 436                                      list($element, $file) = explode('/', $file, 2);
 437  
 438                                      // Try to deal with plugins group in the media folder
 439                                      $found = static::addFileToBuffer(JPATH_ROOT . "/media/$extension/$element/$folder/$file", $ext, $debugMode);
 440  
 441                                      if (!empty($found)) {
 442                                          $includes[] = $found;
 443  
 444                                          break;
 445                                      }
 446  
 447                                      // Try to deal with classical file in a media subfolder called element
 448                                      $found = static::addFileToBuffer(JPATH_ROOT . "/media/$extension/$folder/$element/$file", $ext, $debugMode);
 449  
 450                                      if (!empty($found)) {
 451                                          $includes[] = $found;
 452  
 453                                          break;
 454                                      }
 455  
 456                                      // Try to deal with system files in the template folder
 457                                      if (!empty($template->parent)) {
 458                                          $found = static::addFileToBuffer("$templaPath/$template->template/$folder/system/$element/$file", $ext, $debugMode);
 459  
 460                                          if (!empty($found)) {
 461                                              $includes[] = $found;
 462  
 463                                              break;
 464                                          }
 465  
 466                                          $found = static::addFileToBuffer("$templaPath/$template->parent/$folder/system/$element/$file", $ext, $debugMode);
 467  
 468                                          if (!empty($found)) {
 469                                              $includes[] = $found;
 470  
 471                                              break;
 472                                          }
 473                                      } else {
 474                                          // Try to deal with system files in the media folder
 475                                          $found = static::addFileToBuffer(JPATH_ROOT . "/media/system/$folder/$element/$file", $ext, $debugMode);
 476  
 477                                          if (!empty($found)) {
 478                                              $includes[] = $found;
 479  
 480                                              break;
 481                                          }
 482                                      }
 483                                  } else {
 484                                      // Try to deal with files in the extension's media folder
 485                                      $found = static::addFileToBuffer(JPATH_ROOT . "/media/$extension/$folder/$file", $ext, $debugMode);
 486  
 487                                      if (!empty($found)) {
 488                                          $includes[] = $found;
 489  
 490                                          break;
 491                                      }
 492  
 493                                      // Try to deal with system files in the template folder
 494                                      if (!empty($template->parent)) {
 495                                          $found = static::addFileToBuffer("$templaPath/$template->template/$folder/system/$file", $ext, $debugMode);
 496  
 497                                          if (!empty($found)) {
 498                                              $includes[] = $found;
 499  
 500                                              break;
 501                                          }
 502  
 503                                          $found = static::addFileToBuffer("$templaPath/$template->parent/$folder/system/$file", $ext, $debugMode);
 504  
 505                                          if (!empty($found)) {
 506                                              $includes[] = $found;
 507  
 508                                              break;
 509                                          }
 510                                      } else {
 511                                          // Try to deal with system files in the template folder
 512                                          $found = static::addFileToBuffer("$templaPath/$template->template/$folder/system/$file", $ext, $debugMode);
 513  
 514                                          if (!empty($found)) {
 515                                              $includes[] = $found;
 516  
 517                                              break;
 518                                          }
 519                                      }
 520  
 521                                      // Try to deal with system files in the media folder
 522                                      $found = static::addFileToBuffer(JPATH_ROOT . "/media/system/$folder/$file", $ext, $debugMode);
 523  
 524                                      if (!empty($found)) {
 525                                          $includes[] = $found;
 526  
 527                                          break;
 528                                      }
 529                                  }
 530                              } else {
 531                                  // Try to deal with system files in the media folder
 532                                  $found = static::addFileToBuffer(JPATH_ROOT . "/media/system/$folder/$file", $ext, $debugMode);
 533  
 534                                  if (!empty($found)) {
 535                                      $includes[] = $found;
 536  
 537                                      break;
 538                                  }
 539                              }
 540                          }
 541                      }
 542                  }
 543              } else {
 544                  // If not relative and http is not present in filename
 545                  foreach ($potential as $strip) {
 546                      $files = [];
 547  
 548                      $files[] = $strip . '.' . $ext;
 549  
 550                      /**
 551                       * Loop on 1 or 2 files and break on first found.
 552                       * Add the content of the MD5SUM file located in the same folder to url to ensure cache browser refresh
 553                       * This MD5SUM file must represent the signature of the folder content
 554                       */
 555                      foreach ($files as $file) {
 556                          $path = JPATH_ROOT . "/$file";
 557  
 558                          $found = static::addFileToBuffer($path, $ext, $debugMode);
 559  
 560                          if (!empty($found)) {
 561                              $includes[] = $found;
 562  
 563                              break;
 564                          }
 565                      }
 566                  }
 567              }
 568          }
 569  
 570          return $includes;
 571      }
 572  
 573      /**
 574       * Gets a URL, cleans the Joomla specific params and returns an object
 575       *
 576       * @param    string  $url  The relative or absolute URL to use for the src attribute.
 577       *
 578       * @return   object
 579       * @example  {
 580       *             url: 'string',
 581       *             attributes: [
 582       *               width:  integer,
 583       *               height: integer,
 584       *             ]
 585       *           }
 586       *
 587       * @since    4.0.0
 588       */
 589      public static function cleanImageURL($url)
 590      {
 591          $obj = new \stdClass();
 592  
 593          $obj->attributes = [
 594              'width'  => 0,
 595              'height' => 0,
 596          ];
 597  
 598          if ($url === null) {
 599              $url = '';
 600          }
 601  
 602          if (!strpos($url, '?')) {
 603              $obj->url = $url;
 604  
 605              return $obj;
 606          }
 607  
 608          $mediaUri = new Uri($url);
 609  
 610          // Old image URL format
 611          if ($mediaUri->hasVar('joomla_image_height')) {
 612              $height = (int) $mediaUri->getVar('joomla_image_height');
 613              $width  = (int) $mediaUri->getVar('joomla_image_width');
 614  
 615              $mediaUri->delVar('joomla_image_height');
 616              $mediaUri->delVar('joomla_image_width');
 617          } else {
 618              // New Image URL format
 619              $fragmentUri = new Uri($mediaUri->getFragment());
 620              $width       = (int) $fragmentUri->getVar('width', 0);
 621              $height      = (int) $fragmentUri->getVar('height', 0);
 622          }
 623  
 624          if ($width > 0) {
 625              $obj->attributes['width'] = $width;
 626          }
 627  
 628          if ($height > 0) {
 629              $obj->attributes['height'] = $height;
 630          }
 631  
 632          $mediaUri->setFragment('');
 633          $obj->url = $mediaUri->toString();
 634  
 635          return $obj;
 636      }
 637  
 638      /**
 639       * Write a `<img>` element
 640       *
 641       * @param   string        $file        The relative or absolute URL to use for the src attribute.
 642       * @param   string        $alt         The alt text.
 643       * @param   array|string  $attribs     Attributes to be added to the `<img>` element
 644       * @param   boolean       $relative    Flag if the path to the file is relative to the /media folder (and searches in template).
 645       * @param   integer       $returnPath  Defines the return value for the method:
 646       *                                     -1: Returns a `<img>` tag without looking for relative files
 647       *                                     0: Returns a `<img>` tag while searching for relative files
 648       *                                     1: Returns the file path to the image while searching for relative files
 649       *
 650       * @return  string|null  HTML markup for the image, relative path to the image, or null if path is to be returned but image is not found
 651       *
 652       * @since   1.5
 653       */
 654      public static function image($file, $alt, $attribs = null, $relative = false, $returnPath = 0)
 655      {
 656          // Ensure is an integer
 657          $returnPath = (int) $returnPath;
 658  
 659          // The path of the file
 660          $path = $file;
 661  
 662          // The arguments of the file path
 663          $arguments = '';
 664  
 665          // Get the arguments positions
 666          $pos1 = strpos($file, '?');
 667          $pos2 = strpos($file, '#');
 668  
 669          // Check if there are arguments
 670          if ($pos1 !== false || $pos2 !== false) {
 671              // Get the path only
 672              $path = substr($file, 0, min($pos1, $pos2));
 673  
 674              // Determine the arguments is mostly the part behind the #
 675              $arguments = str_replace($path, '', $file);
 676          }
 677  
 678          // Get the relative file name when requested
 679          if ($returnPath !== -1) {
 680              // Search for relative file names
 681              $includes = static::includeRelativeFiles('images', $path, $relative, false, false);
 682  
 683              // Grab the first found path and if none exists default to null
 684              $path = \count($includes) ? $includes[0] : null;
 685          }
 686  
 687          // Compile the file name
 688          $file = ($path === null ? null : $path . $arguments);
 689  
 690          // If only the file is required, return here
 691          if ($returnPath === 1) {
 692              return $file;
 693          }
 694  
 695          // Ensure we have a valid default for concatenating
 696          if ($attribs === null || $attribs === false) {
 697              $attribs = [];
 698          }
 699  
 700          // When it is a string, we need convert it to an array
 701          if (is_string($attribs)) {
 702              $attributes = [];
 703  
 704              // Go through each argument
 705              foreach (explode(' ', $attribs) as $attribute) {
 706                  // When an argument without a value, default to an empty string
 707                  if (strpos($attribute, '=') === false) {
 708                      $attributes[$attribute] = '';
 709                      continue;
 710                  }
 711  
 712                  // Set the attribute
 713                  list($key, $value) = explode('=', $attribute);
 714                  $attributes[$key]  = trim($value, '"');
 715              }
 716  
 717              // Add the attributes from the string to the original attributes
 718              $attribs = $attributes;
 719          }
 720  
 721          // Fill the attributes with the file and alt text
 722          $attribs['src'] = $file;
 723          $attribs['alt'] = $alt;
 724  
 725          // Render the layout with the attributes
 726          return LayoutHelper::render('joomla.html.image', $attribs);
 727      }
 728  
 729      /**
 730       * Write a `<link>` element to load a CSS file
 731       *
 732       * @param   string  $file     Path to file
 733       * @param   array   $options  Array of options. Example: array('version' => 'auto', 'conditional' => 'lt IE 9')
 734       * @param   array   $attribs  Array of attributes. Example: array('id' => 'scriptid', 'async' => 'async', 'data-test' => 1)
 735       *
 736       * @return  array|string|null  nothing if $returnPath is false, null, path or array of path if specific CSS browser files were detected
 737       *
 738       * @see   Browser
 739       * @since 1.5
 740       */
 741      public static function stylesheet($file, $options = array(), $attribs = array())
 742      {
 743          $options['relative']      = $options['relative'] ?? false;
 744          $options['pathOnly']      = $options['pathOnly'] ?? false;
 745          $options['detectBrowser'] = $options['detectBrowser'] ?? false;
 746          $options['detectDebug']   = $options['detectDebug'] ?? true;
 747  
 748          $includes = static::includeRelativeFiles('css', $file, $options['relative'], $options['detectBrowser'], $options['detectDebug']);
 749  
 750          // If only path is required
 751          if ($options['pathOnly']) {
 752              if (\count($includes) === 0) {
 753                  return;
 754              }
 755  
 756              if (\count($includes) === 1) {
 757                  return $includes[0];
 758              }
 759  
 760              return $includes;
 761          }
 762  
 763          // If inclusion is required
 764          $document = Factory::getApplication()->getDocument();
 765  
 766          foreach ($includes as $include) {
 767              // If there is already a version hash in the script reference (by using deprecated MD5SUM).
 768              if ($pos = strpos($include, '?') !== false) {
 769                  $options['version'] = substr($include, $pos + 1);
 770              }
 771  
 772              $document->addStyleSheet($include, $options, $attribs);
 773          }
 774      }
 775  
 776      /**
 777       * Write a `<script>` element to load a JavaScript file
 778       *
 779       * @param   string  $file     Path to file.
 780       * @param   array   $options  Array of options. Example: array('version' => 'auto', 'conditional' => 'lt IE 9')
 781       * @param   array   $attribs  Array of attributes. Example: array('id' => 'scriptid', 'async' => 'async', 'data-test' => 1)
 782       *
 783       * @return  array|string|null  Nothing if $returnPath is false, null, path or array of path if specific JavaScript browser files were detected
 784       *
 785       * @see   HTMLHelper::stylesheet()
 786       * @since 1.5
 787       */
 788      public static function script($file, $options = array(), $attribs = array())
 789      {
 790          $options['relative']      = $options['relative'] ?? false;
 791          $options['pathOnly']      = $options['pathOnly'] ?? false;
 792          $options['detectBrowser'] = $options['detectBrowser'] ?? false;
 793          $options['detectDebug']   = $options['detectDebug'] ?? true;
 794  
 795          $includes = static::includeRelativeFiles('js', $file, $options['relative'], $options['detectBrowser'], $options['detectDebug']);
 796  
 797          // If only path is required
 798          if ($options['pathOnly']) {
 799              if (\count($includes) === 0) {
 800                  return;
 801              }
 802  
 803              if (\count($includes) === 1) {
 804                  return $includes[0];
 805              }
 806  
 807              return $includes;
 808          }
 809  
 810          // If inclusion is required
 811          $document = Factory::getApplication()->getDocument();
 812  
 813          foreach ($includes as $include) {
 814              // If there is already a version hash in the script reference (by using deprecated MD5SUM).
 815              if ($pos = strpos($include, '?') !== false) {
 816                  $options['version'] = substr($include, $pos + 1);
 817              }
 818  
 819              $document->addScript($include, $options, $attribs);
 820          }
 821      }
 822  
 823      /**
 824       * Set format related options.
 825       *
 826       * Updates the formatOptions array with all valid values in the passed array.
 827       *
 828       * @param   array  $options  Option key/value pairs.
 829       *
 830       * @return  void
 831       *
 832       * @see     HTMLHelper::$formatOptions
 833       * @since   1.5
 834       */
 835      public static function setFormatOptions($options)
 836      {
 837          foreach ($options as $key => $val) {
 838              if (isset(static::$formatOptions[$key])) {
 839                  static::$formatOptions[$key] = $val;
 840              }
 841          }
 842      }
 843  
 844      /**
 845       * Returns formatted date according to a given format and time zone.
 846       *
 847       * @param   string   $input      String in a format accepted by date(), defaults to "now".
 848       * @param   string   $format     The date format specification string (see {@link PHP_MANUAL#date}).
 849       * @param   mixed    $tz         Time zone to be used for the date.  Special cases: boolean true for user
 850       *                               setting, boolean false for server setting.
 851       * @param   boolean  $gregorian  True to use Gregorian calendar.
 852       *
 853       * @return  string    A date translated by the given format and time zone.
 854       *
 855       * @see     strftime
 856       * @since   1.5
 857       */
 858      public static function date($input = 'now', $format = null, $tz = true, $gregorian = false)
 859      {
 860          $app = Factory::getApplication();
 861  
 862          // UTC date converted to user time zone.
 863          if ($tz === true) {
 864              // Get a date object based on UTC.
 865              $date = Factory::getDate($input, 'UTC');
 866  
 867              // Set the correct time zone based on the user configuration.
 868              $date->setTimezone($app->getIdentity()->getTimezone());
 869          } elseif ($tz === false) {
 870              // UTC date converted to server time zone.
 871              // Get a date object based on UTC.
 872              $date = Factory::getDate($input, 'UTC');
 873  
 874              // Set the correct time zone based on the server configuration.
 875              $date->setTimezone(new \DateTimeZone($app->get('offset')));
 876          } elseif ($tz === null) {
 877              // No date conversion.
 878              $date = Factory::getDate($input);
 879          } else {
 880              // UTC date converted to given time zone.
 881              // Get a date object based on UTC.
 882              $date = Factory::getDate($input, 'UTC');
 883  
 884              // Set the correct time zone based on the server configuration.
 885              $date->setTimezone(new \DateTimeZone($tz));
 886          }
 887  
 888          // If no format is given use the default locale based format.
 889          if (!$format) {
 890              $format = Text::_('DATE_FORMAT_LC1');
 891          } elseif (Factory::getLanguage()->hasKey($format)) {
 892              // $format is an existing language key
 893              $format = Text::_($format);
 894          }
 895  
 896          if ($gregorian) {
 897              return $date->format($format, true);
 898          }
 899  
 900          return $date->calendar($format, true);
 901      }
 902  
 903      /**
 904       * Creates a tooltip with an image as button
 905       *
 906       * @param   string  $tooltip  The tip string.
 907       * @param   mixed   $title    The title of the tooltip or an associative array with keys contained in
 908       *                            {'title','image','text','href','alt'} and values corresponding to parameters of the same name.
 909       * @param   string  $image    The image for the tip, if no text is provided.
 910       * @param   string  $text     The text for the tip.
 911       * @param   string  $href     A URL that will be used to create the link.
 912       * @param   string  $alt      The alt attribute for img tag.
 913       * @param   string  $class    CSS class for the tool tip.
 914       *
 915       * @return  string
 916       *
 917       * @since   1.5
 918       */
 919      public static function tooltip($tooltip, $title = '', $image = 'tooltip.png', $text = '', $href = '', $alt = 'Tooltip', $class = 'hasTooltip')
 920      {
 921          if (\is_array($title)) {
 922              foreach (array('image', 'text', 'href', 'alt', 'class') as $param) {
 923                  if (isset($title[$param])) {
 924                      $$param = $title[$param];
 925                  }
 926              }
 927  
 928              if (isset($title['title'])) {
 929                  $title = $title['title'];
 930              } else {
 931                  $title = '';
 932              }
 933          }
 934  
 935          if (!$text) {
 936              $alt = htmlspecialchars($alt, ENT_COMPAT, 'UTF-8');
 937              $text = static::image($image, $alt, null, true);
 938          }
 939  
 940          if ($href) {
 941              $tip = '<a href="' . $href . '">' . $text . '</a>';
 942          } else {
 943              $tip = $text;
 944          }
 945  
 946          if ($class === 'hasTip') {
 947              // Still using MooTools tooltips!
 948              $tooltip = htmlspecialchars($tooltip, ENT_COMPAT, 'UTF-8');
 949  
 950              if ($title) {
 951                  $title = htmlspecialchars($title, ENT_COMPAT, 'UTF-8');
 952                  $tooltip = $title . '::' . $tooltip;
 953              }
 954          } else {
 955              $tooltip = self::tooltipText($title, $tooltip, 0);
 956          }
 957  
 958          return '<span class="' . $class . '" title="' . $tooltip . '">' . $tip . '</span>';
 959      }
 960  
 961      /**
 962       * Converts a double colon separated string or 2 separate strings to a string ready for bootstrap tooltips
 963       *
 964       * @param   string   $title      The title of the tooltip (or combined '::' separated string).
 965       * @param   string   $content    The content to tooltip.
 966       * @param   boolean  $translate  If true will pass texts through Text.
 967       * @param   boolean  $escape     If true will pass texts through htmlspecialchars.
 968       *
 969       * @return  string  The tooltip string
 970       *
 971       * @since   3.1.2
 972       */
 973      public static function tooltipText($title = '', $content = '', $translate = true, $escape = true)
 974      {
 975          // Initialise return value.
 976          $result = '';
 977  
 978          // Don't process empty strings
 979          if ($content !== '' || $title !== '') {
 980              // Split title into title and content if the title contains '::' (old Mootools format).
 981              if ($content === '' && !(strpos($title, '::') === false)) {
 982                  list($title, $content) = explode('::', $title, 2);
 983              }
 984  
 985              // Pass texts through Text if required.
 986              if ($translate) {
 987                  $title = Text::_($title);
 988                  $content = Text::_($content);
 989              }
 990  
 991              // Use only the content if no title is given.
 992              if ($title === '') {
 993                  $result = $content;
 994              } elseif ($title === $content) {
 995                  // Use only the title, if title and text are the same.
 996                  $result = '<strong>' . $title . '</strong>';
 997              } elseif ($content !== '') {
 998                  // Use a formatted string combining the title and content.
 999                  $result = '<strong>' . $title . '</strong><br>' . $content;
1000              } else {
1001                  $result = $title;
1002              }
1003  
1004              // Escape everything, if required.
1005              if ($escape) {
1006                  $result = htmlspecialchars($result);
1007              }
1008          }
1009  
1010          return $result;
1011      }
1012  
1013      /**
1014       * Displays a calendar control field
1015       *
1016       * @param   string  $value    The date value
1017       * @param   string  $name     The name of the text field
1018       * @param   string  $id       The id of the text field
1019       * @param   string  $format   The date format
1020       * @param   mixed   $attribs  Additional HTML attributes
1021       *                            The array can have the following keys:
1022       *                            readonly      Sets the readonly parameter for the input tag
1023       *                            disabled      Sets the disabled parameter for the input tag
1024       *                            autofocus     Sets the autofocus parameter for the input tag
1025       *                            autocomplete  Sets the autocomplete parameter for the input tag
1026       *                            filter        Sets the filter for the input tag
1027       *
1028       * @return  string  HTML markup for a calendar field
1029       *
1030       * @since   1.5
1031       *
1032       */
1033      public static function calendar($value, $name, $id, $format = '%Y-%m-%d', $attribs = array())
1034      {
1035          $app       = Factory::getApplication();
1036          $lang      = $app->getLanguage();
1037          $tag       = $lang->getTag();
1038          $calendar  = $lang->getCalendar();
1039          $direction = strtolower($app->getDocument()->getDirection());
1040  
1041          // Get the appropriate file for the current language date helper
1042          $helperPath = 'system/fields/calendar-locales/date/gregorian/date-helper.min.js';
1043  
1044          if ($calendar && is_dir(JPATH_ROOT . '/media/system/js/fields/calendar-locales/date/' . strtolower($calendar))) {
1045              $helperPath = 'system/fields/calendar-locales/date/' . strtolower($calendar) . '/date-helper.min.js';
1046          }
1047  
1048          $readonly     = isset($attribs['readonly']) && $attribs['readonly'] === 'readonly';
1049          $disabled     = isset($attribs['disabled']) && $attribs['disabled'] === 'disabled';
1050          $autocomplete = isset($attribs['autocomplete']) && $attribs['autocomplete'] === '';
1051          $autofocus    = isset($attribs['autofocus']) && $attribs['autofocus'] === '';
1052          $required     = isset($attribs['required']) && $attribs['required'] === '';
1053          $filter       = isset($attribs['filter']) && $attribs['filter'] === '';
1054          $todayBtn     = $attribs['todayBtn'] ?? true;
1055          $weekNumbers  = $attribs['weekNumbers'] ?? true;
1056          $showTime     = $attribs['showTime'] ?? false;
1057          $fillTable    = $attribs['fillTable'] ?? true;
1058          $timeFormat   = $attribs['timeFormat'] ?? 24;
1059          $singleHeader = $attribs['singleHeader'] ?? false;
1060          $hint         = $attribs['placeholder'] ?? '';
1061          $class        = $attribs['class'] ?? '';
1062          $onchange     = $attribs['onChange'] ?? '';
1063          $minYear      = $attribs['minYear'] ?? null;
1064          $maxYear      = $attribs['maxYear'] ?? null;
1065  
1066          $showTime     = ($showTime) ? "1" : "0";
1067          $todayBtn     = ($todayBtn) ? "1" : "0";
1068          $weekNumbers  = ($weekNumbers) ? "1" : "0";
1069          $fillTable    = ($fillTable) ? "1" : "0";
1070          $singleHeader = ($singleHeader) ? "1" : "0";
1071  
1072          // Format value when not nulldate ('0000-00-00 00:00:00'), otherwise blank it as it would result in 1970-01-01.
1073          if ($value && $value !== Factory::getDbo()->getNullDate() && strtotime($value) !== false) {
1074              $tz = date_default_timezone_get();
1075              date_default_timezone_set('UTC');
1076              $inputvalue = strftime($format, strtotime($value));
1077              date_default_timezone_set($tz);
1078          } else {
1079              $inputvalue = '';
1080          }
1081  
1082          $data = array(
1083              'id'             => $id,
1084              'name'           => $name,
1085              'class'          => $class,
1086              'value'          => $inputvalue,
1087              'format'         => $format,
1088              'filter'         => $filter,
1089              'required'       => $required,
1090              'readonly'       => $readonly,
1091              'disabled'       => $disabled,
1092              'hint'           => $hint,
1093              'autofocus'      => $autofocus,
1094              'autocomplete'   => $autocomplete,
1095              'todaybutton'    => $todayBtn,
1096              'weeknumbers'    => $weekNumbers,
1097              'showtime'       => $showTime,
1098              'filltable'      => $fillTable,
1099              'timeformat'     => $timeFormat,
1100              'singleheader'   => $singleHeader,
1101              'tag'            => $tag,
1102              'helperPath'     => $helperPath,
1103              'direction'      => $direction,
1104              'onchange'       => $onchange,
1105              'minYear'        => $minYear,
1106              'maxYear'        => $maxYear,
1107              'dataAttribute'  => '',
1108              'dataAttributes' => '',
1109              'calendar'       => $calendar,
1110              'firstday'       => $lang->getFirstDay(),
1111              'weekend'        => explode(',', $lang->getWeekEnd()),
1112          );
1113  
1114          return LayoutHelper::render('joomla.form.field.calendar', $data, null, null);
1115      }
1116  
1117      /**
1118       * Add a directory where HTMLHelper should search for helpers. You may
1119       * either pass a string or an array of directories.
1120       *
1121       * @param   string  $path  A path to search.
1122       *
1123       * @return  array  An array with directory elements
1124       *
1125       * @since       1.5
1126       * @deprecated  5.0 Use the service registry instead
1127       */
1128      public static function addIncludePath($path = '')
1129      {
1130          @trigger_error(
1131              'Support for registering lookup paths is deprecated and will be removed in Joomla 5.0, use the service registry instead',
1132              E_USER_DEPRECATED
1133          );
1134  
1135          // Loop through the path directories
1136          foreach ((array) $path as $dir) {
1137              if (!empty($dir) && !\in_array($dir, static::$includePaths)) {
1138                  array_unshift(static::$includePaths, Path::clean($dir));
1139              }
1140          }
1141  
1142          return static::$includePaths;
1143      }
1144  
1145      /**
1146       * Method that searches if file exists in given path and returns the relative path. If a minified version exists it will be preferred.
1147       *
1148       * @param   string   $path       The actual path of the file
1149       * @param   string   $ext        The extension of the file
1150       * @param   boolean  $debugMode  Signifies if debug is enabled
1151       *
1152       * @return  string  The relative path of the file
1153       *
1154       * @since   4.0.0
1155       */
1156      protected static function addFileToBuffer($path = '', $ext = '', $debugMode = false)
1157      {
1158          $position = strrpos($path, '.min.');
1159  
1160          // We are handling a name.min.ext file:
1161          if ($position !== false) {
1162              $minifiedPath    = $path;
1163              $nonMinifiedPath = substr_replace($path, '', $position, 4);
1164  
1165              if ($debugMode) {
1166                  return self::checkFileOrder($minifiedPath, $nonMinifiedPath);
1167              }
1168  
1169              return self::checkFileOrder($nonMinifiedPath, $minifiedPath);
1170          }
1171  
1172          $minifiedPath = pathinfo($path, PATHINFO_DIRNAME) . '/' . pathinfo($path, PATHINFO_FILENAME) . '.min.' . $ext;
1173  
1174          if ($debugMode) {
1175              return self::checkFileOrder($minifiedPath, $path);
1176          }
1177  
1178          return self::checkFileOrder($path, $minifiedPath);
1179      }
1180  
1181      /**
1182       * Method that takes a file path and converts it to a relative path
1183       *
1184       * @param   string  $path  The actual path of the file
1185       *
1186       * @return  string  The relative path of the file
1187       *
1188       * @since   4.0.0
1189       */
1190      protected static function convertToRelativePath($path)
1191      {
1192          $relativeFilePath = Uri::root(true) . str_replace(JPATH_ROOT, '', $path);
1193  
1194          // On windows devices we need to replace "\" with "/" otherwise some browsers will not load the asset
1195          return str_replace(DIRECTORY_SEPARATOR, '/', $relativeFilePath);
1196      }
1197  
1198      /**
1199       * Method that takes two paths and checks if the files exist with different order
1200       *
1201       * @param   string  $first   the path of the minified file
1202       * @param   string  $second  the path of the non minified file
1203       *
1204       * @return  string
1205       *
1206       * @since  4.0.0
1207       */
1208      private static function checkFileOrder($first, $second)
1209      {
1210          if (is_file($second)) {
1211              return static::convertToRelativePath($second);
1212          }
1213  
1214          if (is_file($first)) {
1215              return static::convertToRelativePath($first);
1216          }
1217  
1218          return '';
1219      }
1220  }


Generated: Wed Sep 7 05:41:13 2022 Chilli.vc Blog - For Webmaster,Blog-Writer,System Admin and Domainer