From 6792be18e66fa3f5fa099253b78de448709643f8 Mon Sep 17 00:00:00 2001 From: Vladimir Roudakov <44088-VladimirAus@users.noreply.drupalcode.org> Date: Thu, 23 May 2024 13:31:25 +0000 Subject: [PATCH] Issue #3405523 by VladimirAus, Jasjeet Kaur Brar, Diwakar07, nitin_lama, jannakha: Add gitlab CI and fix errors --- .cspell-project-words.txt | 12 ++++++ .eslintignore | 2 + .gitlab-ci.yml | 25 ++++++++++++ .stylelintignore | 3 ++ README.md | 2 +- bootstrap5.theme | 15 ++++--- js/nav-tabs.es6.js | 35 ---------------- js/nav-tabs.js | 43 +++++++++++--------- src/Drush/Commands/Bootstrap5Commands.php | 18 +++++++-- src/SettingsManager.php | 13 ++---- src/SubthemeFormManager.php | 21 +++++++++- src/SubthemeManager.php | 49 ++++++++++++++--------- 12 files changed, 142 insertions(+), 96 deletions(-) create mode 100644 .cspell-project-words.txt create mode 100644 .eslintignore create mode 100644 .gitlab-ci.yml create mode 100644 .stylelintignore delete mode 100644 js/nav-tabs.es6.js diff --git a/.cspell-project-words.txt b/.cspell-project-words.txt new file mode 100644 index 00000000..2f150a3f --- /dev/null +++ b/.cspell-project-words.txt @@ -0,0 +1,12 @@ +cheatsheet +commandfile +cpath +csvg +matchmedia +replatform +sglink +subnesting +twbstools +updb +Webform +webform \ No newline at end of file diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 00000000..37d5871d --- /dev/null +++ b/.eslintignore @@ -0,0 +1,2 @@ +bin/** +dist/** diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 00000000..a6d694ec --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,25 @@ +include: + - project: $_GITLAB_TEMPLATES_REPO + ref: $_GITLAB_TEMPLATES_REF + file: + - '/includes/include.drupalci.main.yml' + - '/includes/include.drupalci.variables.yml' + - '/includes/include.drupalci.workflows.yml' + +variables: + _CSPELL_IGNORE_PATHS: '"dist/**", "css/**", "bin/**"' + OPT_IN_TEST_CURRENT: 0 + OPT_IN_TEST_NEXT_MINOR: 1 + OPT_IN_TEST_NEXT_MAJOR: 1 +phpcs: + allow_failure: false +phpstan: + allow_failure: false +phpstan (next minor): + allow_failure: false +phpstan (next major): + allow_failure: false +phpunit (next minor): + allow_failure: false +phpunit (next major): + allow_failure: true diff --git a/.stylelintignore b/.stylelintignore new file mode 100644 index 00000000..2e07e61f --- /dev/null +++ b/.stylelintignore @@ -0,0 +1,3 @@ +bin/** +dist/** +css/** diff --git a/README.md b/README.md index beed96ae..158e35b3 100644 --- a/README.md +++ b/README.md @@ -172,7 +172,7 @@ We call a macro which calls itself to render the full tree. ### Configuration -If using configuration synchronisation, make sure your core.extension.yml contains +If using configuration synchronization, make sure your core.extension.yml contains ``` theme: diff --git a/bootstrap5.theme b/bootstrap5.theme index 184b2d15..3df5aef7 100644 --- a/bootstrap5.theme +++ b/bootstrap5.theme @@ -2,7 +2,7 @@ /** * @file - * bootstrap5 theme file. + * Bootstrap5 theme file. */ use Drupal\block\Entity\Block; @@ -40,7 +40,7 @@ function bootstrap5_form_system_theme_settings_alter(&$form, FormStateInterface * Validate callback to ensure filter order and allowed_html are compatible. */ function bootstrap5_form_system_theme_settings_subtheme_validate(array &$form, FormStateInterface $form_state) { - $subtheme_form_manager = new SubthemeFormManager(); + $subtheme_form_manager = new SubthemeFormManager(\Drupal::service('file_system'), \Drupal::service('messenger'), \Drupal::service('extension.list.theme')); return $subtheme_form_manager->validateForm($form, $form_state); } @@ -50,7 +50,7 @@ function bootstrap5_form_system_theme_settings_subtheme_validate(array &$form, F * @see bootstrap5_form_system_theme_settings_alter() */ function bootstrap5_form_system_theme_settings_subtheme_submit($form, FormStateInterface $form_state) { - $subtheme_form_manager = new SubthemeFormManager(); + $subtheme_form_manager = new SubthemeFormManager(\Drupal::service('file_system'), \Drupal::service('messenger'), \Drupal::service('extension.list.theme')); return $subtheme_form_manager->submitForm($form, $form_state); } @@ -277,7 +277,8 @@ function bootstrap5_views_pre_render(ViewExecutable $view) { if ($view->id() === 'media_library') { if ($view->display_handler->options['defaults']['css_class']) { $add_classes($view->displayHandlers->get('default')->options['css_class'], ['media-library-view']); - } else { + } + else { $add_classes($view->display_handler->options['css_class'], ['media-library-view']); } @@ -296,7 +297,8 @@ function bootstrap5_views_pre_render(ViewExecutable $view) { $add_classes($view->field['delete_media']->options['alter']['link_class'], ['media-library-item__remove']); $add_classes($view->field['delete_media']->options['alter']['link_class'], ['icon-link']); } - } elseif (strpos($view->current_display, 'widget') === 0) { + } + elseif (strpos($view->current_display, 'widget') === 0) { if (array_key_exists('rendered_entity', $view->field)) { $add_classes($view->field['rendered_entity']->options['element_class'], ['media-library-item__content']); } @@ -306,7 +308,8 @@ function bootstrap5_views_pre_render(ViewExecutable $view) { if ($view->display_handler->options['defaults']['css_class']) { $add_classes($view->displayHandlers->get('default')->options['css_class'], ['media-library-view--widget']); - } else { + } + else { $add_classes($view->display_handler->options['css_class'], ['media-library-view--widget']); } } diff --git a/js/nav-tabs.es6.js b/js/nav-tabs.es6.js deleted file mode 100644 index bdcbcbec..00000000 --- a/js/nav-tabs.es6.js +++ /dev/null @@ -1,35 +0,0 @@ -/** - * @file - * Responsive navigation tabs (local tasks) - * - * Element requires to have class .is-collapsible and attribute - * [data-drupal-nav-tabs] - */ -(($, Drupal, once) => { - function init(i, tab) { - const $tab = $(tab); - const $target = $tab.find('[data-drupal-nav-tabs-target]'); - - const openMenu = () => { - $target.toggleClass('is-open'); - const $toggle = $target.find('.tab-toggle'); - $toggle.attr( - 'aria-expanded', - (_, isExpanded) => !(isExpanded === 'true'), - ); - }; - - $tab.on('click.tabs', '[data-drupal-nav-tabs-toggle]', openMenu); - } - /** - * Initialize the tabs JS. - */ - Drupal.behaviors.navTabs = { - attach(context) { - once('nav-tabs', '[data-drupal-nav-tabs].is-collapsible', context) - .forEach((value, i) => { - $(value).each(init); - }); - }, - }; -})(jQuery, Drupal, once); diff --git a/js/nav-tabs.js b/js/nav-tabs.js index fd546aba..a605031e 100644 --- a/js/nav-tabs.js +++ b/js/nav-tabs.js @@ -1,31 +1,36 @@ /** - * DO NOT EDIT THIS FILE. - * See the following change record for more information, - * https://www.drupal.org/node/2815083 - * @preserve - **/ - -(function ($, Drupal, once) { + * @file + * Responsive navigation tabs (local tasks). + * + * Element requires to have class .is-collapsible and attribute + * [data-drupal-nav-tabs] + */ +(($, Drupal, once) => { function init(i, tab) { - var $tab = $(tab); - var $target = $tab.find('[data-drupal-nav-tabs-target]'); + const tabObj = $(tab); + const target = tab.find('[data-drupal-nav-tabs-target]'); - var openMenu = function openMenu() { - $target.toggleClass('is-open'); - var $toggle = $target.find('.tab-toggle'); - $toggle.attr('aria-expanded', function (_, isExpanded) { - return !(isExpanded === 'true'); - }); + const openMenu = () => { + target.toggleClass('is-open'); + const toggle = target.find('.tab-toggle'); + toggle.attr('aria-expanded', (_, isExpanded) => !(isExpanded === 'true')); }; - $tab.on('click.tabs', '[data-drupal-nav-tabs-toggle]', openMenu); + tabObj.on('click.tabs', '[data-drupal-nav-tabs-toggle]', openMenu); } + /** + * Initialize the tabs JS. + */ Drupal.behaviors.navTabs = { - attach: function attach(context) { - once('nav-tabs', '[data-drupal-nav-tabs].is-collapsible', context).forEach(function (value, i) { + attach(context) { + once( + 'nav-tabs', + '[data-drupal-nav-tabs].is-collapsible', + context, + ).forEach((value, i) => { $(value).each(init); }); - } + }, }; })(jQuery, Drupal, once); diff --git a/src/Drush/Commands/Bootstrap5Commands.php b/src/Drush/Commands/Bootstrap5Commands.php index f895513d..3a1d6134 100644 --- a/src/Drush/Commands/Bootstrap5Commands.php +++ b/src/Drush/Commands/Bootstrap5Commands.php @@ -4,6 +4,7 @@ namespace Drush\Commands; use Consolidation\AnnotatedCommand\CommandError; use Drupal\bootstrap5\SubthemeManager; +use Drupal\Core\Extension\ThemeExtensionList; use Drupal\Core\File\FileSystemInterface; use Drupal\Core\Messenger\MessengerInterface; use Drush\Attributes as CLI; @@ -20,10 +21,18 @@ final class Bootstrap5Commands extends DrushCommands { /** * Constructs a Subtheme Commands object. + * + * @param \Drupal\Core\File\FileSystemInterface $fileSystem + * The file system service. + * @param \Drupal\Core\Messenger\MessengerInterface $messenger + * The messenger interface. + * @param \Drupal\Core\Extension\ThemeExtensionList $themeExtensionList + * The theme extension list. */ public function __construct( - private readonly FileSystemInterface $fileSystem, - private readonly MessengerInterface $messenger, + protected FileSystemInterface $fileSystem, + protected MessengerInterface $messenger, + protected ThemeExtensionList $themeExtensionList, ) { parent::__construct(); } @@ -35,6 +44,7 @@ final class Bootstrap5Commands extends DrushCommands { return new static( $container->get('file_system'), $container->get('messenger'), + $container->get('extension.list.theme'), ); } @@ -52,9 +62,9 @@ final class Bootstrap5Commands extends DrushCommands { array $options = [ 'subtheme-name' => 'B5 subtheme', 'subtheme-folder' => 'themes/custom', - ] + ], ) { - $subthemeManager = new SubthemeManager($this->fileSystem, $this->messenger); + $subthemeManager = new SubthemeManager($this->fileSystem, $this->messenger, $this->themeExtensionList); $result = $subthemeManager->validateSubtheme($options['subtheme-folder'], $machine_name); if (is_array($result)) { diff --git a/src/SettingsManager.php b/src/SettingsManager.php index 3309c361..223fa8a5 100644 --- a/src/SettingsManager.php +++ b/src/SettingsManager.php @@ -102,7 +102,7 @@ class SettingsManager { $form['body_details'] = [ '#type' => 'details', '#title' => $this->t('Body options'), - '#description' => $this->t('Combination of theme/background colour may affect background colour/text colour contrast. To fix any contrast issues, override corresponding variables in scss file: <code>[bootstrap 5 theme]/dist/boostrap/[version]/scss/_variables.scss</code>'), + '#description' => $this->t('Combination of theme/background colour may affect background colour/text colour contrast. To fix any contrast issues, override corresponding variables in scss file: <code>[bootstrap 5 theme]/dist/bootstrap/[version]/scss/_variables.scss</code>'), '#open' => TRUE, ]; @@ -140,7 +140,7 @@ class SettingsManager { $form['nav_details'] = [ '#type' => 'details', '#title' => $this->t('Navbar options'), - '#description' => $this->t("Combination of theme/background colour may affect background colour/text colour contrast. To fix any contrast issues, override \$navbar-light-*/\$navbar-dark-* variables (refer to dist/boostrap/scss/_variables.scss)"), + '#description' => $this->t("Combination of theme/background colour may affect background colour/text colour contrast. To fix any contrast issues, override \$navbar-light-*/\$navbar-dark-* variables (refer to dist/bootstrap/scss/_variables.scss)"), '#open' => TRUE, ]; @@ -163,7 +163,7 @@ class SettingsManager { $form['footer_details'] = [ '#type' => 'details', '#title' => $this->t('Footer options'), - '#description' => $this->t("Combination of theme/background colour may affect background colour/text colour contrast. To fix any contrast issues, override corresponding variables in scss (refer to dist/boostrap/scss/_variables.scss)"), + '#description' => $this->t("Combination of theme/background colour may affect background colour/text colour contrast. To fix any contrast issues, override corresponding variables in scss (refer to dist/bootstrap/scss/_variables.scss)"), '#open' => TRUE, ]; @@ -190,13 +190,6 @@ class SettingsManager { '#open' => TRUE, ]; - /*$form['text_formats']['b5_ckeditor_enable'] = [ - '#type' => 'checkbox', - '#title' => $this->t('CKEditor with bootstrap support'), - '#default_value' => theme_get_setting('b5_ckeditor_enable'), - '#description' => $this->t("Enable bootstrap support inside bootstrap editor. If enabled, containers, cards and other styles will be rendered inside CKEditor."), - ];*/ - $form['subtheme'] = [ '#type' => 'details', '#title' => $this->t('Subtheme'), diff --git a/src/SubthemeFormManager.php b/src/SubthemeFormManager.php index 0bc20e5c..dfe208cb 100644 --- a/src/SubthemeFormManager.php +++ b/src/SubthemeFormManager.php @@ -2,7 +2,10 @@ namespace Drupal\bootstrap5; +use Drupal\Core\Extension\ThemeExtensionList; +use Drupal\Core\File\FileSystemInterface; use Drupal\Core\Form\FormStateInterface; +use Drupal\Core\Messenger\MessengerInterface; /** * Bootstrap5 subtheme form manager. @@ -16,11 +19,25 @@ class SubthemeFormManager { */ protected SubthemeManager $subthemeManager; + /** + * The theme extension list. + * + * @var \Drupal\Core\Extension\ThemeExtensionList + */ + protected $themeExtensionList; + /** * SubthemeFormManager constructor. + * + * @param \Drupal\Core\File\FileSystemInterface $file_system + * The file system service. + * @param \Drupal\Core\Messenger\MessengerInterface $messenger + * The messenger interface. + * @param \Drupal\Core\Extension\ThemeExtensionList $theme_extension_list + * The theme extension list. */ - public function __construct() { - $this->subthemeManager = new SubthemeManager(\Drupal::service('file_system'), \Drupal::service('messenger')); + public function __construct(FileSystemInterface $file_system, MessengerInterface $messenger, ThemeExtensionList $theme_extension_list) { + $this->subthemeManager = new SubthemeManager($file_system, $messenger, $theme_extension_list); } /** diff --git a/src/SubthemeManager.php b/src/SubthemeManager.php index 82f424f5..ad5e20b2 100644 --- a/src/SubthemeManager.php +++ b/src/SubthemeManager.php @@ -3,6 +3,7 @@ namespace Drupal\bootstrap5; use Drupal\Component\Serialization\Yaml; +use Drupal\Core\Extension\ThemeExtensionList; use Drupal\Core\File\FileSystemInterface; use Drupal\Core\Messenger\MessengerInterface; use Drupal\Core\StringTranslation\StringTranslationTrait; @@ -28,6 +29,13 @@ class SubthemeManager { */ protected $messenger; + /** + * The theme extension list. + * + * @var \Drupal\Core\Extension\ThemeExtensionList + */ + protected $themeExtensionList; + /** * SubthemeManager constructor. * @@ -35,10 +43,13 @@ class SubthemeManager { * The file system service. * @param \Drupal\Core\Messenger\MessengerInterface $messenger * The messenger. + * @param \Drupal\Core\Extension\ThemeExtensionList $them_extension_list + * The theme extension list. */ - public function __construct(FileSystemInterface $file_system, MessengerInterface $messenger) { + public function __construct(FileSystemInterface $file_system, MessengerInterface $messenger, ThemeExtensionList $them_extension_list) { $this->fileSystem = $file_system; $this->messenger = $messenger; + $this->themeExtensionList = $them_extension_list; } /** @@ -110,7 +121,7 @@ class SubthemeManager { ]; } // Validate machine name to ensure correct format. - if(!preg_match("/^[a-z]+[0-9a-z_]+$/", $subtheme_machine_name)) { + if (!preg_match("/^[a-z]+[0-9a-z_]+$/", $subtheme_machine_name)) { return [ 'subtheme_machine_name', $this->t('Subtheme machine name format is incorrect.'), @@ -152,20 +163,20 @@ class SubthemeManager { $themePath = DRUPAL_ROOT . DIRECTORY_SEPARATOR . $subtheme_folder . DIRECTORY_SEPARATOR . $subtheme_machine_name; if (!is_dir($themePath)) { // Copy CSS file replace empty one. - $subforders = ['css']; - foreach ($subforders as $subforder) { - $directory = $themePath . DIRECTORY_SEPARATOR . $subforder . DIRECTORY_SEPARATOR; + $subfolders = ['css']; + foreach ($subfolders as $subfolder) { + $directory = $themePath . DIRECTORY_SEPARATOR . $subfolder . DIRECTORY_SEPARATOR; $fs->prepareDirectory($directory, FileSystemInterface::CREATE_DIRECTORY | FileSystemInterface::MODIFY_PERMISSIONS); $files = $fs->scanDirectory( - \Drupal::service('extension.list.theme')->getPath('bootstrap5') . DIRECTORY_SEPARATOR . $subforder . DIRECTORY_SEPARATOR, '/.*css/', [ + $this->themeExtensionList->getPath('bootstrap5') . DIRECTORY_SEPARATOR . $subfolder . DIRECTORY_SEPARATOR, '/.*css/', [ 'recurse' => FALSE, - ]); + ]); foreach ($files as $file) { $fileName = $file->filename; $fs->copy( - \Drupal::service('extension.list.theme')->getPath('bootstrap5') . DIRECTORY_SEPARATOR . $subforder . DIRECTORY_SEPARATOR . $fileName, - $themePath . DIRECTORY_SEPARATOR . $subforder . DIRECTORY_SEPARATOR . $fileName, TRUE); + $this->themeExtensionList->getPath('bootstrap5') . DIRECTORY_SEPARATOR . $subfolder . DIRECTORY_SEPARATOR . $fileName, + $themePath . DIRECTORY_SEPARATOR . $subfolder . DIRECTORY_SEPARATOR . $fileName, TRUE); } } @@ -176,7 +187,7 @@ class SubthemeManager { 'screenshot.png', ]; foreach ($files as $fileName) { - $fs->copy(\Drupal::service('extension.list.theme')->getPath('bootstrap5') . DIRECTORY_SEPARATOR . $fileName, + $fs->copy($this->themeExtensionList->getPath('bootstrap5') . DIRECTORY_SEPARATOR . $fileName, $themePath . DIRECTORY_SEPARATOR . $fileName, TRUE); } @@ -195,7 +206,7 @@ class SubthemeManager { '', '/**', ' * @file', - ' * ' . $subtheme_name .' theme file.', + ' * ' . $subtheme_name . ' theme file.', ' */', '', ], @@ -217,7 +228,7 @@ class SubthemeManager { foreach ($files as $fileName => $lines) { // Get file content. - $content = str_replace('bootstrap5', $subtheme_machine_name, file_get_contents(\Drupal::service('extension.list.theme')->getPath('bootstrap5') . DIRECTORY_SEPARATOR . $fileName)); + $content = str_replace('bootstrap5', $subtheme_machine_name, file_get_contents($this->themeExtensionList->getPath('bootstrap5') . DIRECTORY_SEPARATOR . $fileName)); if (is_array($lines)) { $content = implode(PHP_EOL, $lines); } @@ -226,7 +237,7 @@ class SubthemeManager { } // Info yml file generation. - $infoYml = Yaml::decode(file_get_contents(\Drupal::service('extension.list.theme')->getPath('bootstrap5') . DIRECTORY_SEPARATOR . 'bootstrap5.info.yml')); + $infoYml = Yaml::decode(file_get_contents($this->themeExtensionList->getPath('bootstrap5') . DIRECTORY_SEPARATOR . 'bootstrap5.info.yml')); $infoYml['name'] = $subtheme_name; $infoYml['description'] = $subtheme_name . ' subtheme based on Bootstrap 5 theme.'; $infoYml['base theme'] = 'bootstrap5'; @@ -234,7 +245,7 @@ class SubthemeManager { $infoYml['libraries'] = []; $infoYml['libraries'][] = $subtheme_machine_name . '/global-styling'; $infoYml['libraries-override'] = [ - 'bootstrap5/global-styling' => false, + 'bootstrap5/global-styling' => FALSE, ]; foreach ([ @@ -255,7 +266,7 @@ class SubthemeManager { // SCSS files generation. $scssPath = $themePath . DIRECTORY_SEPARATOR . 'scss'; - $b5ScssPath = \Drupal::service('extension.list.theme')->getPath('bootstrap5') . DIRECTORY_SEPARATOR . 'scss' . DIRECTORY_SEPARATOR; + $b5ScssPath = $this->themeExtensionList->getPath('bootstrap5') . DIRECTORY_SEPARATOR . 'scss' . DIRECTORY_SEPARATOR; $fs->prepareDirectory($scssPath, FileSystemInterface::CREATE_DIRECTORY | FileSystemInterface::MODIFY_PERMISSIONS); $files = [ @@ -263,14 +274,14 @@ class SubthemeManager { "// Sub theme styling.", "@import 'variables_drupal';", '', - "// Bootstrap overriden variables.", + "// Bootstrap overridden variables.", "// @see https://getbootstrap.com/docs/5.2/customize/sass/#variable-defaults.", "@import 'variables_bootstrap';", '', "// Include bootstrap.", "@import '" . str_repeat('../', count(explode(DIRECTORY_SEPARATOR, $subtheme_folder)) + 2) . - \Drupal::service('extension.list.theme')->getPath('bootstrap5') . "/scss/style';", + $this->themeExtensionList->getPath('bootstrap5') . "/scss/style';", '', ], 'ck5style.scss' => $b5ScssPath . 'ck5style.scss', @@ -290,7 +301,7 @@ class SubthemeManager { } // Add block config to subtheme. - $orig_config_path = \Drupal::service('extension.list.theme')->getPath('bootstrap5') . DIRECTORY_SEPARATOR . 'config/optional'; + $orig_config_path = $this->themeExtensionList->getPath('bootstrap5') . DIRECTORY_SEPARATOR . 'config/optional'; $config_path = $themePath . DIRECTORY_SEPARATOR . 'config/optional'; $files = scandir($orig_config_path); $fs->prepareDirectory($config_path, FileSystemInterface::CREATE_DIRECTORY | FileSystemInterface::MODIFY_PERMISSIONS); @@ -308,7 +319,7 @@ class SubthemeManager { } // Add install config to subtheme. - $orig_config_path = \Drupal::service('extension.list.theme')->getPath('bootstrap5') . DIRECTORY_SEPARATOR . 'config/install'; + $orig_config_path = $this->themeExtensionList->getPath('bootstrap5') . DIRECTORY_SEPARATOR . 'config/install'; $config_path = $themePath . DIRECTORY_SEPARATOR . 'config/install'; $files = scandir($orig_config_path); $fs->prepareDirectory($config_path, FileSystemInterface::CREATE_DIRECTORY | FileSystemInterface::MODIFY_PERMISSIONS); -- GitLab