editor.module

Same filename and directory in other branches
  1. 11.x core/modules/editor/editor.module
  2. 10 core/modules/editor/editor.module
  3. 9 core/modules/editor/editor.module
  4. 8.9.x core/modules/editor/editor.module

File

core/modules/editor/editor.module

View source
<?php


/**
 * @file
 */

use Drupal\Core\Form\SubformState;
use Drupal\editor\Entity\Editor;
use Drupal\Core\Form\FormStateInterface;
use Drupal\filter\FilterFormatInterface;
use Drupal\filter\Plugin\FilterInterface;

/**
 * Button submit handler for filter_format_form()'s 'editor_configure' button.
 */
function editor_form_filter_admin_format_editor_configure($form, FormStateInterface $form_state) : void {
  $editor = $form_state->get('editor');
  $editor_value = $form_state->getValue([
    'editor',
    'editor',
  ]);
  if ($editor_value !== NULL) {
    if ($editor_value === '') {
      $form_state->set('editor', FALSE);
      $form_state->set('editor_plugin', NULL);
    }
    elseif (empty($editor) || $editor_value !== $editor->getEditor()) {
      $format = $form_state->getFormObject()
        ->getEntity();
      $editor = Editor::create([
        'format' => $format->isNew() ? NULL : $format->id(),
        'editor' => $editor_value,
        'image_upload' => [
          'status' => FALSE,
        ],
      ]);
      $form_state->set('editor', $editor);
    }
  }
  $form_state->setRebuild();
}

/**
 * AJAX callback handler for filter_format_form().
 */
function editor_form_filter_admin_form_ajax($form, FormStateInterface $form_state) {
  return $form['editor']['settings'];
}

/**
 * Additional validate handler for filter_format_form().
 */
function editor_form_filter_admin_format_validate($form, FormStateInterface $form_state) : void {
  $editor_set = $form_state->getValue([
    'editor',
    'editor',
  ]) !== "";
  $subform_array_exists = !empty($form['editor']['settings']['subform']) && is_array($form['editor']['settings']['subform']);
  if ($editor_set && $subform_array_exists && $editor_plugin = $form_state->get('editor_plugin')) {
    $subform_state = SubformState::createForSubform($form['editor']['settings']['subform'], $form, $form_state);
    $editor_plugin->validateConfigurationForm($form['editor']['settings']['subform'], $subform_state);
  }
  // This validate handler is not applicable when using the 'Configure' button.
  if ($form_state->getTriggeringElement()['#name'] === 'editor_configure') {
    return;
  }
  // When using this form with JavaScript disabled in the browser, the
  // 'Configure' button won't be clicked automatically. So, when the user has
  // selected a text editor and has then clicked 'Save configuration', we should
  // point out that the user must still configure the text editor.
  if ($form_state->getValue([
    'editor',
    'editor',
  ]) !== '' && !$form_state->get('editor')) {
    $form_state->setErrorByName('editor][editor', t('You must configure the selected text editor.'));
  }
}

/**
 * Additional submit handler for filter_format_form().
 */
function editor_form_filter_admin_format_submit($form, FormStateInterface $form_state) : void {
  // Delete the existing editor if disabling or switching between editors.
  $format = $form_state->getFormObject()
    ->getEntity();
  $format_id = $format->isNew() ? NULL : $format->id();
  $original_editor = $format_id ? Editor::load($format_id) : NULL;
  if ($original_editor && $original_editor->getEditor() != $form_state->getValue([
    'editor',
    'editor',
  ])) {
    $original_editor->delete();
  }
  $editor_set = $form_state->getValue([
    'editor',
    'editor',
  ]) !== "";
  $subform_array_exists = !empty($form['editor']['settings']['subform']) && is_array($form['editor']['settings']['subform']);
  if (($editor_plugin = $form_state->get('editor_plugin')) && $editor_set && $subform_array_exists) {
    $subform_state = SubformState::createForSubform($form['editor']['settings']['subform'], $form, $form_state);
    $editor_plugin->submitConfigurationForm($form['editor']['settings']['subform'], $subform_state);
  }
  // Create a new editor or update the existing editor.
  if ($editor = $form_state->get('editor')) {
    // Ensure the text format is set: when creating a new text format, this
    // would equal the empty string.
    $editor->set('format', $format_id);
    if ($settings = $form_state->getValue([
      'editor',
      'settings',
    ])) {
      $editor->setSettings($settings);
    }
    // When image uploads are disabled (status = FALSE), the schema for image
    // upload settings does not allow other keys to be present.
    // @see editor.image_upload_settings.*
    // @see editor.image_upload_settings.1
    // @see editor.schema.yml
    $image_upload_settings = $editor->getImageUploadSettings();
    if (!$image_upload_settings['status']) {
      $editor->setImageUploadSettings([
        'status' => FALSE,
      ]);
    }
    $editor->save();
  }
}

/**
 * Loads an individual configured text editor based on text format ID.
 *
 * @param string $format_id
 *   A text format ID.
 *
 * @return \Drupal\editor\Entity\Editor|null
 *   A text editor object, or NULL.
 *
 * @deprecated in drupal:11.2.0 and is removed from drupal:12.0.0. Use
 *   \Drupal::entityTypeManager()->getStorage('editor')->load($format_id)
 *   instead.
 * @see https://www.drupal.org/node/3509245
 */
function editor_load($format_id) {
  @trigger_error(__FUNCTION__ . '() is deprecated in drupal:11.2.0 and is removed from drupal:12.0.0. Use \\Drupal::entityTypeManager()->getStorage(\'editor\')->load($format_id) instead. See https://www.drupal.org/node/3509245', E_USER_DEPRECATED);
  // While loading multiple editors at once is a more efficient query, on warm
  // caches, loading editor configuration from APCu is fast and avoids a call to
  // ConfigFactory::listAll() in a loadMultiple() call with no IDs passed.
  // @see Drupal\Core\Config\Entity\ConfigEntityStorage::doLoadMultiple()
  return $format_id ? Editor::load($format_id) : NULL;
}

/**
 * Applies text editor XSS filtering.
 *
 * @param string $html
 *   The HTML string that will be passed to the text editor.
 * @param \Drupal\filter\FilterFormatInterface|null $format
 *   The text format whose text editor will be used or NULL if the previously
 *   defined text format is now disabled.
 * @param \Drupal\filter\FilterFormatInterface|null $original_format
 *   (optional) The original text format (i.e. when switching text formats,
 *   $format is the text format that is going to be used, $original_format is
 *   the one that was being used initially, the one that is stored in the
 *   database when editing).
 *
 * @return string|false
 *   The XSS filtered string or FALSE when no XSS filtering needs to be applied,
 *   because one of the next conditions might occur:
 *   - No text editor is associated with the text format,
 *   - The previously defined text format is now disabled,
 *   - The text editor is safe from XSS,
 *   - The text format does not use any XSS protection filters.
 *
 * @see https://www.drupal.org/node/2099741
 */
function editor_filter_xss($html, ?FilterFormatInterface $format = NULL, ?FilterFormatInterface $original_format = NULL) {
  $editor = $format ? Editor::load($format->id()) : NULL;
  // If no text editor is associated with this text format or the previously
  // defined text format is now disabled, then we don't need text editor XSS
  // filtering either.
  if (!isset($editor)) {
    return FALSE;
  }
  // If the text editor associated with this text format guarantees security,
  // then we also don't need text editor XSS filtering.
  $definition = \Drupal::service('plugin.manager.editor')->getDefinition($editor->getEditor());
  if ($definition['is_xss_safe'] === TRUE) {
    return FALSE;
  }
  // If there is no filter preventing XSS attacks in the text format being used,
  // then no text editor XSS filtering is needed either. (Because then the
  // editing user can already be attacked by merely viewing the content.)
  // e.g.: an admin user creates content in Full HTML and then edits it, no text
  // format switching happens; in this case, no text editor XSS filtering is
  // desirable, because it would strip style attributes, amongst others.
  $current_filter_types = $format->getFilterTypes();
  if (!in_array(FilterInterface::TYPE_HTML_RESTRICTOR, $current_filter_types, TRUE)) {
    if ($original_format === NULL) {
      return FALSE;
    }
    else {
      $original_filter_types = $original_format->getFilterTypes();
      if (!in_array(FilterInterface::TYPE_HTML_RESTRICTOR, $original_filter_types, TRUE)) {
        return FALSE;
      }
    }
  }
  // Otherwise, apply the text editor XSS filter. We use the default one unless
  // a module tells us to use a different one.
  $editor_xss_filter_class = '\\Drupal\\editor\\EditorXssFilter\\Standard';
  \Drupal::moduleHandler()->alter('editor_xss_filter', $editor_xss_filter_class, $format, $original_format);
  return call_user_func($editor_xss_filter_class . '::filterXss', $html, $format, $original_format);
}

Functions

Title Deprecated Summary
editor_filter_xss Applies text editor XSS filtering.
editor_form_filter_admin_format_editor_configure Button submit handler for filter_format_form()'s 'editor_configure' button.
editor_form_filter_admin_format_submit Additional submit handler for filter_format_form().
editor_form_filter_admin_format_validate Additional validate handler for filter_format_form().
editor_form_filter_admin_form_ajax AJAX callback handler for filter_format_form().
editor_load

in drupal:11.2.0 and is removed from drupal:12.0.0. Use \Drupal::entityTypeManager()->getStorage('editor')->load($format_id) instead.

Loads an individual configured text editor based on text format ID.

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