function SmartDefaultSettings::addToolbarItemsToMatchHtmlElementsInFormat

Same name and namespace in other branches
  1. 9 core/modules/ckeditor5/src/SmartDefaultSettings.php \Drupal\ckeditor5\SmartDefaultSettings::addToolbarItemsToMatchHtmlElementsInFormat()
  2. 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.

1 call to SmartDefaultSettings::addToolbarItemsToMatchHtmlElementsInFormat()
SmartDefaultSettings::computeSmartDefaultSettings in core/modules/ckeditor5/src/SmartDefaultSettings.php
Computes the closest possible equivalent settings for switching to CKEditor 5.

File

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

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.