class TextFormat

Same name in this branch
  1. 11.x core/modules/config_translation/src/FormElement/TextFormat.php \Drupal\config_translation\FormElement\TextFormat
Same name and namespace in other branches
  1. 9 core/modules/config_translation/src/FormElement/TextFormat.php \Drupal\config_translation\FormElement\TextFormat
  2. 9 core/modules/filter/src/Element/TextFormat.php \Drupal\filter\Element\TextFormat
  3. 8.9.x core/modules/config_translation/src/FormElement/TextFormat.php \Drupal\config_translation\FormElement\TextFormat
  4. 8.9.x core/modules/filter/src/Element/TextFormat.php \Drupal\filter\Element\TextFormat
  5. 10 core/modules/config_translation/src/FormElement/TextFormat.php \Drupal\config_translation\FormElement\TextFormat
  6. 10 core/modules/filter/src/Element/TextFormat.php \Drupal\filter\Element\TextFormat

Provides a text format render element.

Properties:

@property $base_type The form element #type to use for the 'value' element. 'textarea' by default. @property $format (optional) The text format ID to preselect. If omitted, the default format for the current user will be used. @property $allowed_formats (optional) An array of text format IDs that are available for this element. If omitted, all text formats that the current user has access to will be allowed.

Usage Example:

$form['body'] = [
  '#type' => 'text_format',
  '#title' => 'Body',
  '#format' => 'full_html',
  '#default_value' => '<p>The quick brown fox jumped over the lazy dog.</p>',
];

Attributes

#[RenderElement('text_format')]

Hierarchy

Expanded class hierarchy of TextFormat

See also

\Drupal\Core\Render\Element\Textarea

1 file declares its use of TextFormat
TextfieldWidget.php in core/modules/text/src/Plugin/Field/FieldWidget/TextfieldWidget.php
4 string references to 'TextFormat'
ClaroPreRender::trustedCallbacks in core/themes/claro/src/ClaroPreRender.php
Lists the trusted callbacks provided by the implementing class.
claro_element_info_alter in core/themes/claro/claro.theme
Implements hook_element_info_alter().
OliveroPreRender::trustedCallbacks in core/themes/olivero/src/OliveroPreRender.php
Lists the trusted callbacks provided by the implementing class.
olivero_element_info_alter in core/themes/olivero/olivero.theme
Implements hook_element_info_alter().
7 #type uses of TextFormat
FilterTestFormatForm::buildForm in core/modules/filter/tests/filter_test/src/Form/FilterTestFormatForm.php
Form constructor.
FormTestDisabledElementsForm::buildForm in core/modules/system/tests/modules/form_test/src/Form/FormTestDisabledElementsForm.php
Form constructor.
InputRequired::buildOptionsForm in core/modules/views/src/Plugin/views/exposed_form/InputRequired.php
Provide a form to edit options for this plugin.
JavascriptStatesForm::buildForm in core/modules/system/tests/modules/form_test/src/Form/JavascriptStatesForm.php
Form constructor.
Text::buildOptionsForm in core/modules/views/src/Plugin/views/area/Text.php
Provide a form to edit options for this plugin.

... See full list

File

core/modules/filter/src/Element/TextFormat.php, line 39

Namespace

Drupal\filter\Element
View source
class TextFormat extends RenderElementBase {
  
  /**
   * {@inheritdoc}
   */
  public function getInfo() {
    return [
      '#process' => [
        [
          static::class,
          'processFormat',
        ],
      ],
      '#base_type' => 'textarea',
      '#theme_wrappers' => [
        'text_format_wrapper',
      ],
    ];
  }
  
  /**
   * Expands an element into a base element with text format selector attached.
   *
   * The form element will be expanded into two separate form elements, one
   * holding the original element, and the other holding the text format
   * selector:
   * - value: Holds the original element, having its #type changed to the value
   *   of #base_type or 'textarea' by default.
   * - format: Holds the text format details and the text format selection,
   *   using the text format ID specified in #format or the user's default
   *   format by default, if NULL.
   *
   * The resulting value for the element will be an array holding the value and
   * the format. For example, the value for the body element will be:
   * @code
   *   $values = $form_state->getValue('body');
   *   $values['value'] = 'foo';
   *   $values['format'] = 'foo';
   * @endcode
   *
   * @param array $element
   *   The form element to process. See main class documentation for properties.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The current state of the form.
   * @param array $complete_form
   *   The complete form structure.
   *
   * @return array
   *   The form element.
   */
  public static function processFormat(&$element, FormStateInterface $form_state, &$complete_form) {
    $user = static::currentUser();
    // Ensure that children appear as subkeys of this element.
    $element['#tree'] = TRUE;
    $keys_not_to_copy = [
      // Make \Drupal::formBuilder()->doBuildForm() regenerate child properties.
'#parents',
      '#id',
      '#name',
      // Do not copy this #process function to prevent
      // \Drupal::formBuilder()->doBuildForm() from recursing infinitely.
'#process',
      // Ensure #pre_render functions will be run.
'#pre_render',
      // Description is handled by theme_text_format_wrapper().
'#description',
      // Ensure proper ordering of children.
'#weight',
      // Properties already processed for the parent element.
'#prefix',
      '#suffix',
      '#attached',
      '#processed',
      '#theme_wrappers',
    ];
    // Move this element into sub-element 'value'.
    unset($element['value']);
    foreach (Element::properties($element) as $key) {
      if (!in_array($key, $keys_not_to_copy)) {
        $element['value'][$key] = $element[$key];
      }
    }
    $element['value']['#type'] = $element['#base_type'];
    $element['value'] += static::elementInfo()->getInfo($element['#base_type']);
    // Make sure the #default_value key is set, so we can use it below.
    $element['value'] += [
      '#default_value' => '',
    ];
    // Turn original element into a text format wrapper.
    $element['#attached']['library'][] = 'filter/drupal.filter';
    // Setup child container for the text format widget.
    $element['format'] = [
      '#type' => 'container',
      '#theme_wrappers' => [
        'container__text_format_filter_wrapper',
      ],
      '#attributes' => [
        'class' => [
          'js-filter-wrapper',
        ],
      ],
    ];
    // Get a list of formats that the current user has access to.
    $formats = filter_formats($user);
    // Allow the list of formats to be restricted.
    if (isset($element['#allowed_formats'])) {
      // We do not add the fallback format here to allow the use-case of forcing
      // certain text formats to be used for certain text areas. In case the
      // fallback format is supposed to be allowed as well, it must be added to
      // $element['#allowed_formats'] explicitly.
      $formats = array_intersect_key($formats, array_flip($element['#allowed_formats']));
    }
    if (!isset($element['#format']) && !empty($formats)) {
      // If no text format was selected, use the allowed format with the highest
      // weight. This is equivalent to calling filter_default_format().
      $element['#format'] = reset($formats)->id();
    }
    // If #allowed_formats is set, the list of formats must not be modified in
    // any way. Otherwise, however, if all of the following conditions are true,
    // remove the fallback format from the list of formats:
    // 1. The 'always_show_fallback_choice' filter setting has not been
    //    activated.
    // 2. Multiple text formats are available.
    // 3. The fallback format is not the default format.
    // The 'always_show_fallback_choice' filter setting is a hidden setting that
    // has no UI. It defaults to FALSE.
    $config = static::configFactory()->get('filter.settings');
    if (!isset($element['#allowed_formats']) && !$config->get('always_show_fallback_choice')) {
      $fallback_format = $config->get('fallback_format');
      if ($element['#format'] !== $fallback_format && count($formats) > 1) {
        unset($formats[$fallback_format]);
      }
    }
    // If the value element has #states set, copy it to the format element.
    if (isset($element['value']['#states'])) {
      $element['format']['#states'] = $element['value']['#states'];
    }
    // Prepare text format guidelines.
    $element['format']['guidelines'] = [
      '#type' => 'container',
      '#attributes' => [
        'class' => [
          'js-filter-guidelines',
        ],
      ],
      '#theme_wrappers' => [
        'container__text_format_filter_guidelines',
      ],
      '#weight' => 20,
    ];
    $options = [];
    foreach ($formats as $format) {
      $options[$format->id()] = $format->label();
      $element['format']['guidelines'][$format->id()] = [
        '#theme' => 'filter_guidelines',
        '#format' => $format,
      ];
    }
    $element['format']['format'] = [
      '#type' => 'select',
      '#title' => t('Text format'),
      '#options' => $options,
      '#default_value' => $element['#format'],
      '#access' => count($formats) > 1,
      '#weight' => 10,
      '#attributes' => [
        'class' => [
          'js-filter-list',
        ],
      ],
      '#parents' => array_merge($element['#parents'], [
        'format',
      ]),
    ];
    $element['format']['help'] = [
      '#type' => 'container',
      '#theme_wrappers' => [
        'container__text_format_filter_help',
      ],
      'about' => [
        '#type' => 'link',
        '#title' => t('About text formats'),
        '#url' => new Url('filter.tips_all'),
        '#attributes' => [
          'target' => '_blank',
        ],
      ],
      '#weight' => 0,
    ];
    $all_formats = filter_formats();
    $format_exists = isset($all_formats[$element['#format']]);
    $format_allowed = !isset($element['#allowed_formats']) || in_array($element['#format'], $element['#allowed_formats']);
    $user_has_access = isset($formats[$element['#format']]);
    $user_is_admin = $user->hasPermission('administer filters');
    // If the stored format does not exist or if it is not among the allowed
    // formats for this textarea, administrators have to assign a new format.
    if ((!$format_exists || !$format_allowed) && $user_is_admin) {
      $element['format']['format']['#required'] = TRUE;
      $element['format']['format']['#default_value'] = NULL;
      // Force access to the format selector (it may have been denied above if
      // the user only has access to a single format).
      $element['format']['format']['#access'] = TRUE;
    }
    elseif (!$user_has_access || !$format_exists) {
      // Overload default values into #value to make them unalterable.
      $element['value']['#value'] = $element['value']['#default_value'];
      $element['format']['format']['#value'] = $element['format']['format']['#default_value'];
      // Prepend #pre_render callback to replace field value with user notice
      // prior to rendering.
      $element['value'] += [
        '#pre_render' => [],
      ];
      array_unshift($element['value']['#pre_render'], [
        static::class,
        'accessDeniedCallback',
      ]);
      // Cosmetic adjustments.
      if (isset($element['value']['#rows'])) {
        $element['value']['#rows'] = 3;
      }
      $element['value']['#disabled'] = TRUE;
      $element['value']['#resizable'] = 'none';
      // Hide the text format selector and any other child element (such as text
      // field's summary).
      foreach (Element::children($element) as $key) {
        if ($key != 'value') {
          $element[$key]['#access'] = FALSE;
        }
      }
    }
    return $element;
  }
  
  /**
   * Render API callback: Hides the field value of 'text_format' elements.
   *
   * To not break form processing and previews if a user does not have access to
   * a stored text format, the expanded form elements in
   * \Drupal\filter\Element\TextFormat::processFormat() are forced to take over
   * the stored #default_values for 'value' and 'format'. However, to prevent
   * the unfiltered, original #value from being displayed to the user, we
   * replace it with a friendly notice here.
   *
   * @param array $element
   *   The render array to add the access denied message to.
   *
   * @return array
   *   The updated render array.
   */
  public static function accessDeniedCallback(array $element) {
    $element['#value'] = t('This field has been disabled because you do not have sufficient permissions to edit it.');
    return $element;
  }
  
  /**
   * Wraps the current user.
   *
   * \Drupal\Core\Session\AccountInterface
   */
  protected static function currentUser() {
    return \Drupal::currentUser();
  }
  
  /**
   * Wraps the config factory.
   *
   * @return \Drupal\Core\Config\ConfigFactoryInterface
   *   The configuration factory service.
   */
  protected static function configFactory() {
    return \Drupal::configFactory();
  }
  
  /**
   * Wraps the element info service.
   *
   * @return \Drupal\Core\Render\ElementInfoManagerInterface
   *   The element info service.
   */
  protected static function elementInfo() {
    return \Drupal::service('element_info');
  }

}

Members

Title Sort descending Modifiers Object type Summary Overriden Title Overrides
PluginInspectionInterface::getPluginDefinition public function Gets the definition of the plugin implementation. 7
PluginInspectionInterface::getPluginId public function Gets the plugin ID of the plugin instance. 3
RenderElementBase::$renderParent protected property The parent element.
RenderElementBase::$renderParentName protected property The parent key.
RenderElementBase::$storage protected property The storage.
RenderElementBase::addChild public function Adds a child render element. Overrides ElementInterface::addChild
RenderElementBase::changeType public function Change the type of the element. Overrides ElementInterface::changeType
RenderElementBase::create public static function Creates an instance of the plugin. Overrides ContainerFactoryPluginInterface::create
RenderElementBase::createChild public function Creates a render object and attaches it to the current render object. Overrides ElementInterface::createChild
RenderElementBase::elementInfoManager protected function Returns the element info manager.
RenderElementBase::getChild public function Gets a child. Overrides ElementInterface::getChild
RenderElementBase::getChildren public function Returns child elements. Overrides ElementInterface::getChildren
RenderElementBase::initializeInternalStorage public function Initialize storage. Overrides ElementInterface::initializeInternalStorage
RenderElementBase::preRenderAjaxForm public static function Adds Ajax information about an element to communicate with JavaScript. 2
RenderElementBase::preRenderGroup public static function Adds members of this group as actual elements for rendering. 2
RenderElementBase::processAjaxForm public static function Form element processing handler for the #ajax form property. 3
RenderElementBase::processGroup public static function Arranges elements into groups. 2
RenderElementBase::removeChild public function Removes a child. Overrides ElementInterface::removeChild
RenderElementBase::setAttributes public static function Sets a form element&#039;s class attribute. Overrides ElementInterface::setAttributes 2
RenderElementBase::setType protected function Set type on initialize.
RenderElementBase::toRenderable public function Returns a render array. Overrides ElementInterface::toRenderable
RenderElementBase::__construct public function Constructs a new render element object.
RenderElementBase::__get public function Magic method: gets a property value.
RenderElementBase::__isset public function Magic method: checks if a property value is set.
RenderElementBase::__set public function Magic method: Sets a property value.
RenderElementBase::__sleep public function
RenderElementBase::__unset public function Magic method: unsets a property value.
RenderElementBase::__wakeup public function
TextFormat::accessDeniedCallback public static function Render API callback: Hides the field value of &#039;text_format&#039; elements.
TextFormat::configFactory protected static function Wraps the config factory.
TextFormat::currentUser protected static function Wraps the current user.
TextFormat::elementInfo protected static function Wraps the element info service.
TextFormat::getInfo public function Returns the element properties for this element. Overrides ElementInterface::getInfo
TextFormat::processFormat public static function Expands an element into a base element with text format selector attached.

Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.