diff --git a/administrator/templates/atum/joomla.asset.json b/administrator/templates/atum/joomla.asset.json index 9c17c08429ad0..ad6295aa2e558 100644 --- a/administrator/templates/atum/joomla.asset.json +++ b/administrator/templates/atum/joomla.asset.json @@ -14,7 +14,8 @@ "bootstrap.js.bundle", "css-vars-ponyfill" ], - "js": [] + "js": [], + "weight": 10000 }, "template.atum.ltr": { "name": "template.atum.ltr", diff --git a/build/media_src/system/joomla.asset.json b/build/media_src/system/joomla.asset.json index a2b3c9b371780..3624ff3ce7fca 100644 --- a/build/media_src/system/joomla.asset.json +++ b/build/media_src/system/joomla.asset.json @@ -8,7 +8,8 @@ "name": "core", "js": [ "media/system/js/core.min.js" - ] + ], + "weight": 70 }, "keepalive": { "name": "keepalive", diff --git a/libraries/src/WebAsset/WebAssetItem.php b/libraries/src/WebAsset/WebAssetItem.php index ad56b334b231f..d599febad33a7 100644 --- a/libraries/src/WebAsset/WebAssetItem.php +++ b/libraries/src/WebAsset/WebAssetItem.php @@ -160,6 +160,11 @@ public function __construct(string $name, array $data = []) { $this->dependencies = (array) $data['dependencies']; } + + if (!empty($data['weight'])) + { + $this->weight = (float) $data['weight']; + } } /** diff --git a/libraries/src/WebAsset/WebAssetRegistry.php b/libraries/src/WebAsset/WebAssetRegistry.php index 0fa100e229d9a..b9b59942f4b7f 100644 --- a/libraries/src/WebAsset/WebAssetRegistry.php +++ b/libraries/src/WebAsset/WebAssetRegistry.php @@ -25,33 +25,6 @@ class WebAssetRegistry implements DispatcherAwareInterface { use DispatcherAwareTrait; - /** - * Mark the new registry file - * - * @var integer - * - * @since 4.0.0 - */ - const REGISTRY_FILE_NEW = 1; - - /** - * Mark already parsed registry file - * - * @var integer - * - * @since 4.0.0 - */ - const REGISTRY_FILE_PARSED = 2; - - /** - * Mark a broken/non-existing registry file - * - * @var integer - * - * @since 4.0.0 - */ - const REGISTRY_FILE_INVALID = -1; - /** * Files with Asset info. File path should be relative. * @@ -98,7 +71,16 @@ class WebAssetRegistry implements DispatcherAwareInterface * * @since 4.0.0 */ - protected $dataFiles = []; + protected $dataFilesNew = []; + + /** + * List of parsed files + * + * @var array + * + * @since 4.0.0 + */ + protected $dataFilesParsed = []; /** * Registry of available Assets @@ -457,6 +439,9 @@ protected function calculateWeightOfActiveAssets(): self } } + // Make a copy to be used during weight processing + $graphIncomingCopy = $graphIncoming; + // Find items without incoming connections $emptyIncoming = array_keys( array_filter( @@ -489,16 +474,69 @@ function ($el){ } // Update a weight for each active asset + $requestedWeights = []; foreach (array_reverse($result) as $index => $name) { - $activeAssets[$name]->setWeight($index + 1); + // Check for existing/requested weight + $requestedWeights[$name] = null; + if ($activeAssets[$name]->getWeight()) + { + $requestedWeights[$name] = $activeAssets[$name]->getWeight(); + } + + $activeAssets[$name]->setWeight($index * 10 + 100); + } + + // 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[] = $activeAssets[$pItem]->getWeight(); + } + $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 > $activeAssets[$item]->getWeight() && !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] = $activeAssets[$incomingItem]->getWeight() + $newWeight; + } + } + } + + // Set a new weight + $activeAssets[$item]->setWeight($newWeight); } return $this; } /** - * Return dependancy for Asset as array of AssetItem objects + * Return dependency for Asset as array of AssetItem objects * * @param WebAssetItem $asset Asset instance * @param boolean $recursively Whether to search for dependancy recursively @@ -601,12 +639,15 @@ public function addRegistryFile(string $path): self { $path = Path::clean($path); - if (isset($this->dataFiles[$path])) + if (isset($this->dataFilesNew[$path]) || isset($this->dataFilesParsed[$path])) { return $this; } - $this->dataFiles[$path] = is_file(JPATH_ROOT . '/' . $path) ? static::REGISTRY_FILE_NEW : static::REGISTRY_FILE_INVALID; + if (is_file(JPATH_ROOT . '/' . $path)) + { + $this->dataFilesNew[$path] = $path; + } return $this; } @@ -620,27 +661,18 @@ public function addRegistryFile(string $path): self */ protected function parseRegistryFiles() { - // Filter new asset data files and parse each - $constantIsNew = static::REGISTRY_FILE_NEW; - $files = array_filter( - $this->dataFiles, - function($state) use ($constantIsNew) - { - return $state === $constantIsNew; - } - ); - - if (!$files) + if (!$this->dataFilesNew) { return; } - foreach (array_keys($files) as $path) + foreach ($this->dataFilesNew as $path) { $this->parseRegistryFile($path); // Mark as parsed (not new) - $this->dataFiles[$path] = static::REGISTRY_FILE_PARSED; + unset($this->dataFilesNew[$path]); + $this->dataFilesParsed[$path] = $path; } } diff --git a/templates/cassiopeia/joomla.asset.json b/templates/cassiopeia/joomla.asset.json index 02833c5927458..9e5fdc9fb6804 100644 --- a/templates/cassiopeia/joomla.asset.json +++ b/templates/cassiopeia/joomla.asset.json @@ -15,7 +15,8 @@ "js": [ "template.js", "user.js" - ] + ], + "weight": 10000 }, "template.cassiopeia.ltr": { "name": "template.cassiopeia.ltr",