[ Index ] |
PHP Cross Reference of Joomla 4.2.2 documentation |
[Summary view] [Print] [Text view]
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 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Wed Sep 7 05:41:13 2022 | Chilli.vc Blog - For Webmaster,Blog-Writer,System Admin and Domainer |