swup-1.0.0-alpha1/swup_ui/swup_ui.module

swup_ui/swup_ui.module
<?php

/**
 * @file
 * Drupal's integration with Swup.js library UI module.
 *
 * Swup is a versatile and extensible page transition library for
 * server-rendered websites. It makes your site feel like a single-page
 * application with smooth transitions between pages.
 *
 * GitHub: https://github.com/swup/swup
 * Website: https://swup.js.org/
 * License: MIT licensed
 *
 * Copyright (C) 2016-2025 Georgy Marchuk
 */

use Drupal\Core\Installer\InstallerKernel;
use Drupal\Core\Link;
use Drupal\Core\Routing\RouteMatchInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;

/**
 * Implements hook_help().
 */
function swup_ui_help($route_name, RouteMatchInterface $route_match) {
  switch ($route_name) {
    case 'help.page.swup_ui':
      $settings = Link::createFromRoute(
        t('settings page'),
        'swup.settings'
      )->toString();

      $output = '<h3>' . t('About') . '</h3>';
      $output .= '<p>' . t(
          'Swup UI provides a configuration interface for the Swup.js library. Use it to control how and where the library is attached.'
        ) . '</p>';

      $output .= '<h3>' . t('Configuration') . '</h3>';
      $output .= '<ul>';
      $output .= '<li>' . t(
          '<strong>Load Swup.js</strong>: Global on/off for auto-attach.'
        ) . '</li>';
      $output .= '<li>' . t(
          '<strong>CDN Provider</strong>: Choose between unpkg or jsDelivr.'
        ) . '</li>';
      $output .= '<li>' . t(
          '<strong>Build variant</strong>: ESM for modern browsers, UMD for older.'
        ) . '</li>';
      $output .= '<li>' . t(
          '<strong>Core & Plugins</strong>: Enable core and optional plugins (JS, Preload, Scripts, Forms, Debug).'
        ) . '</li>';
      $output .= '<li>' . t(
          '<strong>Themes</strong>: Restrict loading to specific themes or all except a list.'
        ) . '</li>';
      $output .= '<li>' . t(
          '<strong>Pages</strong>: Path-based visibility with wildcard support.'
        ) . '</li>';
      $output .= '</ul>';

      $output .= '<h3>' . t('Notes') . '</h3>';
      $output .= '<ul>';
      $output .= '<li>' . t(
          'When core is disabled, global loading is disabled and settings reset to defaults.'
        ) . '</li>';
      $output .= '<li>' . t(
          'Core must be enabled for plugins to work.'
        ) . '</li>';
      $output .= '<li>' . t(
          'Access requires the "@perm" permission.',
          ['@perm' => 'administer swup']
        ) . '</li>';
      $output .= '</ul>';

      $output .= '<p>' . t(
          'Open the @settings to configure.',
          ['@settings' => $settings]
        ) . '</p>';

      return $output;
  }
}

/**
 * Implements hook_page_attachments().
 */
function swup_ui_page_attachments(array &$attachments) {
  // Do not attach libraries during installation.
  if (InstallerKernel::installationAttempted()) {
    return;
  }

  // Read configuration.
  $config = \Drupal::config('swup_ui.settings');

  // Enforce visibility rules and global loading flag.
  if (
    !$config->get('load') ||
    !_swup_ui_check_theme() ||
    !_swup_ui_check_path()
  ) {
    return;
  }

  // Check if local installation exists.
  $local_exists = swup_check_installed();
  $cdn_provider = $config->get('cdn_provider');
  $variant = $config->get('build.variant');
  $plugins = (array) $config->get('plugins');

  // Attach core library.
  if ($config->get('core')) {
    if ($local_exists && $config->get('prefer_local')) {
      // Use local version.
      $lib_id = $variant === 'minified' ? 'swup.local.min' : 'swup.local';
      $attachments['#attached']['library'][] = 'swup/' . $lib_id;
    }
    else {
      // Use CDN version.
      if ($variant === 'esm') {
        $cdn_lib = ($cdn_provider === 'jsdelivr') ? 'swup.cdn.jsdelivr.esm' : 'swup.cdn.esm';
      }
      else {
        $cdn_lib = ($cdn_provider === 'jsdelivr') ? 'swup.cdn.jsdelivr.umd' : 'swup.cdn.umd';
      }
      $attachments['#attached']['library'][] = 'swup/' . $cdn_lib;
    }

    // Attach enabled plugins (only if core is enabled).
    foreach ($plugins as $plugin_name => $enabled) {
      if (!$enabled) {
        continue;
      }
      // All plugins are CDN-only for now.
      $plugin_lib = 'swup.plugin.' . $plugin_name . '.cdn';
      $attachments['#attached']['library'][] = 'swup/' . $plugin_lib;
    }
  }
}

/**
 * Check if Swup should be active for the current URL.
 *
 * @param \Symfony\Component\HttpFoundation\Request $request
 *   The request to use if provided, otherwise \Drupal::request() will be used.
 * @param \Symfony\Component\HttpFoundation\RequestStack $request_stack
 *   The request stack.
 *
 * @return bool
 *   TRUE if Swup should be active for the current page.
 */
function _swup_ui_check_path(Request $request = NULL, RequestStack $request_stack = NULL): bool {
  // Use the provided request or get the current request.
  $request = $request ?: \Drupal::request();

  // Initialize match status as FALSE.
  $page_match = FALSE;

  // Check for the ?swup=no parameter in the URL to deactivate library.
  $query = $request->query;
  if ($query->get('swup') !== NULL && $query->get('swup') == 'no') {
    return $page_match;
  }

  // Load the module configuration.
  $config = \Drupal::config('swup_ui.settings');
  // Get the list of pages where Swup should be active.
  $pages = _swup_ui_array_to_string($config->get('request_path.pages'));
  $pages = $pages ? mb_strtolower($pages) : '';

  // If no specific pages are configured, Swup is active on all pages.
  if (!$pages) {
    return TRUE;
  }

  // Use the provided request stack or get the current request stack.
  $request_stack = $request_stack ?: \Drupal::requestStack();
  $current_request = $request_stack->getCurrentRequest();

  // Get the current path.
  $path = \Drupal::service('path.current')->getPath($current_request);
  // Do not trim the trailing slash if it is the complete path.
  $path = $path === '/' ? $path : rtrim($path, '/');

  // Get the current language code.
  $langcode = \Drupal::languageManager()->getCurrentLanguage()->getId();
  // Get the path alias and convert to lowercase.
  $path_alias = mb_strtolower(\Drupal::service('path_alias.manager')->getAliasByPath($path, $langcode));

  // Check if the path alias matches the configured pages.
  $page_match = \Drupal::service('path.matcher')->matchPath($path_alias, $pages);
  // If the path alias is different from the internal path,
  // check the internal path as well.
  if ($path_alias != $path) {
    $page_match = $page_match || \Drupal::service('path.matcher')->matchPath($path, $pages);
  }

  // Negate the match if configured to load on all pages except those listed.
  $page_match = $config->get('request_path.negate') == 0 ? !$page_match : $page_match;

  return $page_match;
}

/**
 * Verify if the current theme is selected in the module settings.
 *
 * @return bool
 *   TRUE if the current theme is selected, otherwise FALSE.
 */
function _swup_ui_check_theme(): bool {
  // Load the Swup UI module configuration.
  $config = \Drupal::config('swup_ui.settings');

  // Get the name of the active theme.
  $active_theme = \Drupal::theme()->getActiveTheme()->getName();

  // Retrieve the list of valid themes from the configuration.
  $valid_themes = (array) $config->get('theme_groups.themes');

  // If no themes are configured, Swup should be active.
  if (empty($valid_themes) || count($valid_themes) === 0) {
    return TRUE;
  }

  // Get the visibility setting from the configuration.
  $visibility = $config->get('theme_groups.negate');

  // Check if the active theme is in the list of valid themes.
  $theme_match = in_array($active_theme, $valid_themes);

  // With XOR we flip match for "all except" mode.
  return !($visibility xor $theme_match);
}

/**
 * Flatten a multidimensional array to a single-level array.
 *
 * @param array $array
 *   Input array.
 *
 * @return array
 *   Flattened values.
 */
function _swup_ui_array_flatten(array $array): array {
  $result = [];
  array_walk_recursive($array, function ($v) use (&$result) {
    $result[] = $v;
  });
  return $result;
}

/**
 * Convert newline-separated text into an array of trimmed lines.
 *
 * @param string $text
 *   Raw text.
 *
 * @return array|null
 *   Lines or NULL if input is not a string.
 */
function _swup_ui_string_to_array($text): ?array {
  if (!is_string($text)) {
    return NULL;
  }
  $text = str_replace("\r\n", "\n", $text);
  return array_values(array_filter(array_map('trim', explode("\n", $text))));
}

/**
 * Convert an array of lines to CRLF text.
 *
 * @param array $array
 *   Lines.
 *
 * @return string|null
 *   CRLF-joined string or NULL if input is not an array.
 */
function _swup_ui_array_to_string($array): ?string {
  if (!is_array($array)) {
    return NULL;
  }
  return implode("\r\n", array_map('trim', $array));
}

/**
 * Recursively convert arrays/objects to associative arrays.
 *
 * @param mixed $data
 *   Input data.
 *
 * @return array|mixed
 *   Converted array or the original value.
 */
function _swup_ui_object_to_array($data) {
  if (is_array($data) || is_object($data)) {
    $out = [];
    foreach ($data as $k => $v) {
      $out[$k] = _swup_ui_object_to_array($v);
    }
    return $out;
  }
  return $data;
}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc