Skip to content
Snippets Groups Projects
Commit e8d0fc31 authored by Frank Mably's avatar Frank Mably
Browse files

Issue #3513304 by mably: Generate a javascript file containing only the active services

parent a7326982
No related branches found
No related tags found
1 merge request!29Issue #3513304 by mably: Generate a javascript file containing only the active services
Pipeline #452357 passed
......@@ -3,6 +3,7 @@ cookieslist
dailymotion
ferank
informations
mably
multiplegtag
recommanded
ressources
......
......@@ -7,6 +7,8 @@ tacjs.settings:
expire:
type: integer
label: 'Expire'
active:
type: tacjs_active
texts:
type: tacjs_texts
services:
......@@ -287,6 +289,16 @@ tacjs_texts:
type: text
label: 'credit'
tacjs_active:
type: mapping
mapping:
generate:
type: boolean
label: 'Generate active services JS file'
suffix:
type: string
label: 'Suffix to add to the generated JS file'
tacjs_service:
type: mapping
label: 'TacJS services'
......
......@@ -2,6 +2,7 @@
namespace Drupal\tacjs\Form\Steps;
use Drupal\Core\Asset\LibraryDiscoveryInterface;
use Drupal\Core\Config\Config;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Form\ConfigFormBase;
......@@ -32,6 +33,13 @@ class AddServices extends ConfigFormBase {
*/
protected $moduleHandler;
/**
* The library discovery collector service.
*
* @var \Drupal\Core\Asset\LibraryDiscoveryInterface
*/
protected $libraryDiscovery;
/**
* The tarteaucitron.js services.
*
......@@ -46,10 +54,17 @@ class AddServices extends ConfigFormBase {
* The language manager.
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
* The module handler.
* @param \Drupal\Core\Asset\LibraryDiscoveryInterface $library_discovery
* The library discovery collector service.
*/
public function __construct(LanguageManagerInterface $language_manager, ModuleHandlerInterface $module_handler) {
public function __construct(
LanguageManagerInterface $language_manager,
ModuleHandlerInterface $module_handler,
LibraryDiscoveryInterface $library_discovery,
) {
$this->languageManager = $language_manager;
$this->moduleHandler = $module_handler;
$this->libraryDiscovery = $library_discovery;
$this->content = $this->getContent();
}
......@@ -59,7 +74,8 @@ class AddServices extends ConfigFormBase {
public static function create(ContainerInterface $container) {
return new static(
$container->get('language_manager'),
$container->get('module_handler')
$container->get('module_handler'),
$container->get('library.discovery'),
);
}
......@@ -275,6 +291,13 @@ class AddServices extends ConfigFormBase {
$config->save();
parent::submitForm($form, $form_state);
// Generate the active services JavaScript file.
if ($config->get('active.generate')) {
_tacjs_generate_active_services_file($config);
// Clear the library cache.
$this->libraryDiscovery->clear();
}
}
/**
......@@ -300,7 +323,7 @@ class AddServices extends ConfigFormBase {
$content = Json::decode($content_json);
// Allow modules to inject custom services into settings form.
// Allow modules to inject custom services into the settings form.
$this->moduleHandler->alter('tacjs_content', $content);
return $content;
......
......@@ -266,6 +266,13 @@ class ManageDialog extends ConfigFormBase {
'#min' => 1,
'#max' => 365,
];
$form['advanced']['activeGenerate'] = [
'#type' => 'checkbox',
'#title' => $this->t('Generate a JavaScript file containing only the active services (EXPERIMENTAL)'),
'#description' => $this->t('If checked, a new JavaScript file will be generated containing only the active TarteAuCitron services.'),
'#default_value' => $config->get('active.generate') ?? FALSE,
];
}
/**
......@@ -299,7 +306,8 @@ class ManageDialog extends ConfigFormBase {
->setValue('useExternalJs', $form_state->getValue('useExternalJs') ? TRUE : FALSE)
->setValue('mandatory', $form_state->getValue('mandatory') ? TRUE : FALSE)
->setValue('closePopup', $form_state->getValue('closePopup') ? TRUE : FALSE)
->setValue('expire', (int) $form_state->getValue('expire') ?: NULL);
->setValue('expire', (int) $form_state->getValue('expire') ?: NULL)
->setValue('activeGenerate', (bool) $form_state->getValue('activeGenerate'));
parent::validateForm($form, $form_state);
}
......@@ -337,7 +345,10 @@ class ManageDialog extends ConfigFormBase {
->set('dialog.mandatoryCta', $form_state->getValue('mandatoryCta'))
->set('dialog.closePopup', $form_state->getValue('closePopup'))
->set('dialog.customCloserId', $form_state->getValue('customCloserId'))
->set('expire', $form_state->getValue('expire'));
->set('expire', $form_state->getValue('expire'))
->set('active.generate', $form_state->getValue('activeGenerate'))
// The suffix is needed to be able to handle multiple services files.
->set('active.suffix', 'default');
}
/**
......
......@@ -20,3 +20,23 @@ function hook_tacjs_content_alter(array &$content) {
],
];
}
/**
* Implements hook_tacjs_services_alter().
*/
function hook_tacjs_services_alter(array &$services) {
// Path to the module JavaScript file containing my custom services.
$tacjs_path = \Drupal::service('extension.list.module')->getPath('my_module');
$inputFile = $tacjs_path . '/js/my_custom_services.js';
$jsContent = file_get_contents($inputFile);
$pattern = '/tarteaucitron\.services\.(\w+)\s*=\s*\{\s*\n?([\s\S]*?)\n\};/m';
preg_match_all($pattern, $jsContent, $matches, PREG_SET_ORDER);
foreach ($matches as $match) {
$serviceName = $match[1];
$services[$serviceName] =
"tarteaucitron.services." . $serviceName . " = {\n" . $match[2] . "\n};";
}
}
......@@ -2,9 +2,5 @@ name: TacJS
type: module
description: 'Comply to the European cookie law using tarteaucitron.js'
package: GDPR
<<<<<<< HEAD
core_version_requirement: ^9.3 || ^10
=======
core_version_requirement: ^8.8 || ^9 || ^10 || ^11
>>>>>>> 4be8563 (Drupal 11 compatibility fixes)
configure: tacjs.manage_dialog
......@@ -7,11 +7,16 @@ tarteaucitron.js:
gpl-compatible: true
js:
assets/vendor/tarteaucitron.js/tarteaucitron.js: {}
assets/vendor/tarteaucitron.js/tarteaucitron.services.js: {}
css:
theme:
assets/vendor/tarteaucitron.js/css/tarteaucitron.css: {}
tarteaucitron.services.js:
js:
assets/vendor/tarteaucitron.js/tarteaucitron.services.js: {}
dependencies:
- tacjs/tarteaucitron.js
fetch:
remote: https://github.com/github/fetch
version: "v3.6.2"
......
......@@ -7,6 +7,8 @@
* Comply to the European cookie law using tarteaucitron.js.
*/
use Drupal\Core\File\FileSystemInterface;
/**
* Implements hook_page_attachments().
*
......@@ -19,9 +21,18 @@ function tacjs_page_attachments(&$page) {
->getCurrentLanguage()
->getId();
// Only send the active services to the browser.
$services = $config->get('services');
$active_services = [];
foreach ($services as $service_name => $service) {
if ($service['status']) {
$active_services[$service_name] = $service;
}
}
$js_settings = [
'dialog' => $config->get('dialog'),
'services' => $config->get('services'),
'services' => $active_services,
// Missing user causes javascript errors #3326860 #3323411.
'user' => $config->get('user') ?? [],
'texts' => $config->get('texts'),
......@@ -42,6 +53,23 @@ function tacjs_page_attachments(&$page) {
// Fall back to english if the current language has no translation.
$page['#attached']['library'][] = 'tacjs/tarteaucitron.en.js';
}
if ($config->get('active.generate')) {
// The suffix is useful to handle multiple generated services files.
// For example, when using the domain module, each domain can have its
// own active services.
$suffix = $config->get('active.suffix');
$active_filename = 'tarteaucitron.active.services.' . $suffix . '.js';
if (isset($libraries[$active_filename])) {
$page['#attached']['library'][] = 'tacjs/' . $active_filename;
}
else {
$page['#attached']['library'][] = 'tacjs/tarteaucitron.services.js';
}
}
else {
$page['#attached']['library'][] = 'tacjs/tarteaucitron.services.js';
}
}
}
......@@ -56,8 +84,8 @@ function tacjs_library_info_build() {
/** @var \Drupal\Core\File\FileSystemInterface $fileSystem */
$fileSystem = \Drupal::service('file_system');
foreach ($fileSystem->scanDirectory(\Drupal::service('extension.list.module')
->getPath('tacjs') . '/assets/vendor/tarteaucitron.js/lang/', '/tarteaucitron\.(\w+)\.js/') as $file) {
$tacjs_path = \Drupal::service('extension.list.module')->getPath('tacjs');
foreach ($fileSystem->scanDirectory($tacjs_path . '/assets/vendor/tarteaucitron.js/lang/', '/tarteaucitron\.(\w+)\.js/') as $file) {
$libraries[$file->filename] = [
'js' => [
'/' . $file->uri => [],
......@@ -68,5 +96,88 @@ function tacjs_library_info_build() {
];
}
$file_url_generator = \Drupal::service('file_url_generator');
foreach ($fileSystem->scanDirectory(
'public://tacjs', '/tarteaucitron\.active\.services\.(\w+)\.js/') as $file
) {
$path = $file_url_generator->generateAbsoluteString($file->uri);
$file_path = str_replace(base_path(), '/', parse_url($path, PHP_URL_PATH));
$libraries[$file->filename] = [
'js' => [
$file_path => [],
],
'dependencies' => [
'tacjs/tarteaucitron.js',
],
];
}
return $libraries;
}
/**
* Extract TarteAuCitron services from a JavaScript file.
*
* @param array $services
* The array where the extracted services will be added.
* @param array $file_path
* The path to the JavaScript files containing the service definitions.
*/
function _tacjs_extract_services_from_file(array &$services, string $file_path) {
// Read the JavaScript file.
$javascript_content = file_get_contents($file_path);
if ($javascript_content) {
// Match service definitions spanning multiple lines.
$pattern = '/tarteaucitron\.services\.(\w+)\s*=\s*\{\s*\n?([\s\S]*?)\n};/m';
preg_match_all($pattern, $javascript_content, $matches, PREG_SET_ORDER);
foreach ($matches as $match) {
// Extracted service name.
$service_name = $match[1];
// Rebuild the service definition.
$services[$service_name] =
"tarteaucitron.services." . $service_name . " = {\n" . $match[2] . "\n};";
}
}
}
/**
* Generates an active services JavaScript file.
*
* @param \Drupal\Core\Config\Config $config
* The tacjs module configuration file.
*/
function _tacjs_generate_active_services_file($config) {
// Path to the original JavaScript file containing all services.
$tacjs_path = \Drupal::service('extension.list.module')->getPath('tacjs');
$inputFile = $tacjs_path . '/assets/vendor/tarteaucitron.js/tarteaucitron.services.js';
$services = [];
_tacjs_extract_services_from_file($services, $inputFile);
// Allow other modules to inject custom services.
Drupal::service('module_handler')->alter(
'tacjs_services', $services);
$config_services = $config->get('services');
$active_services_javascript = '';
foreach ($config_services as $service_name => $service) {
if ($service['status'] && isset($services[$service_name])) {
$active_services_javascript .= $services[$service_name] . "\n";
}
}
$tacjs_directory = 'public://tacjs';
/** @var \Drupal\Core\File\FileSystemInterface $fileSystem */
$fileSystem = \Drupal::service('file_system');
if ($fileSystem->prepareDirectory($tacjs_directory,
FileSystemInterface:: CREATE_DIRECTORY | FileSystemInterface::MODIFY_PERMISSIONS)) {
$suffix = $config->get('active.suffix') ?? 'default';
$output_file = $tacjs_directory . '/tarteaucitron.active.services.' . $suffix . '.js';
file_put_contents($output_file, $active_services_javascript);
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment