function SmartDefaultSettings::addToolbarItemsToMatchHtmlElementsInFormat

Same name and namespace in other branches
  1. 11.x core/modules/ckeditor5/src/SmartDefaultSettings.php \Drupal\ckeditor5\SmartDefaultSettings::addToolbarItemsToMatchHtmlElementsInFormat()

Adds CKEditor 5 toolbar items to match the format's HTML elements.

Parameters

\Drupal\filter\FilterFormatInterface $format: The text format for which to compute smart default settings.

\Drupal\editor\EditorInterface $editor: The text editor config entity to update.

Return value

array|null NULL when nothing happened, otherwise an array with four values: 1. a description (for use in a message) of which CKEditor 5 plugins were enabled to match the HTML tags allowed by the text format. 2. a description (for use in a message) of which CKEditor 5 plugins were enabled to match the HTML attributes allowed by the text format. 3. the unsupported elements, in an HTMLRestrictions value object. 4. the list of enabled plugin labels.

File

core/modules/ckeditor5/src/SmartDefaultSettings.php, line 807

Class

SmartDefaultSettings
Generates CKEditor 5 settings for existing text editors/formats.

Namespace

Drupal\ckeditor5

Code

private function addToolbarItemsToMatchHtmlElementsInFormat(FilterFormatInterface $format, EditorInterface $editor) : ?array {
  $html_restrictions_needed_elements = $format->getHtmlRestrictions();
  if ($html_restrictions_needed_elements === FALSE) {
    return NULL;
  }
  $all_definitions = $this->pluginManager
    ->getDefinitions();
  $enabled_definitions = $this->pluginManager
    ->getEnabledDefinitions($editor);
  $disabled_definitions = array_diff_key($all_definitions, $enabled_definitions);
  $enabled_plugins = array_keys($enabled_definitions);
  $provided_elements = $this->pluginManager
    ->getProvidedElements($enabled_plugins, $editor);
  $provided = new HTMLRestrictions($provided_elements);
  $needed = HTMLRestrictions::fromTextFormat($format);
  // Plugins only supporting <tag attr> cannot create the tag. For that, they
  // must support plain <tag> too. With this being the case, break down what
  // is needed based on what is currently provided.
  // @see \Drupal\ckeditor5\Plugin\CKEditor5PluginDefinition::getCreatableElements()
  // TRICKY: the HTMLRestrictions value object can only convey complete
  // restrictions: merging <foo> and <foo bar> results in just <foo bar>. The
  // list of already provided plain tags must hence be constructed separately.
  $provided_plain_tags = new HTMLRestrictions($this->pluginManager
    ->getProvidedElements($enabled_plugins, NULL, FALSE, TRUE));
  // Determine the still needed plain tags, the still needed attributes, and
  // the union of both.
  $still_needed_plain_tags = $needed->extractPlainTagsSubset()
    ->diff($provided_plain_tags);
  $still_needed_attributes = $needed->diff($provided)
    ->diff($still_needed_plain_tags);
  $still_needed = $still_needed_plain_tags->merge($still_needed_attributes);
  if (!$still_needed->allowsNothing()) {
    // Select plugins for supporting the still needed plain tags.
    $plugin_candidates_plain_tags = self::getCandidates($provided_plain_tags, $still_needed_plain_tags, $disabled_definitions);
    $selected_plugins_plain_tags = self::selectCandidate($plugin_candidates_plain_tags, $still_needed_plain_tags, array_keys($provided_plain_tags->getAllowedElements()));
    // Select plugins for supporting the still needed attributes.
    $plugin_candidates_attributes = self::getCandidates($provided, $still_needed_attributes, $disabled_definitions);
    $selected_plugins_attributes = self::selectCandidate($plugin_candidates_attributes, $still_needed, array_keys($provided->getAllowedElements()));
    // Combine the selection.
    $selected_plugins = array_merge_recursive($selected_plugins_plain_tags, $selected_plugins_attributes);
    // If additional plugins need to be enabled to support attribute config,
    // loop through the list to enable the plugins and build a UI message that
    // will convey this plugin-enabling to the user.
    if (!empty($selected_plugins)) {
      $enabled_for_tags_message_content = '';
      $enabled_for_attributes_message_content = '';
      $editor_settings_to_update = $editor->getSettings();
      // Create new group for all the added toolbar items.
      $editor_settings_to_update['toolbar']['items'][] = '|';
      foreach ($selected_plugins as $plugin_id => $reason_why_enabled) {
        $plugin_definition = $this->pluginManager
          ->getDefinition($plugin_id);
        $label = $plugin_definition->label();
        $plugins_enabled[] = $label;
        if ($plugin_definition->hasToolbarItems()) {
          [$net_new] = self::computeNetNewElementsForPlugin($provided, $still_needed, $plugin_definition);
          $editor_settings_to_update['toolbar']['items'] = array_merge($editor_settings_to_update['toolbar']['items'], array_keys($plugin_definition->getToolbarItems()));
          foreach ($reason_why_enabled as $attribute_name => $attribute_config) {
            // Plugin was selected for tag.
            if (in_array($attribute_name, [
              '-attributes-none-',
              '-attributes-any-',
            ], TRUE)) {
              $tags = array_reduce(array_keys($net_new->getAllowedElements()), function ($carry, $item) {
                return $carry . "<{$item}>";
              });
              $enabled_for_tags_message_content .= "{$label} (for tags: {$tags}) ";
              // This plugin does not add attributes: continue to next plugin.
              continue;
            }
            // Plugin was selected for attribute.
            $enabled_for_attributes_message_content .= "{$label} (";
            foreach ($attribute_config as $tag_name => $attribute_value_config) {
              $enabled_for_attributes_message_content .= " for tag: <{$tag_name}> to support: {$attribute_name}";
              if (is_array($attribute_value_config)) {
                $enabled_for_attributes_message_content .= " with value(s): ";
                foreach (array_keys($attribute_value_config) as $allowed_value) {
                  $enabled_for_attributes_message_content .= " {$allowed_value},";
                }
                $enabled_for_attributes_message_content = substr($enabled_for_attributes_message_content, 0, -1) . '), ';
              }
            }
          }
          // Fewer attributes are still needed.
          $still_needed = $still_needed->diff($net_new);
        }
      }
      $editor->setSettings($editor_settings_to_update);
      // Some plugins enabled, maybe some missing tags or attributes.
      return [
        substr($enabled_for_tags_message_content, 0, -1),
        substr($enabled_for_attributes_message_content, 0, -2),
        $still_needed,
        $plugins_enabled,
      ];
    }
    else {
      // No plugins enabled, maybe some missing tags or attributes.
      return [
        NULL,
        NULL,
        $still_needed,
        NULL,
      ];
    }
  }
  else {
    return NULL;
  }
}

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