From a73fdb1e7592eeab08dc0b988ec32ec48c034b6f Mon Sep 17 00:00:00 2001
From: Florent Torregrosa
 <14238-florenttorregrosa@users.noreply.drupalcode.org>
Date: Thu, 30 Mar 2023 18:57:10 +0200
Subject: [PATCH] Issue #3345264 by Grimreaper: Text format form element

---
 src/Element/ElementProcessTextFormat.php  | 59 +++++++++++++++++++++++
 src/HookHandler/ElementInfoAlter.php      |  9 ++++
 src/HookHandler/PreprocessFormElement.php |  5 +-
 src/Utility/DrupalAttributes.php          |  7 +++
 src/Utility/Element.php                   |  3 +-
 5 files changed, 81 insertions(+), 2 deletions(-)
 create mode 100644 src/Element/ElementProcessTextFormat.php

diff --git a/src/Element/ElementProcessTextFormat.php b/src/Element/ElementProcessTextFormat.php
new file mode 100644
index 00000000..03fa747e
--- /dev/null
+++ b/src/Element/ElementProcessTextFormat.php
@@ -0,0 +1,59 @@
+<?php
+
+declare(strict_types = 1);
+
+namespace Drupal\ui_suite_bootstrap\Element;
+
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\ui_suite_bootstrap\Utility\DrupalAttributes;
+use Drupal\ui_suite_bootstrap\Utility\Element;
+
+/**
+ * Element Process methods for text format.
+ */
+class ElementProcessTextFormat {
+
+  /**
+   * Ensure the format select list is placed before the about link.
+   */
+  public const FORMAT_WEIGHT = -10;
+
+  /**
+   * Processes a text format form element.
+   */
+  public static function processTextFormat(array &$element, FormStateInterface $form_state, array &$complete_form): array {
+    $element_object = Element::create($element);
+    if (isset($element_object->format)) {
+      $element_object->format->addClass([
+        'border',
+        'border-top-0',
+        'p-3',
+        'mb-3',
+        'd-flex',
+        'align-items-center',
+      ]);
+
+      // Guidelines (removed).
+      $element_object->format->guidelines->setProperty('access', FALSE);
+
+      // Format (select).
+      $element_object->format->format->setProperty('title_display', 'invisible');
+      $element_object->format->format->addClass([
+        'me-auto',
+      ], DrupalAttributes::WRAPPER);
+      $element_object->format->format->setProperty('weight', static::FORMAT_WEIGHT);
+      // Allow to detect that this select list is from a text format element.
+      // Value textarea already have this property.
+      $element_object->format->format->setProperty('format', $element_object->getProperty('format', []));
+
+      // Help (link).
+      $element_object->format->help->addClass([
+        'ms-auto',
+      ]);
+      $element_object->format->help->about->setAttribute('title', \t('Opens in new window'));
+    }
+
+    return $element;
+  }
+
+}
diff --git a/src/HookHandler/ElementInfoAlter.php b/src/HookHandler/ElementInfoAlter.php
index 017db9cf..53bcdd05 100644
--- a/src/HookHandler/ElementInfoAlter.php
+++ b/src/HookHandler/ElementInfoAlter.php
@@ -7,6 +7,7 @@ namespace Drupal\ui_suite_bootstrap\HookHandler;
 use Drupal\ui_suite_bootstrap\Element\ElementProcessCheckboxes;
 use Drupal\ui_suite_bootstrap\Element\ElementProcessInputGroup;
 use Drupal\ui_suite_bootstrap\Element\ElementProcessRadios;
+use Drupal\ui_suite_bootstrap\Element\ElementProcessTextFormat;
 
 /**
  * Element Info Alter.
@@ -156,6 +157,14 @@ class ElementInfoAlter {
         $info[$form_element_id]["#{$property}"] = $property_default_value;
       }
     }
+
+    // Text format.
+    if (isset($info['text_format'])) {
+      $info['text_format']['#process'][] = [
+        ElementProcessTextFormat::class,
+        'processTextFormat',
+      ];
+    }
   }
 
 }
diff --git a/src/HookHandler/PreprocessFormElement.php b/src/HookHandler/PreprocessFormElement.php
index f1c1b097..09e4d319 100644
--- a/src/HookHandler/PreprocessFormElement.php
+++ b/src/HookHandler/PreprocessFormElement.php
@@ -64,7 +64,10 @@ class PreprocessFormElement {
     // For all other form elements add 'form-label' class.
     else {
       $label->addClass('form-label');
-      $this->variables->addClass('mb-3');
+      // If the element is a sub-element of a text_format do not add the class.
+      if (!$this->element->hasProperty('format')) {
+        $this->variables->addClass('mb-3');
+      }
     }
 
     // Input group.
diff --git a/src/Utility/DrupalAttributes.php b/src/Utility/DrupalAttributes.php
index adcbb118..8b4b66cb 100644
--- a/src/Utility/DrupalAttributes.php
+++ b/src/Utility/DrupalAttributes.php
@@ -25,6 +25,13 @@ class DrupalAttributes extends ArrayObject {
    */
   public const DESCRIPTION = 'description_attributes';
 
+  /**
+   * Defines the "inner_wrapper_attributes" storage type constant.
+   *
+   * @var string
+   */
+  public const INNER_WRAPPER = 'inner_wrapper_attributes';
+
   /**
    * Defines the "input_group_attributes" storage type constant.
    *
diff --git a/src/Utility/Element.php b/src/Utility/Element.php
index bed9be36..2c69decf 100644
--- a/src/Utility/Element.php
+++ b/src/Utility/Element.php
@@ -64,7 +64,8 @@ class Element extends DrupalAttributes {
     if (CoreElement::property($key)) {
       throw new \InvalidArgumentException('Cannot dynamically retrieve element property. Please use  \Drupal\ui_suite_bootstrap\Utility\Element::getProperty instead.');
     }
-    return new self($this->offsetGet($key, []), $this->formState);
+    $instance = new self($this->offsetGet($key, []), $this->formState);
+    return $instance;
   }
 
   /**
-- 
GitLab