File manager - Edit - /home/opticamezl/www/newok/WebAsset.tar
Back
WebAssetRegistry.php 0000644 00000031312 15172715467 0010542 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\WebAsset; use Joomla\CMS\Event\AbstractEvent; use Joomla\CMS\Filesystem\Path; use Joomla\CMS\WebAsset\Exception\UnknownAssetException; use Joomla\Event\Dispatcher as EventDispatcher; use Joomla\Event\DispatcherAwareInterface; use Joomla\Event\DispatcherAwareTrait; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Web Asset Registry class * * @since 4.0.0 */ class WebAssetRegistry implements WebAssetRegistryInterface, DispatcherAwareInterface { use DispatcherAwareTrait; /** * Files with Asset info. File path should be relative. * * @var array * @example of registry file: * * { * "title" : "Example", * "name" : "com_example", * "author": "Joomla! CMS", * "assets": [ * { * "name": "library1", * "version": "3.5.0", * "type": "script", * "uri": "com_example/library1.min.js" * }, * { * "name": "library2", * "version": "3.5.0", * "type": "script", * "uri": "com_example/library2.min.js", * "dependencies": [ * "core", * "library1" * ], * "attribute": { * "attr-name": "attr value" * "defer": true * } * }, * { * "name": "library1", * "version": "3.5.0", * "type": "style", * "uri": "com_example/library1.min.css" * "attribute": { * "media": "all" * } * }, * { * "name": "library1", * "type": "preset", * "dependencies": { * "library1#style", * "library1#script" * } * }, * ] * } * * @since 4.0.0 */ protected $dataFilesNew = []; /** * List of parsed files * * @var array * * @since 4.0.0 */ protected $dataFilesParsed = []; /** * Registry of available Assets * * @var array * * @since 4.0.0 */ protected $assets = []; /** * Registry constructor * * @since 4.0.0 */ public function __construct() { // Use a dedicated dispatcher $this->setDispatcher(new EventDispatcher()); } /** * Get an existing Asset from a registry, by asset name. * * @param string $type Asset type, script or style * @param string $name Asset name * * @return WebAssetItem * * @throws UnknownAssetException When Asset cannot be found * * @since 4.0.0 */ public function get(string $type, string $name): WebAssetItemInterface { // Check if any new file was added $this->parseRegistryFiles(); if (empty($this->assets[$type][$name])) { throw new UnknownAssetException(sprintf('There is no "%s" asset of a "%s" type in the registry.', $name, $type)); } return $this->assets[$type][$name]; } /** * Add Asset to registry of known assets * * @param string $type Asset type, script or style * @param WebAssetItemInterface $asset Asset instance * * @return self * * @since 4.0.0 */ public function add(string $type, WebAssetItemInterface $asset): WebAssetRegistryInterface { $type = strtolower($type); if (!array_key_exists($type, $this->assets)) { $this->assets[$type] = []; } // Check if any new file was added $this->parseRegistryFiles(); $eventChange = 'new'; $eventAsset = $asset; // Use "old" asset for "Changed" event, a "new" asset can be loaded by a name from the registry if (!empty($this->assets[$type][$asset->getName()])) { $eventChange = 'override'; $eventAsset = $this->assets[$type][$asset->getName()]; } $this->assets[$type][$asset->getName()] = $asset; $this->dispatchAssetChanged($type, $eventAsset, $eventChange); return $this; } /** * Remove Asset from registry. * * @param string $type Asset type, script or style * @param string $name Asset name * * @return self * * @since 4.0.0 */ public function remove(string $type, string $name): WebAssetRegistryInterface { // Check if any new file was added $this->parseRegistryFiles(); if (!empty($this->assets[$type][$name])) { $asset = $this->assets[$type][$name]; unset($this->assets[$type][$name]); $this->dispatchAssetChanged($type, $asset, 'remove'); } return $this; } /** * Check whether the asset exists in the registry. * * @param string $type Asset type, script or style * @param string $name Asset name * * @return boolean * * @since 4.0.0 */ public function exists(string $type, string $name): bool { // Check if any new file was added $this->parseRegistryFiles(); return !empty($this->assets[$type][$name]); } /** * Prepare new Asset instance. * * @param string $name The asset name * @param string $uri The URI for the asset * @param array $options Additional options for the asset * @param array $attributes Attributes for the asset * @param array $dependencies Asset dependencies * * @return WebAssetItem * * @since 4.0.0 */ public function createAsset( string $name, string $uri = null, array $options = [], array $attributes = [], array $dependencies = [] ): WebAssetItem { $nameSpace = \array_key_exists('namespace', $options) ? $options['namespace'] : __NAMESPACE__ . '\\AssetItem'; $className = \array_key_exists('class', $options) ? $options['class'] : null; if ($className && class_exists($nameSpace . '\\' . $className)) { $className = $nameSpace . '\\' . $className; return new $className($name, $uri, $options, $attributes, $dependencies); } return new WebAssetItem($name, $uri, $options, $attributes, $dependencies); } /** * Register new file with Asset(s) info * * @param string $path Relative path * * @return self * * @since 4.0.0 */ public function addRegistryFile(string $path): self { $path = Path::clean($path); if (isset($this->dataFilesNew[$path]) || isset($this->dataFilesParsed[$path])) { return $this; } if (is_file(JPATH_ROOT . '/' . $path)) { $this->dataFilesNew[$path] = $path; } return $this; } /** * Get a list of the registry files * * @return array * * @since 4.0.0 */ public function getRegistryFiles(): array { return array_values($this->dataFilesParsed + $this->dataFilesNew); } /** * Helper method to register new file with Template Asset(s) info * * @param string $template The template name * @param integer $client The application client id * * @return self * * @since 4.0.0 */ public function addTemplateRegistryFile(string $template, int $client): self { switch ($client) { case 0: $this->addRegistryFile('templates/' . $template . '/joomla.asset.json'); break; case 1: $this->addRegistryFile('administrator/templates/' . $template . '/joomla.asset.json'); break; default: break; } return $this; } /** * Helper method to register new file with Extension Asset(s) info * * @param string $name A full extension name, actually a name in the /media folder, eg: com_example, plg_system_example etc. * * @return self * * @since 4.0.0 */ public function addExtensionRegistryFile(string $name): self { $this->addRegistryFile('media/' . $name . '/joomla.asset.json'); return $this; } /** * Parse registered files * * @return void * * @since 4.0.0 */ protected function parseRegistryFiles() { if (!$this->dataFilesNew) { return; } $paths = $this->dataFilesNew; $this->dataFilesNew = []; foreach ($paths as $path) { // Parse only if the file was not parsed already if (empty($this->dataFilesParsed[$path])) { $this->parseRegistryFile($path); // Mark the file as parsed $this->dataFilesParsed[$path] = $path; } } } /** * Parse registry file * * @param string $path Relative path to the data file * * @return void * * @throws \RuntimeException If file is empty or invalid * * @since 4.0.0 */ protected function parseRegistryFile($path) { $data = file_get_contents(JPATH_ROOT . '/' . $path); $data = $data ? json_decode($data, true) : null; if ($data === null) { throw new \RuntimeException(sprintf('Asset registry file "%s" contains invalid JSON', $path)); } // Check if asset field exists and contains data. If it doesn't - we can just bail here. if (empty($data['assets'])) { return; } // Keep source info $assetSource = [ 'registryFile' => $path, ]; $namespace = \array_key_exists('namespace', $data) ? $data['namespace'] : null; // Prepare WebAssetItem instances foreach ($data['assets'] as $i => $item) { if (empty($item['name'])) { throw new \RuntimeException( sprintf('Failed parsing asset registry file "%s". Property "name" is required for asset index "%s"', $path, $i) ); } if (empty($item['type'])) { throw new \RuntimeException( sprintf('Failed parsing asset registry file "%s". Property "type" is required for asset "%s"', $path, $item['name']) ); } $item['type'] = strtolower($item['type']); $name = $item['name']; $uri = $item['uri'] ?? ''; $options = $item; $options['assetSource'] = $assetSource; unset($options['uri'], $options['name']); // Inheriting the Namespace if ($namespace && !\array_key_exists('namespace', $options)) { $options['namespace'] = $namespace; } $assetItem = $this->createAsset($name, $uri, $options); $this->add($item['type'], $assetItem); } } /** * Dispatch an event to notify listeners about asset changes: new, remove, override * Events: * - onWebAssetRegistryChangedAssetNew When new asset added to the registry * - onWebAssetRegistryChangedAssetOverride When the asset overridden * - onWebAssetRegistryChangedAssetRemove When new asset was removed from the registry * * @param string $type Asset type, script or style * @param WebAssetItemInterface $asset Asset instance * @param string $change A type of change: new, remove, override * * @return void * * @since 4.0.0 */ protected function dispatchAssetChanged(string $type, WebAssetItemInterface $asset, string $change) { // Trigger the event $event = AbstractEvent::create( 'onWebAssetRegistryChangedAsset' . ucfirst($change), [ 'eventClass' => 'Joomla\\CMS\\Event\\WebAsset\\WebAssetRegistryAssetChanged', 'subject' => $this, 'assetType' => $type, 'asset' => $asset, 'change' => $change, ] ); $this->getDispatcher()->dispatch($event->getName(), $event); } } WebAssetRegistryInterface.php 0000644 00000003507 15172715467 0012370 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\WebAsset; use Joomla\CMS\WebAsset\Exception\UnknownAssetException; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Web Asset Registry interface * * @since 4.0.0 */ interface WebAssetRegistryInterface { /** * Get an existing Asset from a registry, by asset name and asset type. * * @param string $type Asset type, script or style etc * @param string $name Asset name * * @return WebAssetItem * * @throws UnknownAssetException When Asset cannot be found * * @since 4.0.0 */ public function get(string $type, string $name): WebAssetItemInterface; /** * Add Asset to registry of known assets * * @param string $type Asset type, script or style etc * @param WebAssetItemInterface $asset Asset instance * * @return self * * @since 4.0.0 */ public function add(string $type, WebAssetItemInterface $asset): self; /** * Remove Asset from registry. * * @param string $type Asset type, script or style etc * @param string $name Asset name * * @return self * * @since 4.0.0 */ public function remove(string $type, string $name): self; /** * Check whether the asset exists in the registry. * * @param string $type Asset type, script or style etc * @param string $name Asset name * * @return boolean * * @since 4.0.0 */ public function exists(string $type, string $name): bool; } Exception/WebAssetExceptionInterface.php 0000644 00000000744 15172715467 0014454 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\WebAsset\Exception; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Exception interface defining a WebAsset error * * @since 4.0.0 */ interface WebAssetExceptionInterface { } Exception/UnknownAssetException.php 0000644 00000001027 15172715467 0013550 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\WebAsset\Exception; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Exception class defining an Unknown Asset * * @since 4.0.0 */ class UnknownAssetException extends \RuntimeException implements WebAssetExceptionInterface { } Exception/InvalidActionException.php 0000644 00000001037 15172715467 0013636 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\WebAsset\Exception; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Exception class defining an Invalid Action error * * @since 4.0.0 */ class InvalidActionException extends \RuntimeException implements WebAssetExceptionInterface { } Exception/UnsatisfiedDependencyException.php 0000644 00000001051 15172715467 0015363 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\WebAsset\Exception; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Exception class defining an Unsatisfied Dependency * * @since 4.0.0 */ class UnsatisfiedDependencyException extends \RuntimeException implements WebAssetExceptionInterface { } WebAssetManagerInterface.php 0000644 00000004711 15172715467 0012130 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\WebAsset; use Joomla\CMS\WebAsset\Exception\InvalidActionException; use Joomla\CMS\WebAsset\Exception\UnknownAssetException; use Joomla\CMS\WebAsset\Exception\UnsatisfiedDependencyException; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Web Asset Manager Interface * * @since 4.0.0 */ interface WebAssetManagerInterface { /** * Enable an asset item to be attached to a Document * * @param string $type Asset type, script or style etc * @param string $name The asset name * * @return self * * @throws UnknownAssetException When Asset cannot be found * @throws InvalidActionException When the Manager already attached to a Document * * @since 4.0.0 */ public function useAsset(string $type, string $name): self; /** * Deactivate an asset item, so it will not be attached to a Document * * @param string $type Asset type, script or style etc * @param string $name The asset name * * @return self * * @throws UnknownAssetException When Asset cannot be found * @throws InvalidActionException When the Manager already attached to a Document * * @since 4.0.0 */ public function disableAsset(string $type, string $name): self; /** * Check whether the asset are enabled * * @param string $type Asset type, script or style etc * @param string $name The asset name * * @return boolean * * @throws UnknownAssetException When Asset cannot be found * * @since 4.0.0 */ public function isAssetActive(string $type, string $name): bool; /** * Get all assets that was enabled for given type * * @param string $type Asset type, script or style etc * @param bool $sort Whether need to sort the assets to follow the dependency Graph * * @return WebAssetItemInterface[] * * @throws UnknownAssetException When Asset cannot be found * @throws UnsatisfiedDependencyException When Dependency cannot be found * * @since 4.0.0 */ public function getAssets(string $type, bool $sort = false): array; } WebAssetItemInterface.php 0000644 00000005352 15172715467 0011456 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\WebAsset; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Web Asset Item interface * * Asset Item are "read only" object, all properties must be set through class constructor. * Only properties allowed to be edited is an attributes and an options. * Changing an uri or a dependencies are not allowed, prefer to create a new asset instance. * * @since 4.0.0 */ interface WebAssetItemInterface { /** * Return Asset name * * @return string * * @since 4.0.0 */ public function getName(): string; /** * Return Asset version * * @return string * * @since 4.0.0 */ public function getVersion(): string; /** * Return dependencies list * * @return array * * @since 4.0.0 */ public function getDependencies(): array; /** * Get the URI of the asset * * @param boolean $resolvePath Whether need to search for a real paths * * @return string * * @since 4.0.0 */ public function getUri($resolvePath = true): string; /** * Get the option * * @param string $key An option key * @param string $default A default value * * @return mixed * * @since 4.0.0 */ public function getOption(string $key, $default = null); /** * Set the option * * @param string $key An option key * @param string $value An option value * * @return self * * @since 4.0.0 */ public function setOption(string $key, $value = null): WebAssetItemInterface; /** * Get all options of the asset * * @return array * * @since 4.0.0 */ public function getOptions(): array; /** * Get the attribute * * @param string $key An attributes key * @param string $default A default value * * @return mixed * * @since 4.0.0 */ public function getAttribute(string $key, $default = null); /** * Set the attribute * * @param string $key An attribute key * @param string $value An attribute value * * @return self * * @since 4.0.0 */ public function setAttribute(string $key, $value = null): WebAssetItemInterface; /** * Get all attributes * * @return array * * @since 4.0.0 */ public function getAttributes(): array; } AssetItem/TableColumnsAssetItem.php 0000644 00000002116 15172715467 0013401 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2022 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\WebAsset\AssetItem; use Joomla\CMS\Document\Document; use Joomla\CMS\Language\Text; use Joomla\CMS\WebAsset\WebAssetAttachBehaviorInterface; use Joomla\CMS\WebAsset\WebAssetItem; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Web Asset Item class for tables.column asset * * @since 4.2.0 */ class TableColumnsAssetItem extends WebAssetItem implements WebAssetAttachBehaviorInterface { /** * Method called when asset attached to the Document. * Used to add the language strings required by the script. * * @param Document $doc Active document * * @return void * * @since 4.2.0 */ public function onAttachCallback(Document $doc) { // Add table-columns.js language strings Text::script('JGLOBAL_COLUMNS'); } } AssetItem/FormValidateAssetItem.php 0000644 00000002362 15172715467 0013371 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2020 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\WebAsset\AssetItem; use Joomla\CMS\Document\Document; use Joomla\CMS\Language\Text; use Joomla\CMS\WebAsset\WebAssetAttachBehaviorInterface; use Joomla\CMS\WebAsset\WebAssetItem; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Web Asset Item class for form.validate asset * * @since 4.0.0 */ class FormValidateAssetItem extends WebAssetItem implements WebAssetAttachBehaviorInterface { /** * Method called when asset attached to the Document. * Useful for Asset to add a Script options. * * @param Document $doc Active document * * @return void * * @since 4.0.0 */ public function onAttachCallback(Document $doc) { // Add validate.js language strings Text::script('JLIB_FORM_CONTAINS_INVALID_FIELDS'); Text::script('JLIB_FORM_FIELD_REQUIRED_VALUE'); Text::script('JLIB_FORM_FIELD_REQUIRED_CHECK'); Text::script('JLIB_FORM_FIELD_INVALID_VALUE'); } } AssetItem/KeepaliveAssetItem.php 0000644 00000003751 15172715467 0012724 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\WebAsset\AssetItem; use Joomla\CMS\Document\Document; use Joomla\CMS\Factory; use Joomla\CMS\Router\Route; use Joomla\CMS\WebAsset\WebAssetAttachBehaviorInterface; use Joomla\CMS\WebAsset\WebAssetItem; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Web Asset Item class for Keepalive asset * * @since 4.0.0 */ class KeepaliveAssetItem extends WebAssetItem implements WebAssetAttachBehaviorInterface { /** * Method called when asset attached to the Document. * Useful for Asset to add a Script options. * * @param Document $doc Active document * * @return void * * @since 4.0.0 */ public function onAttachCallback(Document $doc) { $app = Factory::getApplication(); $sessionHandler = $app->get('session_handler', 'database'); // If the handler is not 'Database', we set a fixed, small refresh value (here: 5 min) $refreshTime = 300; if ($sessionHandler === 'database') { $lifeTime = $app->getSession()->getExpire(); $refreshTime = $lifeTime <= 60 ? 45 : $lifeTime - 60; // The longest refresh period is one hour to prevent integer overflow. if ($refreshTime > 3600 || $refreshTime <= 0) { $refreshTime = 3600; } } // If we are in the frontend or logged in as a user, we can use the ajax component to reduce the load $uri = 'index.php' . ($app->isClient('site') || !Factory::getUser()->guest ? '?option=com_ajax&format=json' : ''); // Add keepalive script options. $doc->addScriptOptions('system.keepalive', ['interval' => $refreshTime * 1000, 'uri' => Route::_($uri)]); } } AssetItem/CoreAssetItem.php 0000644 00000002564 15172715467 0011710 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\WebAsset\AssetItem; use Joomla\CMS\Document\Document; use Joomla\CMS\HTML\HTMLHelper; use Joomla\CMS\Uri\Uri; use Joomla\CMS\WebAsset\WebAssetAttachBehaviorInterface; use Joomla\CMS\WebAsset\WebAssetItem; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Web Asset Item class for Core asset * * @since 4.0.0 */ class CoreAssetItem extends WebAssetItem implements WebAssetAttachBehaviorInterface { /** * Method called when asset attached to the Document. * Useful for Asset to add a Script options. * * @param Document $doc Active document * * @return void * * @since 4.0.0 */ public function onAttachCallback(Document $doc) { // Add core and base uri paths so javascript scripts can use them. $doc->addScriptOptions( 'system.paths', [ 'root' => Uri::root(true), 'rootFull' => Uri::root(), 'base' => Uri::base(true), 'baseFull' => Uri::base(), ] ); HTMLHelper::_('form.csrf'); } } AssetItem/LangActiveAssetItem.php 0000644 00000003253 15172715467 0013031 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2020 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\WebAsset\AssetItem; use Joomla\CMS\Factory; use Joomla\CMS\WebAsset\WebAssetItem; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Web Asset Item class for load asset file for active language. * Used in core templates. * * @since 4.0.0 */ class LangActiveAssetItem extends WebAssetItem { /** * Class constructor * * @param string $name The asset name * @param string $uri The URI for the asset * @param array $options Additional options for the asset * @param array $attributes Attributes for the asset * @param array $dependencies Asset dependencies * * @since 4.0.0 */ public function __construct( string $name, string $uri = null, array $options = [], array $attributes = [], array $dependencies = [] ) { parent::__construct($name, $uri, $options, $attributes, $dependencies); // Prepare Uri depend from the active language $langTag = Factory::getApplication()->getLanguage()->getTag(); $client = $this->getOption('client'); // Create Uri <client>/language/<langTag>/<langTag>.css if ($client) { $this->uri = $client . '/language/' . $langTag . '/' . $langTag . '.css'; } else { $this->uri = 'language/' . $langTag . '/' . $langTag . '.css'; } } } WebAssetManager.php 0000644 00000100375 15172715467 0010312 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\WebAsset; use Joomla\CMS\Event\WebAsset\WebAssetRegistryAssetChanged; use Joomla\CMS\WebAsset\Exception\InvalidActionException; use Joomla\CMS\WebAsset\Exception\UnknownAssetException; use Joomla\CMS\WebAsset\Exception\UnsatisfiedDependencyException; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Web Asset Manager class * * @method WebAssetManager registerStyle(WebAssetItem|string $asset, string $uri = '', $options = [], $attributes = [], $dependencies = []) * @method WebAssetManager registerAndUseStyle(WebAssetItem|string $asset, string $uri = '', $options = [], $attributes = [], $dependencies = []) * @method WebAssetManager useStyle($name) * @method WebAssetManager disableStyle($name) * @method WebAssetManager addInlineStyle(WebAssetItem|string $content, $options = [], $attributes = [], $dependencies = []) * * @method WebAssetManager registerScript(WebAssetItem|string $asset, string $uri = '', $options = [], $attributes = [], $dependencies = []) * @method WebAssetManager registerAndUseScript(WebAssetItem|string $asset, string $uri = '', $options = [], $attributes = [], $dependencies = []) * @method WebAssetManager useScript($name) * @method WebAssetManager disableScript($name) * @method WebAssetManager addInlineScript(WebAssetItem|string $content, $options = [], $attributes = [], $dependencies = []) * * @method WebAssetManager registerPreset(WebAssetItem|string $asset, string $uri = '', $options = [], $attributes = [], $dependencies = []) * @method WebAssetManager registerAndUsePreset(WebAssetItem|string $asset, string $uri = '', $options = [], $attributes = [], $dependencies = []) * @method WebAssetManager usePreset($name) * @method WebAssetManager disablePreset($name) * * @since 4.0.0 */ class WebAssetManager implements WebAssetManagerInterface { /** * Mark inactive asset * * @var integer * * @since 4.0.0 */ public const ASSET_STATE_INACTIVE = 0; /** * Mark active asset. Just enabled, but WITHOUT dependency resolved * * @var integer * * @since 4.0.0 */ public const ASSET_STATE_ACTIVE = 1; /** * Mark active asset that is enabled as dependency to another asset * * @var integer * * @since 4.0.0 */ public const ASSET_STATE_DEPENDENCY = 2; /** * The WebAsset Registry instance * * @var WebAssetRegistry * * @since 4.0.0 */ protected $registry; /** * A list of active assets (including their dependencies). * Array of Name => State * * @var array * * @since 4.0.0 */ protected $activeAssets = []; /** * Internal marker to check the manager state, * to prevent use of the manager after an assets are rendered * * @var boolean * * @since 4.0.0 */ protected $locked = false; /** * Internal marker to keep track when need to recheck dependencies * * @var boolean * * @since 4.0.0 */ protected $dependenciesIsActual = false; /** * Class constructor * * @param WebAssetRegistry $registry The WebAsset Registry instance * * @since 4.0.0 */ public function __construct(WebAssetRegistry $registry) { $this->registry = $registry; // Listen to changes in the registry $this->registry->getDispatcher()->addListener( 'onWebAssetRegistryChangedAssetOverride', function (WebAssetRegistryAssetChanged $event) { // If the changed asset are used if (!empty($this->activeAssets[$event->getAssetType()][$event->getAsset()->getName()])) { $this->dependenciesIsActual = false; } } ); $this->registry->getDispatcher()->addListener( 'onWebAssetRegistryChangedAssetRemove', function (WebAssetRegistryAssetChanged $event) { // If the changed asset are used if (!empty($this->activeAssets[$event->getAssetType()][$event->getAsset()->getName()])) { $this->dependenciesIsActual = false; } } ); } /** * Get associated registry instance * * @return WebAssetRegistry * * @since 4.0.0 */ public function getRegistry(): WebAssetRegistry { return $this->registry; } /** * Clears all collected items. * * @return self * * @since 4.1.1 */ public function reset(): WebAssetManagerInterface { if ($this->locked) { throw new InvalidActionException('WebAssetManager is locked'); } $this->activeAssets = []; $this->dependenciesIsActual = false; return $this; } /** * Adds support for magic method calls * * @param string $method A method name * @param array $arguments Arguments for a method * * @return mixed * * @throws \BadMethodCallException * * @since 4.0.0 */ public function __call($method, $arguments) { $method = strtolower($method); if (0 === strpos($method, 'use')) { $type = substr($method, 3); if (empty($arguments[0])) { throw new \BadMethodCallException('An asset name is required'); } return $this->useAsset($type, $arguments[0]); } if (0 === strpos($method, 'addinline')) { $type = substr($method, 9); if (empty($arguments[0])) { throw new \BadMethodCallException('Content is required'); } return $this->addInline($type, ...$arguments); } if (0 === strpos($method, 'disable')) { $type = substr($method, 7); if (empty($arguments[0])) { throw new \BadMethodCallException('An asset name is required'); } return $this->disableAsset($type, $arguments[0]); } if (0 === strpos($method, 'register')) { // Check for registerAndUse<Type> $andUse = substr($method, 8, 6) === 'anduse'; // Extract the type $type = $andUse ? substr($method, 14) : substr($method, 8); if (empty($arguments[0])) { throw new \BadMethodCallException('An asset instance or an asset name is required'); } if ($andUse) { $name = $arguments[0] instanceof WebAssetItemInterface ? $arguments[0]->getName() : $arguments[0]; return $this->registerAsset($type, ...$arguments)->useAsset($type, $name); } else { return $this->registerAsset($type, ...$arguments); } } throw new \BadMethodCallException(sprintf('Undefined method %s in class %s', $method, get_class($this))); } /** * Enable an asset item to be attached to a Document * * @param string $type The asset type, script or style * @param string $name The asset name * * @return self * * @throws UnknownAssetException When Asset cannot be found * @throws InvalidActionException When the Manager already attached to a Document * * @since 4.0.0 */ public function useAsset(string $type, string $name): WebAssetManagerInterface { if ($this->locked) { throw new InvalidActionException('WebAssetManager is locked, you came late'); } // Check whether asset exists $asset = $this->registry->get($type, $name); if (empty($this->activeAssets[$type])) { $this->activeAssets[$type] = []; } // For "preset" need to check the dependencies first if ($type === 'preset') { $this->usePresetItems($name); } // Asset already enabled if (!empty($this->activeAssets[$type][$name])) { // Set state to active, in case it was ASSET_STATE_DEPENDENCY $this->activeAssets[$type][$name] = static::ASSET_STATE_ACTIVE; return $this; } $this->activeAssets[$type][$name] = static::ASSET_STATE_ACTIVE; // To re-check dependencies if ($asset->getDependencies()) { $this->dependenciesIsActual = false; } return $this; } /** * Deactivate an asset item, so it will not be attached to a Document * * @param string $type The asset type, script or style * @param string $name The asset name * * @return self * * @throws UnknownAssetException When Asset cannot be found * @throws InvalidActionException When the Manager already attached to a Document * * @since 4.0.0 */ public function disableAsset(string $type, string $name): WebAssetManagerInterface { if ($this->locked) { throw new InvalidActionException('WebAssetManager is locked, you came late'); } // Check whether asset exists $this->registry->get($type, $name); unset($this->activeAssets[$type][$name]); // To re-check dependencies $this->dependenciesIsActual = false; // For Preset case if ($type === 'preset') { $this->disablePresetItems($name); } return $this; } /** * Enable list of assets provided by Preset item. * * "Preset" a special kind of asset that hold a list of assets that has to be enabled, * same as direct call of useAsset() to each of item in list. * Can hold mixed types of assets (script, style, another preset, etc), the type provided after # symbol, after * the asset name, example: foo#style, bar#script. * * The method call useAsset() internally for each of its dependency, this is important for keeping FIFO order * of enabled items. * The Preset not a strict asset, and each of its dependency can be safely disabled by use of disableAsset() later. * * @param string $name The asset name * * @return self * * @throws UnsatisfiedDependencyException When Asset dependency cannot be found * * @since 4.0.0 */ protected function usePresetItems($name): WebAssetManagerInterface { // Get the asset object $asset = $this->registry->get('preset', $name); // Call useAsset() to each of its dependency foreach ($asset->getDependencies() as $dependency) { $depType = ''; $depName = $dependency; $pos = strrpos($dependency, '#'); // Check for cross-dependency "dependency-name#type" case if ($pos) { $depType = substr($dependency, $pos + 1); $depName = substr($dependency, 0, $pos); } $depType = $depType ?: 'preset'; // Make sure dependency exists if (!$this->registry->exists($depType, $depName)) { throw new UnsatisfiedDependencyException( sprintf('Unsatisfied dependency "%s" for an asset "%s" of type "%s"', $dependency, $name, 'preset') ); } $this->useAsset($depType, $depName); } return $this; } /** * Deactivate list of assets provided by Preset item. * * @param string $name The asset name * * @return self * * @throws UnsatisfiedDependencyException When Asset dependency cannot be found * * @since 4.0.0 */ protected function disablePresetItems($name): WebAssetManagerInterface { // Get the asset object $asset = $this->registry->get('preset', $name); // Call disableAsset() to each of its dependency foreach ($asset->getDependencies() as $dependency) { $depType = ''; $depName = $dependency; $pos = strrpos($dependency, '#'); // Check for cross-dependency "dependency-name#type" case if ($pos) { $depType = substr($dependency, $pos + 1); $depName = substr($dependency, 0, $pos); } $depType = $depType ?: 'preset'; // Make sure dependency exists if (!$this->registry->exists($depType, $depName)) { throw new UnsatisfiedDependencyException( sprintf('Unsatisfied dependency "%s" for an asset "%s" of type "%s"', $dependency, $name, 'preset') ); } $this->disableAsset($depType, $depName); } return $this; } /** * Get a state for the Asset * * @param string $type The asset type, script or style * @param string $name The asset name * * @return integer * * @throws UnknownAssetException When Asset cannot be found * * @since 4.0.0 */ public function getAssetState(string $type, string $name): int { // Check whether asset exists first $this->registry->get($type, $name); // Make sure that all dependencies are active if (!$this->dependenciesIsActual) { $this->enableDependencies(); } if (!empty($this->activeAssets[$type][$name])) { return $this->activeAssets[$type][$name]; } return static::ASSET_STATE_INACTIVE; } /** * Check whether the asset are enabled * * @param string $type The asset type, script or style * @param string $name The asset name * * @return boolean * * @throws UnknownAssetException When Asset cannot be found * * @since 4.0.0 */ public function isAssetActive(string $type, string $name): bool { return $this->getAssetState($type, $name) !== static::ASSET_STATE_INACTIVE; } /** * Helper method to check whether the asset exists in the registry. * * @param string $type Asset type, script or style * @param string $name Asset name * * @return boolean * * @since 4.0.0 */ public function assetExists(string $type, string $name): bool { return $this->registry->exists($type, $name); } /** * Register a new asset. * Allow to register WebAssetItem instance in the registry, by call registerAsset($type, $assetInstance) * Or create an asset on fly (from name and Uri) and register in the registry, by call registerAsset($type, $assetName, $uri, $options ....) * * @param string $type The asset type, script or style * @param WebAssetItem|string $asset The asset name or instance to register * @param string $uri The URI for the asset * @param array $options Additional options for the asset * @param array $attributes Attributes for the asset * @param array $dependencies Asset dependencies * * @return self * * @since 4.0.0 * * @throws \InvalidArgumentException */ public function registerAsset(string $type, $asset, string $uri = '', array $options = [], array $attributes = [], array $dependencies = []) { if ($asset instanceof WebAssetItemInterface) { $this->registry->add($type, $asset); } elseif (is_string($asset)) { $options['type'] = $type; $assetInstance = $this->registry->createAsset($asset, $uri, $options, $attributes, $dependencies); $this->registry->add($type, $assetInstance); } else { throw new \InvalidArgumentException( sprintf( '%s(): Argument #2 ($asset) must be a string or an instance of %s, %s given.', __METHOD__, WebAssetItemInterface::class, \is_object($asset) ? \get_class($asset) : \gettype($asset) ) ); } return $this; } /** * Helper method to get the asset from the registry. * * @param string $type Asset type, script or style * @param string $name Asset name * * @return WebAssetItemInterface * * @throws UnknownAssetException When Asset cannot be found * * @since 4.0.0 */ public function getAsset(string $type, string $name): WebAssetItemInterface { return $this->registry->get($type, $name); } /** * Get all active assets, optionally sort them to follow the dependency Graph * * @param string $type The asset type, script or style * @param bool $sort Whether need to sort the assets to follow the dependency Graph * * @return WebAssetItem[] * * @throws UnknownAssetException When Asset cannot be found * @throws UnsatisfiedDependencyException When Dependency cannot be found * * @since 4.0.0 */ public function getAssets(string $type, bool $sort = false): array { // Make sure that all dependencies are active if (!$this->dependenciesIsActual) { $this->enableDependencies(); } if (empty($this->activeAssets[$type])) { return []; } // Apply Tree sorting for regular asset items, but return FIFO order for "preset" if ($sort && $type !== 'preset') { $assets = $this->calculateOrderOfActiveAssets($type); } else { $assets = []; foreach (array_keys($this->activeAssets[$type]) as $name) { $assets[$name] = $this->registry->get($type, $name); } } return $assets; } /** * Helper method to calculate inline to non inline relation (before/after positions). * Return associated array, which contain dependency (handle) name as key, and list of inline items for each position. * Example: ['handle.name' => ['before' => ['inline1', 'inline2'], 'after' => ['inline3', 'inline4']]] * * Note: If inline asset have a multiple dependencies, then will be used last one from the list for positioning * * @param WebAssetItem[] $assets The assets list * * @return array * * @since 4.0.0 */ public function getInlineRelation(array $assets): array { $inlineRelation = []; // Find an inline assets and their relations to non inline foreach ($assets as $k => $asset) { if (!$asset->getOption('inline')) { continue; } // Check whether position are requested with dependencies $position = $asset->getOption('position'); $position = $position === 'before' || $position === 'after' ? $position : null; $deps = $asset->getDependencies(); if ($position && $deps) { // If inline asset have a multiple dependencies, then use last one from the list for positioning $handle = end($deps); $inlineRelation[$handle][$position][$asset->getName()] = $asset; } } return $inlineRelation; } /** * Helper method to filter an inline assets * * @param WebAssetItem[] $assets Reference to a full list of active assets * * @return WebAssetItem[] Array of inline assets * * @since 4.0.0 */ public function filterOutInlineAssets(array &$assets): array { $inlineAssets = []; foreach ($assets as $k => $asset) { if (!$asset->getOption('inline')) { continue; } // Remove inline assets from assets list, and add to list of inline unset($assets[$k]); $inlineAssets[$asset->getName()] = $asset; } return $inlineAssets; } /** * Add a new inline content asset. * Allow to register WebAssetItem instance in the registry, by call addInline($type, $assetInstance) * Or create an asset on fly (from name and Uri) and register in the registry, by call addInline($type, $content, $options ....) * * @param string $type The asset type, script or style * @param WebAssetItem|string $content The content to of inline asset * @param array $options Additional options for the asset * @param array $attributes Attributes for the asset * @param array $dependencies Asset dependencies * * @return self * * @since 4.0.0 * * @throws \InvalidArgumentException */ public function addInline(string $type, $content, array $options = [], array $attributes = [], array $dependencies = []): self { if ($content instanceof WebAssetItemInterface) { $assetInstance = $content; } elseif (is_string($content)) { $name = $options['name'] ?? ('inline.' . md5($content)); $assetInstance = $this->registry->createAsset($name, '', $options, $attributes, $dependencies); $assetInstance->setOption('content', $content); } else { throw new \InvalidArgumentException( sprintf( '%s(): Argument #2 ($content) must be a string or an instance of %s, %s given.', __METHOD__, WebAssetItemInterface::class, \is_object($content) ? \get_class($content) : \gettype($content) ) ); } // Get the name $asset = $assetInstance->getName(); // Set required options $assetInstance->setOption('type', $type); $assetInstance->setOption('inline', true); // Add to registry $this->registry->add($type, $assetInstance); // And make active $this->useAsset($type, $asset); return $this; } /** * Lock the manager to prevent further modifications * * @return self * * @since 4.0.0 */ public function lock(): self { $this->locked = true; return $this; } /** * Get the manager state. A collection of registry files and active asset names (per type). * * @return array * * @since 4.0.0 */ public function getManagerState(): array { return [ 'registryFiles' => $this->getRegistry()->getRegistryFiles(), 'activeAssets' => $this->activeAssets, ]; } /** * Update Dependencies state for all active Assets or only for given * * @param string $type The asset type, script or style * @param WebAssetItem $asset The asset instance to which need to enable dependencies * * @return self * * @since 4.0.0 */ protected function enableDependencies(string $type = null, WebAssetItem $asset = null): self { if ($type === 'preset') { // Preset items already was enabled by usePresetItems() return $this; } if ($asset) { // Get all dependencies of given asset recursively $allDependencies = $this->getDependenciesForAsset($type, $asset, true); foreach ($allDependencies as $depType => $depItems) { foreach ($depItems as $depItem) { // Set dependency state only when it is inactive, to keep a manually activated Asset in their original state if (empty($this->activeAssets[$depType][$depItem->getName()])) { // Add the dependency at the top of the list of active assets $this->activeAssets[$depType] = [$depItem->getName() => static::ASSET_STATE_DEPENDENCY] + $this->activeAssets[$depType]; } } } } else { // Re-Check for dependencies for all active assets // Firstly, filter out only active assets foreach ($this->activeAssets as $type => $activeAsset) { $this->activeAssets[$type] = array_filter( $activeAsset, function ($state) { return $state === WebAssetManager::ASSET_STATE_ACTIVE; } ); } // Secondary, check for dependencies of each active asset // This need to be separated from previous step because we may have "cross type" dependency foreach ($this->activeAssets as $type => $activeAsset) { foreach (array_keys($activeAsset) as $name) { $asset = $this->registry->get($type, $name); $this->enableDependencies($type, $asset); } } $this->dependenciesIsActual = true; } return $this; } /** * Calculate weight of active Assets, by its Dependencies * * @param string $type The asset type, script or style * * @return WebAssetItem[] * * @since 4.0.0 */ protected function calculateOrderOfActiveAssets($type): array { // See https://en.wikipedia.org/wiki/Topological_sorting#Kahn.27s_algorithm $graphOrder = []; $activeAssets = $this->getAssets($type, false); // Get Graph of Outgoing and Incoming connections $connectionsGraph = $this->getConnectionsGraph($activeAssets); $graphOutgoing = $connectionsGraph['outgoing']; $graphIncoming = $connectionsGraph['incoming']; // Make a copy to be used during weight processing $graphIncomingCopy = $graphIncoming; // Find items without incoming connections $emptyIncoming = array_keys( array_filter( $graphIncoming, function ($el) { return !$el; } ) ); // Reverse, to start from a last enabled and move up to a first enabled, this helps to maintain an original sorting $emptyIncoming = array_reverse($emptyIncoming); // Loop through, and sort the graph while ($emptyIncoming) { // Add the node without incoming connection to the result $item = array_shift($emptyIncoming); $graphOrder[] = $item; // Check of each neighbor of the node foreach (array_reverse($graphOutgoing[$item]) as $neighbor) { // Remove incoming connection of already visited node unset($graphIncoming[$neighbor][$item]); // If there no more incoming connections add the node to queue if (empty($graphIncoming[$neighbor])) { $emptyIncoming[] = $neighbor; } } } // Sync Graph order with FIFO order $fifoWeights = []; $graphWeights = []; $requestedWeights = []; foreach (array_keys($this->activeAssets[$type]) as $index => $name) { $fifoWeights[$name] = $index * 10 + 10; } foreach (array_reverse($graphOrder) as $index => $name) { $graphWeights[$name] = $index * 10 + 10; $requestedWeights[$name] = $activeAssets[$name]->getOption('weight') ?: $fifoWeights[$name]; } // Try to set a requested weight, or make it close as possible to requested, but keep the Graph order while ($requestedWeights) { $item = key($requestedWeights); $weight = array_shift($requestedWeights); // Skip empty items if ($weight === null) { continue; } // Check the predecessors (Outgoing vertexes), the weight cannot be lighter than the predecessor have $topBorder = $weight - 1; if (!empty($graphOutgoing[$item])) { $prevWeights = []; foreach ($graphOutgoing[$item] as $pItem) { $prevWeights[] = $graphWeights[$pItem]; } $topBorder = max($prevWeights); } // Calculate a new weight $newWeight = $weight > $topBorder ? $weight : $topBorder + 1; // If a new weight heavier than existing, then we need to update all incoming connections (children) if ($newWeight > $graphWeights[$item] && !empty($graphIncomingCopy[$item])) { // Sort Graph of incoming by actual position foreach ($graphIncomingCopy[$item] as $incomingItem) { // Set a weight heavier than current, then this node to be processed in next iteration if (empty($requestedWeights[$incomingItem])) { $requestedWeights[$incomingItem] = $graphWeights[$incomingItem] + $newWeight; } } } // Set a new weight $graphWeights[$item] = $newWeight; } asort($graphWeights); // Get Assets in calculated order $resultAssets = []; foreach (array_keys($graphWeights) as $name) { $resultAssets[$name] = $activeAssets[$name]; } return $resultAssets; } /** * Build Graph of Outgoing and Incoming connections for given assets. * * @param WebAssetItem[] $assets Asset instances * * @return array * * @since 4.0.0 */ protected function getConnectionsGraph(array $assets): array { $graphOutgoing = []; $graphIncoming = []; foreach ($assets as $asset) { $name = $asset->getName(); // Initialise an array for outgoing nodes of the asset $graphOutgoing[$name] = []; // Initialise an array for incoming nodes of the asset if (!\array_key_exists($name, $graphIncoming)) { $graphIncoming[$name] = []; } // Collect an outgoing/incoming nodes foreach ($asset->getDependencies() as $depName) { $graphOutgoing[$name][$depName] = $depName; $graphIncoming[$depName][$name] = $name; } } return [ 'outgoing' => $graphOutgoing, 'incoming' => $graphIncoming, ]; } /** * Return dependencies for Asset as array of WebAssetItem objects * * @param string $type The asset type, script or style * @param WebAssetItem $asset Asset instance * @param boolean $recursively Whether to search for dependency recursively * @param string $recursionType The type of initial item to prevent loop * @param WebAssetItem $recursionRoot Initial item to prevent loop * * @return array * * @throws UnsatisfiedDependencyException When Dependency cannot be found * * @since 4.0.0 */ protected function getDependenciesForAsset( string $type, WebAssetItem $asset, $recursively = false, string $recursionType = null, WebAssetItem $recursionRoot = null ): array { $assets = []; $recursionRoot = $recursionRoot ?? $asset; $recursionType = $recursionType ?? $type; foreach ($asset->getDependencies() as $depName) { $depType = $type; // Skip already loaded in recursion if ($recursionRoot->getName() === $depName && $recursionType === $depType) { continue; } if (!$this->registry->exists($depType, $depName)) { throw new UnsatisfiedDependencyException( sprintf('Unsatisfied dependency "%s" for an asset "%s" of type "%s"', $depName, $asset->getName(), $depType) ); } $dep = $this->registry->get($depType, $depName); $assets[$depType][$depName] = $dep; if (!$recursively) { continue; } $parentDeps = $this->getDependenciesForAsset($depType, $dep, true, $recursionType, $recursionRoot); $assets = array_replace_recursive($assets, $parentDeps); } return $assets; } } WebAssetItem.php 0000644 00000017073 15172715467 0007640 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\WebAsset; use Joomla\CMS\HTML\HTMLHelper; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Web Asset Item class * * Asset Item are "read only" object, all properties must be set through class constructor. * Only properties allowed to be edited is an attributes and an options. * Changing an uri or a dependencies are not allowed, prefer to create a new asset instance. * * @since 4.0.0 */ class WebAssetItem implements WebAssetItemInterface { /** * Asset name * * @var string $name * @since 4.0.0 */ protected $name = ''; /** * The URI for the asset * * @var string * @since 4.0.0 */ protected $uri = ''; /** * Additional options for the asset * * @var array * @since 4.0.0 */ protected $options = []; /** * Attributes for the asset, to be rendered in the asset's HTML tag * * @var array * @since 4.0.0 */ protected $attributes = []; /** * Asset dependencies * * @var string[] * @since 4.0.0 */ protected $dependencies = []; /** * Asset version * * @var string * @since 4.0.0 */ protected $version = 'auto'; /** * Class constructor * * @param string $name The asset name * @param string $uri The URI for the asset * @param array $options Additional options for the asset * @param array $attributes Attributes for the asset * @param array $dependencies Asset dependencies * * @since 4.0.0 */ public function __construct( string $name, string $uri = null, array $options = [], array $attributes = [], array $dependencies = [] ) { $this->name = $name; $this->uri = $uri; if (array_key_exists('version', $options)) { $this->version = $options['version']; unset($options['version']); } if (array_key_exists('attributes', $options)) { $this->attributes = (array) $options['attributes']; unset($options['attributes']); } else { $this->attributes = $attributes; } if (array_key_exists('dependencies', $options)) { $this->dependencies = (array) $options['dependencies']; unset($options['dependencies']); } else { $this->dependencies = $dependencies; } $this->options = $options; } /** * Return Asset name * * @return string * * @since 4.0.0 */ public function getName(): string { return $this->name; } /** * Return Asset version * * @return string * * @since 4.0.0 */ public function getVersion(): string { return (string) $this->version; } /** * Return dependencies list * * @return array * * @since 4.0.0 */ public function getDependencies(): array { return $this->dependencies; } /** * Get the file path * * @param boolean $resolvePath Whether need to search for a real paths * * @return string The resolved path if resolved, else an empty string. * * @since 4.0.0 */ public function getUri($resolvePath = true): string { $path = $this->uri; if ($resolvePath && $path) { switch (pathinfo($path, PATHINFO_EXTENSION)) { case 'js': $path = $this->resolvePath($path, 'script'); break; case 'css': $path = $this->resolvePath($path, 'stylesheet'); break; default: break; } } return $path ?? ''; } /** * Get the option * * @param string $key An option key * @param string $default A default value * * @return mixed * * @since 4.0.0 */ public function getOption(string $key, $default = null) { if (array_key_exists($key, $this->options)) { return $this->options[$key]; } return $default; } /** * Set the option * * @param string $key An option key * @param string $value An option value * * @return self * * @since 4.0.0 */ public function setOption(string $key, $value = null): WebAssetItemInterface { $this->options[$key] = $value; return $this; } /** * Get all options * * @return array * * @since 4.0.0 */ public function getOptions(): array { return $this->options; } /** * Get the attribute * * @param string $key An attributes key * @param string $default A default value * * @return mixed * * @since 4.0.0 */ public function getAttribute(string $key, $default = null) { if (array_key_exists($key, $this->attributes)) { return $this->attributes[$key]; } return $default; } /** * Set the attribute * * @param string $key An attribute key * @param string $value An attribute value * * @return self * * @since 4.0.0 */ public function setAttribute(string $key, $value = null): WebAssetItemInterface { $this->attributes[$key] = $value; return $this; } /** * Get all attributes * * @return array * * @since 4.0.0 */ public function getAttributes(): array { return $this->attributes; } /** * Resolve path * * @param string $path The path to resolve * @param string $type The resolver method * * @return string * * @since 4.0.0 */ protected function resolvePath(string $path, string $type): string { if ($type !== 'script' && $type !== 'stylesheet') { throw new \UnexpectedValueException('Unexpected [type], expected "script" or "stylesheet"'); } $file = $path; $external = $this->isPathExternal($path); if (!$external) { // Get the file path $file = HTMLHelper::_( $type, $path, [ 'pathOnly' => true, 'relative' => !$this->isPathAbsolute($path), ] ); } return $file ?? ''; } /** * Check if the Path is External * * @param string $path Path to test * * @return boolean * * @since 4.0.0 */ protected function isPathExternal(string $path): bool { return strpos($path, 'http://') === 0 || strpos($path, 'https://') === 0 || strpos($path, '//') === 0; } /** * Check if the Path is relative to /media folder or absolute * * @param string $path Path to test * * @return boolean * * @since 4.0.0 */ protected function isPathAbsolute(string $path): bool { // We have a full path or not return strpos($path, '/') !== false && is_file(JPATH_ROOT . '/' . $path); } } WebAssetAttachBehaviorInterface.php 0000644 00000001420 15172715467 0013434 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\WebAsset; use Joomla\CMS\Document\Document; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Web Asset Behavior interface * * @since 4.0.0 */ interface WebAssetAttachBehaviorInterface { /** * Method called when asset attached to the Document. * Useful for Asset to add a Script options. * * @param Document $doc Active document * * @return void * * @since 4.0.0 */ public function onAttachCallback(Document $doc); }
| ver. 1.4 |
Github
|
.
| PHP 8.3.23 | Generation time: 0 |
proxy
|
phpinfo
|
Settings