Version 1
[yaffs-website] / web / modules / contrib / advagg / src / Asset / AssetResolver.php
diff --git a/web/modules/contrib/advagg/src/Asset/AssetResolver.php b/web/modules/contrib/advagg/src/Asset/AssetResolver.php
new file mode 100644 (file)
index 0000000..a28bee4
--- /dev/null
@@ -0,0 +1,311 @@
+<?php
+
+namespace Drupal\advagg\Asset;
+
+use Drupal\Core\Asset\AssetCollectionOptimizerInterface;
+use Drupal\Core\Asset\AssetResolver as CoreAssetResolver;
+use Drupal\Core\Asset\AssetResolverInterface;
+use Drupal\Core\Asset\AttachedAssetsInterface;
+use Drupal\Core\Asset\LibraryDiscoveryInterface;
+use Drupal\Core\Asset\LibraryDependencyResolverInterface;
+use Drupal\Component\Utility\Crypt;
+use Drupal\Component\Utility\NestedArray;
+use Drupal\Core\Cache\CacheBackendInterface;
+use Drupal\Core\Extension\ModuleHandlerInterface;
+use Drupal\Core\Language\LanguageManagerInterface;
+use Drupal\Core\Theme\ThemeManagerInterface;
+use Drupal\Core\State\StateInterface;
+
+/**
+ * The default asset resolver.
+ */
+class AssetResolver extends CoreAssetResolver implements AssetResolverInterface {
+
+  /**
+   * The CSS collection optimizer.
+   *
+   * @var \Drupal\Core\Asset\AssetCollectionOptimizerInterface
+   */
+  protected $cssCollectionOptimizer;
+
+  /**
+   * The JS collection optimizer.
+   *
+   * @var \Drupal\Core\Asset\AssetCollectionOptimizerInterface
+   */
+  protected $jsCollectionOptimizer;
+
+  /**
+   * The AdvAgg file status state information storage service.
+   *
+   * @var \Drupal\Core\State\StateInterface
+   */
+  protected $advaggFiles;
+
+  /**
+   * Constructs a new AssetResolver instance.
+   *
+   * @param \Drupal\Core\Asset\LibraryDiscoveryInterface $library_discovery
+   *   The library discovery service.
+   * @param \Drupal\Core\Asset\LibraryDependencyResolverInterface $library_dependency_resolver
+   *   The library dependency resolver.
+   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
+   *   The module handler.
+   * @param \Drupal\Core\Theme\ThemeManagerInterface $theme_manager
+   *   The theme manager.
+   * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
+   *   The language manager.
+   * @param \Drupal\Core\Cache\CacheBackendInterface $cache
+   *   The cache backend.
+   * @param \Drupal\Core\Asset\AssetCollectionOptimizerInterface $css_collection_optimizer
+   *   The CSS collection optimizer.
+   * @param \Drupal\Core\Asset\AssetCollectionOptimizerInterface $js_collection_optimizer
+   *   The JS collection optimizer.
+   * @param \Drupal\Core\State\StateInterface $advagg_files
+   *   The AdvAgg file status state information storage service.
+   */
+  public function __construct(LibraryDiscoveryInterface $library_discovery, LibraryDependencyResolverInterface $library_dependency_resolver, ModuleHandlerInterface $module_handler, ThemeManagerInterface $theme_manager, LanguageManagerInterface $language_manager, CacheBackendInterface $cache, AssetCollectionOptimizerInterface $css_collection_optimizer, AssetCollectionOptimizerInterface $js_collection_optimizer, StateInterface $advagg_files) {
+    $this->libraryDiscovery = $library_discovery;
+    $this->libraryDependencyResolver = $library_dependency_resolver;
+    $this->moduleHandler = $module_handler;
+    $this->themeManager = $theme_manager;
+    $this->languageManager = $language_manager;
+    $this->cache = $cache;
+    $this->cssCollectionOptimizer = $css_collection_optimizer;
+    $this->jsCollectionOptimizer = $js_collection_optimizer;
+    $this->advaggFiles = $advagg_files;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getCssAssets(AttachedAssetsInterface $assets, $optimize) {
+    $theme_info = $this->themeManager->getActiveTheme();
+    // Add the theme name to the cache key since themes may implement
+    // hook_css_alter().
+    $libraries_to_load = $this->getLibrariesToLoad($assets);
+    $cid = 'css:' . $theme_info->getName() . ':' . Crypt::hashBase64(serialize($libraries_to_load)) . (int) $optimize;
+    if ($cached = $this->cache->get($cid)) {
+      return $cached->data;
+    }
+
+    $css = [];
+    $default_options = [
+      'type' => 'file',
+      'group' => CSS_AGGREGATE_DEFAULT,
+      'weight' => 0,
+      'media' => 'all',
+      'preprocess' => TRUE,
+      'browsers' => [],
+    ];
+
+    foreach ($libraries_to_load as $library) {
+      list($extension, $name) = explode('/', $library, 2);
+      $definition = $this->libraryDiscovery->getLibraryByName($extension, $name);
+      if (isset($definition['css'])) {
+        foreach ($definition['css'] as $options) {
+          $options += $default_options;
+          $options['browsers'] += [
+            'IE' => TRUE,
+            '!IE' => TRUE,
+          ];
+
+          // Files with a query string cannot be preprocessed.
+          if ($options['type'] === 'file' && $options['preprocess'] && strpos($options['data'], '?') !== FALSE) {
+            $options['preprocess'] = FALSE;
+          }
+
+          // Always add a tiny value to the weight, to conserve the insertion
+          // order.
+          $options['weight'] += count($css) / 1000;
+
+          // CSS files are being keyed by the full path.
+          $css[$options['data']] = $options;
+        }
+      }
+    }
+
+    // Allow modules and themes to alter the CSS assets.
+    $this->moduleHandler->alter('css', $css, $assets);
+    $this->themeManager->alter('css', $css, $assets);
+
+    // After alter get file information (in case alter changes things).
+    $this->advaggFiles->getMultiple(array_column($css, 'data'));
+
+    // Sort CSS items, so that they appear in the correct order.
+    uasort($css, 'static::sort');
+
+    // Allow themes to remove CSS files by CSS files full path and file name.
+    // @todo Remove in Drupal 9.0.x.
+    if ($stylesheet_remove = $theme_info->getStyleSheetsRemove()) {
+      foreach ($css as $key => $options) {
+        if (isset($stylesheet_remove[$key])) {
+          unset($css[$key]);
+        }
+      }
+    }
+
+    if ($optimize) {
+      $css = $this->cssCollectionOptimizer->optimize($css);
+    }
+    $this->cache->set($cid, $css, CacheBackendInterface::CACHE_PERMANENT, ['library_info']);
+
+    return $css;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getJsAssets(AttachedAssetsInterface $assets, $optimize) {
+    $theme_info = $this->themeManager->getActiveTheme();
+    // Add the theme name to the cache key since themes may implement
+    // hook_js_alter(). Additionally add the current language to support
+    // translation of JavaScript files.
+    $libraries_to_load = $this->getLibrariesToLoad($assets);
+    $cid = 'js:' . $theme_info->getName() . ':' . $this->languageManager->getCurrentLanguage()->getId() . ':' . Crypt::hashBase64(serialize($libraries_to_load)) . (int) (count($assets->getSettings()) > 0) . (int) $optimize;
+
+    if ($cached = $this->cache->get($cid)) {
+      list($js_assets_header, $js_assets_footer, $settings, $settings_in_header) = $cached->data;
+    }
+    else {
+      $javascript = [];
+      $default_options = [
+        'type' => 'file',
+        'group' => JS_DEFAULT,
+        'weight' => 0,
+        'cache' => TRUE,
+        'preprocess' => TRUE,
+        'attributes' => [],
+        'version' => NULL,
+        'browsers' => [],
+      ];
+
+      // Collect all libraries that contain JS assets and are in the header.
+      $header_js_libraries = [];
+      foreach ($libraries_to_load as $library) {
+        list($extension, $name) = explode('/', $library, 2);
+        $definition = $this->libraryDiscovery->getLibraryByName($extension, $name);
+        if (isset($definition['js']) && !empty($definition['header'])) {
+          $header_js_libraries[] = $library;
+        }
+      }
+      // The current list of header JS libraries are only those libraries that
+      // are in the header, but their dependencies must also be loaded for them
+      // to function correctly, so update the list with those.
+      $header_js_libraries = $this->libraryDependencyResolver->getLibrariesWithDependencies($header_js_libraries);
+
+      foreach ($libraries_to_load as $library) {
+        list($extension, $name) = explode('/', $library, 2);
+        $definition = $this->libraryDiscovery->getLibraryByName($extension, $name);
+        if (isset($definition['js'])) {
+          foreach ($definition['js'] as $options) {
+            $options += $default_options;
+
+            // 'scope' is a calculated option, based on which libraries are
+            // marked to be loaded from the header (see above).
+            $options['scope'] = in_array($library, $header_js_libraries) ? 'header' : 'footer';
+
+            // Preprocess can only be set if caching is enabled and no
+            // attributes are set.
+            $options['preprocess'] = $options['cache'] && empty($options['attributes']) ? $options['preprocess'] : FALSE;
+
+            // Always add a tiny value to the weight, to conserve the insertion
+            // order.
+            $options['weight'] += count($javascript) / 1000;
+
+            // Local and external files must keep their name as the associative
+            // key so the same JavaScript file is not added twice.
+            $javascript[$options['data']] = $options;
+          }
+        }
+      }
+
+      // Allow modules and themes to alter the JavaScript assets.
+      $this->moduleHandler->alter('js', $javascript, $assets);
+      $this->themeManager->alter('js', $javascript, $assets);
+
+      // After alter get file information (in case alter changes things).
+      $this->advaggFiles->getMultiple(array_column($javascript, 'data'));
+
+      // Sort JavaScript assets, so that they appear in the correct order.
+      uasort($javascript, 'static::sort');
+
+      // Prepare the return value: filter JavaScript assets per scope.
+      $js_assets_header = [];
+      $js_assets_footer = [];
+      foreach ($javascript as $key => $item) {
+        if ($item['scope'] == 'header') {
+          $js_assets_header[$key] = $item;
+        }
+        elseif ($item['scope'] == 'footer') {
+          $js_assets_footer[$key] = $item;
+        }
+      }
+
+      if ($optimize) {
+        $js_assets_header = $this->jsCollectionOptimizer->optimize($js_assets_header);
+        $js_assets_footer = $this->jsCollectionOptimizer->optimize($js_assets_footer);
+      }
+
+      // If the core/drupalSettings library is being loaded or is already
+      // loaded, get the JavaScript settings assets, and convert them into a
+      // single "regular" JavaScript asset.
+      $libraries_to_load = $this->getLibrariesToLoad($assets);
+      $settings_required = in_array('core/drupalSettings', $libraries_to_load) || in_array('core/drupalSettings', $this->libraryDependencyResolver->getLibrariesWithDependencies($assets->getAlreadyLoadedLibraries()));
+      $settings_have_changed = count($libraries_to_load) > 0 || count($assets->getSettings()) > 0;
+
+      // Initialize settings to FALSE since they are not needed by default. This
+      // distinguishes between an empty array which must still allow
+      // hook_js_settings_alter() to be run.
+      $settings = FALSE;
+      if ($settings_required && $settings_have_changed) {
+        $settings = $this->getJsSettingsAssets($assets);
+        // Allow modules to add cached JavaScript settings.
+        foreach ($this->moduleHandler->getImplementations('js_settings_build') as $module) {
+          $function = $module . '_js_settings_build';
+          $function($settings, $assets);
+        }
+      }
+      $settings_in_header = in_array('core/drupalSettings', $header_js_libraries);
+      $this->cache->set($cid, [
+        $js_assets_header,
+        $js_assets_footer,
+        $settings,
+        $settings_in_header,
+      ], CacheBackendInterface::CACHE_PERMANENT, ['library_info']);
+    }
+
+    if ($settings !== FALSE) {
+      // Attached settings override both library definitions and
+      // hook_js_settings_build().
+      $settings = NestedArray::mergeDeepArray([$settings, $assets->getSettings()], TRUE);
+      // Allow modules and themes to alter the JavaScript settings.
+      $this->moduleHandler->alter('js_settings', $settings, $assets);
+      $this->themeManager->alter('js_settings', $settings, $assets);
+      // Update the $assets object accordingly, so that it reflects the final
+      // settings.
+      $assets->setSettings($settings);
+      $settings_as_inline_javascript = [
+        'type' => 'setting',
+        'group' => JS_SETTING,
+        'weight' => 0,
+        'browsers' => [],
+        'data' => $settings,
+      ];
+      $settings_js_asset = ['drupalSettings' => $settings_as_inline_javascript];
+      // Prepend to the list of JS assets, to render it first. Preferably in
+      // the footer, but in the header if necessary.
+      if ($settings_in_header) {
+        $js_assets_header = $settings_js_asset + $js_assets_header;
+      }
+      else {
+        $js_assets_footer = $settings_js_asset + $js_assets_footer;
+      }
+    }
+    return [
+      $js_assets_header,
+      $js_assets_footer,
+    ];
+  }
+
+}