drowl_paragraphs_bs-1.x-dev/drowl_paragraphs_bs.module
drowl_paragraphs_bs.module
<?php
/**
* @file
* DROWL Paragraphs for Bootstrap enhancements.
*/
use Drupal\Component\Serialization\Json;
use Drupal\Component\Utility\Html;
use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\Core\Template\Attribute;
use Drupal\paragraphs\Entity\ParagraphsType;
/**
* Implements hook_field_info_alter().
*
* Taken from https://www.drupal.org/node/3375748.
*
* @todo Remove once minimum version supported is at least 10.2.0.
*/
function drowl_paragraphs_bs_field_info_alter(array &$info): void {
// Allow module to work with versions of older versions of Drupal:
if (\version_compare(\Drupal::VERSION, '10.1.9999', '<')) {
$info['drowl_paragraphs_bs_settings']['category'] = new TranslatableMarkup("DROWL Paragraphs");
}
}
/**
* Implements hook_preprocess_layout_paragraphs_builder().
*/
function drowl_paragraphs_bs_preprocess_layout_paragraphs_builder(array &$variables) {
// Add backend library form to layout_paragraphs builder form.
$variables['#attached']['library'][] = 'drowl_paragraphs_bs/admin';
}
/**
* Implements hook_theme_suggestions_HOOK_alter().
*/
function drowl_paragraphs_bs_theme_suggestions_paragraph_alter(&$suggestions, $variables) {
$entity = $variables['elements']['#paragraph'];
$sanitized_view_mode = strtr($variables['elements']['#view_mode'], '.', '_');
$type = $entity->getType();
$drowl_paragraphs_bs_suggestions = [];
$drowl_paragraphs_bs_suggestions[] = 'paragraph__drowl_paragraphs_bs';
$drowl_paragraphs_bs_suggestions[] = 'paragraph__drowl_paragraphs_bs__' . $type;
$drowl_paragraphs_bs_suggestions[] = 'paragraph__drowl_paragraphs_bs__' . $type . '__' . $sanitized_view_mode;
// Our override should be more general than the theme suggestion:
$suggestions = array_merge($drowl_paragraphs_bs_suggestions, $suggestions);
}
/**
* Prepared variables for paragraph output.
*/
function drowl_paragraphs_bs_preprocess_paragraph(&$variables) {
// Add frontend library for paragraphs display:
$variables['#attached']['library'][] = 'drowl_paragraphs_bs/global';
// If there is no paragraph, return early:
if (empty($variables['paragraph'])) {
return;
}
$paragraph = $variables['paragraph'];
$variables['attributes'] = new Attribute($variables['attributes'] ?? []);
// If the paragraph doesn't have a field_settings field, return early:
if (!$paragraph->hasField('field_settings')) {
return;
}
$paragraphFieldSettings = $paragraph->get('field_settings');
// If the paragraph field_settings field is not of type
// drowl_paragraphs_bs_settings, return early:
if ($paragraphFieldSettings->getFieldDefinition()->getType() !== 'drowl_paragraphs_bs_settings') {
return;
}
$paragraphSettingsArray = $paragraphFieldSettings->getValue();
// The first setting of this entry is our paragraph settings array. Return
// early, if it isn't set:
if (empty($paragraphSettingsArray[0])) {
return;
}
$ps = $paragraphSettingsArray[0];
$animations = [];
$animations_allowed_count = 4;
for ($i = 1; $i <= $animations_allowed_count; $i++) {
if (!empty($ps['style_animation_' . $i . '_events'] && !empty($ps['style_animation_' . $i . '_animation']))) {
$animations[] = [
'event' => $ps['style_animation_' . $i . '_events'],
'animation' => $ps['style_animation_' . $i . '_animation'],
'offset' => $ps['style_animation_' . $i . '_offset'],
'delay' => $ps['style_animation_' . $i . '_delay'],
'transition_duration' => $ps['style_animation_' . $i . '_transition_duration'],
];
}
}
if (!empty($animations)) {
$variables['attributes']->addClass('has-animation');
$variables['attributes']->setAttribute('data-animations', Json::encode($animations));
}
if (!empty($ps['equal_height_group'])) {
$variables['attributes']->setAttribute('data-equal-height-group', $ps['equal_height_group']);
}
// Set custom classes.
if (!empty($ps['classes_additional'])) {
$variables['attributes']->addClass(explode(' ', $ps['classes_additional']));
}
// Set custom id.
if (!empty($ps['id_attr'])) {
$variables['attributes']->setAttribute('id', $ps['id_attr']);
}
// Add Equal height library if the equal height group field is not
// empty.
if (!empty($ps['equal_height_group'])) {
$variables['#attached']['library'][] = 'drowl_paragraphs_bs/equal_height_groups';
}
}
/**
* Implements hook_theme().
*/
function drowl_paragraphs_bs_theme($existing, $type, $theme, $path) {
$templates = $path . '/templates';
return [
'field__field_paragraphs_paragraphs' => [
'base hook' => 'field',
'path' => $templates . '/fields',
],
'paragraph_preview_placeholder' => [
'variables' => [
'text' => NULL,
'icon_path' => NULL,
'view_mode' => NULL,
'entity' => NULL,
],
],
'paragraph__drowl_paragraphs_bs' => [
'base hook' => 'paragraph',
'path' => $templates,
],
'form__drowl_paragraphs_bs__layout_paragraphs_component_form' => [
// Path to your custom template file relative to your module's root
// 'template' =>
// 'form--drowl-paragraphs--layout-paragraphs-component-form.html.twig',.
'path' => $templates,
// Variables available in the template
// 'variables' => ['form' => NULL],.
],
];
}
/**
* Implements hook_entity_extra_field_info().
*/
function drowl_paragraphs_bs_entity_extra_field_info() {
$extra = [];
foreach (ParagraphsType::loadMultiple() as $bundle) {
$extra['paragraph'][$bundle->Id()]['display']['paragraph_preview_placeholder'] = [
'label' => t('Paragraph preview placeholder'),
'description' => t('Optional placeholder use in preview form display instead of the rendered paragraph elements.'),
'weight' => 100,
'visible' => FALSE,
];
}
return $extra;
}
/**
* Implements hook_ENTITY_TYPE_view().
*/
function drowl_paragraphs_bs_paragraph_view(array &$build, EntityInterface $entity, EntityViewDisplayInterface $display, $view_mode) {
if (!$display->getComponent('paragraph_preview_placeholder')) {
return;
}
if (method_exists($entity, 'getParagraphType')) {
$icon_path = NULL;
$icon = $entity->getParagraphType()->getIconFile();
if (!empty($icon)) {
$icon_path = $icon->createFileUrl();
}
$build['paragraph_preview_placeholder'] = [
'#theme' => 'paragraph_preview_placeholder',
'#text' => t('%label paragraph placeholder', ['%label' => $entity->getParagraphType()->label()]),
'#icon_path' => $icon_path,
'#view_mode' => $view_mode,
'#entity' => $entity,
];
}
}
/**
* Implements hook_theme_suggestions_HOOK().
*/
function drowl_paragraphs_bs_theme_suggestions_paragraph_preview_placeholder(array $variables) {
// Provide further theme suggestions for paragraph_preview_placeholder:
$suggestions = [];
$entity = !empty($variables['entity']) ? $variables['entity'] : NULL;
$sanitized_view_mode = !empty($variables['view_mode']) ? strtr($variables['view_mode'], '.', '_') : NULL;
if (!empty($sanitized_view_mode)) {
$suggestions[] = 'paragraph_preview_placeholder__' . $sanitized_view_mode;
}
if (!empty($entity)) {
$suggestions[] = 'paragraph_preview_placeholder__' . $entity->bundle();
}
if (!empty($entity) && !empty($sanitized_view_mode)) {
$suggestions[] = 'paragraph_preview_placeholder__' . $entity->bundle() . '__' . $sanitized_view_mode;
}
return $suggestions;
}
/**
* Implements hook_form_FORM_ID_alter().
*/
function drowl_paragraphs_bs_form_layout_paragraphs_component_form_alter(&$form, $form_state, $form_id) {
// Make the outside details element a container, so the users don't have to
// click twice to change ui_styles.
$form['behavior_plugins']['#type'] = 'container';
}
/**
* Implements hook_preprocess_HOOK().
*/
function drowl_paragraphs_bs_preprocess_details(&$variables) {
// Because we are not able to alter the BehaviorForm created here:
// https://git.drupalcode.org/project/ui_styles_paragraphs/-/blob/1.1.x/src/Plugin/paragraphs/Behavior/UIStyleOptions.php?ref_type=heads
// We alter all details element, if there is a "ui_style_options" element set:
// There is probably a cleaner way to do this.
$element = $variables['element'];
if (
!isset($element['#parents']) ||
!in_array('behavior_plugins', $element['#parents']) ||
!in_array('ui_style_options', $element['#parents'])
) {
return;
}
if ($element['#title'] instanceof TranslatableMarkup) {
$details_title = $element['#title']->getUntranslatedString();
}
else {
$details_title = $element['#title'];
}
// Add our own class to have a reliable solution.
$element['#attributes']['class'][] = 'form-wrapper--' . Html::cleanCssIdentifier(strtolower($details_title));
// Show paragraph type specific ui_option detail elements open by default.
// (Using the untranslated label, as we have no more reliable values here)
$types_to_expand_by_default = [
'Layout Options',
'Icon',
'Buttons',
'Score',
'Slideshow',
'Tabs / Accordion',
'Image Style',
'Media+Text',
'Card',
'Gallery',
];
if (in_array($details_title, $types_to_expand_by_default)) {
$element['#attributes']['open'] = '';
}
// Update details attributes.
$variables['attributes'] = $element['#attributes'];
}
/**
* Implements hook_theme_suggestions_HOOK().
*/
function drowl_paragraphs_bs_theme_suggestions_form_alter(array &$suggestions, array $variables, $hook) {
// Override the Layout Paragraphs Paragraph Edit Form, so we are able to add a
// layout.
if (isset($variables['element']['#form_id']) && $variables['element']['#form_id'] === 'layout_paragraphs_component_form') {
// Add your custom suggestion to the list.
$suggestions[] = 'form__drowl_paragraphs_bs';
$suggestions[] = 'form__drowl_paragraphs_bs__' . $variables['element']['#form_id'];
}
}
