barbajs-1.0.0-alpha1/barbajs_ui/barbajs_ui.module
barbajs_ui/barbajs_ui.module
<?php
/**
* @file
* Drupal's integration with Barba.js library.
*
* Barba.js - Create badass, fluid and smooth transitions
* between your website’s pages.
*
* GitHub: https://github.com/barbajs/barba
* Website: https://barba.js.org/
* license: MIT licensed
*
* Copyright (C) 2018-2025 Luigi De Rosa
*/
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 barbajs_ui_help($route_name, RouteMatchInterface $route_match) {
switch ($route_name) {
case 'help.page.barbajs_ui':
$settings = Link::createFromRoute(
t('settings page'),
'barba.settings'
)->toString();
$output = '<h3>' . t('About') . '</h3>';
$output .= '<p>' . t(
'Barba JS UI provides a configuration UI for the Barba.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 Barba.js</strong>: Global on/off for auto-attach.'
) . '</li>';
$output .= '<li>' . t(
'<strong>Attach method</strong>: Choose Local or CDN.'
) . '</li>';
$output .= '<li>' . t(
'<strong>Build variant</strong>: Minified or non-minified.'
) . '</li>';
$output .= '<li>' . t(
'<strong>Files</strong>: Core and optional plugins (CSS, Prefetch, Router).'
) . '</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 no files are selected, global loading is disabled and file settings reset to defaults (Core enabled, plugins disabled).'
) . '</li>';
$output .= '<li>' . t(
'Core must be enabled for plugins to work.'
) . '</li>';
$output .= '<li>' . t(
'Access requires the "@perm" permission.',
['@perm' => 'administer barba']
) . '</li>';
$output .= '</ul>';
$output .= '<p>' . t(
'Open the @settings to configure.',
['@settings' => $settings]
) . '</p>';
return $output;
}
}
/**
* Implements hook_page_attachments().
*/
function barbajs_ui_page_attachments(array &$attachments) {
// Do not attach libraries during installation.
if (InstallerKernel::installationAttempted()) {
return;
}
// Read configuration.
$config = \Drupal::config('barbajs_ui.settings');
// Enforce visibility rules and global loading flag.
if (
!$config->get('load') ||
!_barbajs_ui_check_theme() ||
!_barbajs_ui_check_path()
) {
return;
}
// Determine source: local if available, otherwise CDN.
$methods = barbajs_check_installed() ? $config->get('method') : 'cdn';
$plugins = (array) $config->get('file_types');
$variant = $config->get('build.variant') ? '.min' : '';
// Loop through all enabled plugins.
foreach ($plugins as $plugin_name => $enabled) {
if (!$enabled) {
continue;
}
// Map "core" to 'barba' and others to 'barba_<plugin>'.
$lib_id = ($plugin_name === 'core') ? 'barba' : 'barba_' . $plugin_name;
$suffix = ($methods === 'cdn') ? '.cdn' . $variant : $variant;
$attachments['#attached']['library'][] = 'barbajs/' . $lib_id . $suffix;
}
}
/**
* Check if Barba 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 Barba should be active for the current page.
*/
function _barbajs_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 ?barbajs=no parameter in the URL to deactivate library.
$query = $request->query;
if ($query->get('barba') !== NULL && $query->get('barba') == 'no') {
return $page_match;
}
// Load the module configuration.
$config = \Drupal::config('barbajs_ui.settings');
// Get the list of pages where Barba should be active.
$pages = _barbajs_ui_array_to_string($config->get('request_path.pages'));
$pages = $pages ? mb_strtolower($pages) : '';
// If no specific pages are configured, Barba 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 _barbajs_ui_check_theme(): bool {
// Load the BarbaJS UI module configuration.
$config = \Drupal::config('barbajs_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, Barba 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 _barbajs_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 _barbajs_ui_string_to_array($text): array|null {
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 _barbajs_ui_array_to_string($array): string|null {
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 _barbajs_ui_object_to_array($data) {
if (is_array($data) || is_object($data)) {
$out = [];
foreach ($data as $k => $v) {
$out[$k] = _barbajs_ui_object_to_array($v);
}
return $out;
}
return $data;
}
