function Internal::generateACFSettings

Same name in other branches
  1. 8.9.x core/modules/ckeditor/src/Plugin/CKEditorPlugin/Internal.php \Drupal\ckeditor\Plugin\CKEditorPlugin\Internal::generateACFSettings()

Builds the ACF part of the CKEditor JS settings.

This ensures that CKEditor obeys the HTML restrictions defined by Drupal's filter system, by enabling CKEditor's Advanced Content Filter (ACF) functionality: http://ckeditor.com/blog/CKEditor-4.1-RC-Released.

Parameters

\Drupal\editor\Entity\Editor $editor: A configured text editor object.

Return value

array An array with two values:

  • the first value is the "allowedContent" setting: a well-formatted array or TRUE. The latter indicates that anything is allowed.
  • the second value is the "disallowedContent" setting: a well-formatted array or FALSE. The latter indicates that nothing is disallowed.

See also

getConfig()

1 call to Internal::generateACFSettings()
Internal::getConfig in core/modules/ckeditor/src/Plugin/CKEditorPlugin/Internal.php
Returns the additions to CKEDITOR.config for a specific CKEditor instance.

File

core/modules/ckeditor/src/Plugin/CKEditorPlugin/Internal.php, line 409

Class

Internal
Defines the "internal" plugin (i.e. core plugins part of our CKEditor build).

Namespace

Drupal\ckeditor\Plugin\CKEditorPlugin

Code

protected function generateACFSettings(Editor $editor) {
    // When no text format is associated yet, assume nothing is disallowed, so
    // set allowedContent to true.
    if (!$editor->hasAssociatedFilterFormat()) {
        return TRUE;
    }
    $format = $editor->getFilterFormat();
    $filter_types = $format->getFilterTypes();
    // When nothing is disallowed, set allowedContent to true.
    if (!in_array(FilterInterface::TYPE_HTML_RESTRICTOR, $filter_types)) {
        return [
            TRUE,
            FALSE,
        ];
    }
    else {
        $get_attribute_values = function ($attribute_values, $allowed_values) {
            $values = array_keys(array_filter($attribute_values, function ($value) use ($allowed_values) {
                if ($allowed_values) {
                    return $value !== FALSE;
                }
                else {
                    return $value === FALSE;
                }
            }));
            if (count($values)) {
                return implode(',', $values);
            }
            else {
                return NULL;
            }
        };
        $html_restrictions = $format->getHtmlRestrictions();
        // When all HTML is allowed, also set allowedContent to true and
        // disallowedContent to false.
        if ($html_restrictions === FALSE) {
            return [
                TRUE,
                FALSE,
            ];
        }
        $allowed = [];
        $disallowed = [];
        if (isset($html_restrictions['forbidden_tags'])) {
            foreach ($html_restrictions['forbidden_tags'] as $tag) {
                $disallowed[$tag] = TRUE;
            }
        }
        foreach ($html_restrictions['allowed'] as $tag => $attributes) {
            // Tell CKEditor the tag is allowed, but no attributes.
            if ($attributes === FALSE) {
                $allowed[$tag] = [
                    'attributes' => FALSE,
                    'styles' => FALSE,
                    'classes' => FALSE,
                ];
            }
            elseif ($attributes === TRUE) {
                $allowed[$tag] = [
                    'attributes' => TRUE,
                    'styles' => TRUE,
                    'classes' => TRUE,
                ];
                // We've just marked that any value for the "style" and "class"
                // attributes is allowed. However, that may not be the case: the "*"
                // tag may still apply restrictions.
                // Since CKEditor's ACF follows the following principle:
                // - Once validated, an element or its property cannot be
                //   invalidated by another rule.
                // That means that the most permissive setting wins. Which means that
                // it will still be allowed by CKEditor, for instance, to define any
                // style, no matter what the "*" tag's restrictions may be. If there
                // is a setting for either the "style" or "class" attribute, it cannot
                // possibly be more permissive than what was set above. Hence, inherit
                // from the "*" tag where possible.
                if (isset($html_restrictions['allowed']['*'])) {
                    $wildcard = $html_restrictions['allowed']['*'];
                    if (isset($wildcard['style'])) {
                        if (!is_array($wildcard['style'])) {
                            $allowed[$tag]['styles'] = $wildcard['style'];
                        }
                        else {
                            $allowed_styles = $get_attribute_values($wildcard['style'], TRUE);
                            if (isset($allowed_styles)) {
                                $allowed[$tag]['styles'] = $allowed_styles;
                            }
                            else {
                                unset($allowed[$tag]['styles']);
                            }
                        }
                    }
                    if (isset($wildcard['class'])) {
                        if (!is_array($wildcard['class'])) {
                            $allowed[$tag]['classes'] = $wildcard['class'];
                        }
                        else {
                            $allowed_classes = $get_attribute_values($wildcard['class'], TRUE);
                            if (isset($allowed_classes)) {
                                $allowed[$tag]['classes'] = $allowed_classes;
                            }
                            else {
                                unset($allowed[$tag]['classes']);
                            }
                        }
                    }
                }
            }
            elseif (is_array($attributes)) {
                // Set defaults (these will be overridden below if more specific
                // values are present).
                $allowed[$tag] = [
                    'attributes' => FALSE,
                    'styles' => FALSE,
                    'classes' => FALSE,
                ];
                // Configure allowed attributes, allowed "style" attribute values and
                // allowed "class" attribute values.
                // CKEditor only allows specific values for the "class" and "style"
                // attributes; so ignore restrictions on other attributes, which
                // Drupal filters may provide.
                // NOTE: A Drupal contrib module can subclass this class, override the
                // getConfig() method, and override the JavaScript at
                // Drupal.editors.ckeditor to somehow make validation of values for
                // attributes other than "class" and "style" work.
                $allowed_attributes = array_filter($attributes, function ($value) {
                    return $value !== FALSE;
                });
                if (count($allowed_attributes)) {
                    $allowed[$tag]['attributes'] = implode(',', array_keys($allowed_attributes));
                }
                if (isset($allowed_attributes['style'])) {
                    if (is_bool($allowed_attributes['style'])) {
                        $allowed[$tag]['styles'] = $allowed_attributes['style'];
                    }
                    elseif (is_array($allowed_attributes['style'])) {
                        $allowed_classes = $get_attribute_values($allowed_attributes['style'], TRUE);
                        if (isset($allowed_classes)) {
                            $allowed[$tag]['styles'] = $allowed_classes;
                        }
                    }
                }
                if (isset($allowed_attributes['class'])) {
                    if (is_bool($allowed_attributes['class'])) {
                        $allowed[$tag]['classes'] = $allowed_attributes['class'];
                    }
                    elseif (is_array($allowed_attributes['class'])) {
                        $allowed_classes = $get_attribute_values($allowed_attributes['class'], TRUE);
                        if (isset($allowed_classes)) {
                            $allowed[$tag]['classes'] = $allowed_classes;
                        }
                    }
                }
                // Handle disallowed attributes analogously. However, to handle *dis-
                // allowed* attribute values, we must look at *allowed* attributes'
                // disallowed attribute values! After all, a disallowed attribute
                // implies that all of its possible attribute values are disallowed,
                // thus we must look at the disallowed attribute values on allowed
                // attributes.
                $disallowed_attributes = array_filter($attributes, function ($value) {
                    return $value === FALSE;
                });
                if (count($disallowed_attributes)) {
                    // No need to blacklist the 'class' or 'style' attributes; CKEditor
                    // handles them separately (if no specific class or style attribute
                    // values are allowed, then those attributes are disallowed).
                    if (isset($disallowed_attributes['class'])) {
                        unset($disallowed_attributes['class']);
                    }
                    if (isset($disallowed_attributes['style'])) {
                        unset($disallowed_attributes['style']);
                    }
                    $disallowed[$tag]['attributes'] = implode(',', array_keys($disallowed_attributes));
                }
                if (isset($allowed_attributes['style']) && is_array($allowed_attributes['style'])) {
                    $disallowed_styles = $get_attribute_values($allowed_attributes['style'], FALSE);
                    if (isset($disallowed_styles)) {
                        $disallowed[$tag]['styles'] = $disallowed_styles;
                    }
                }
                if (isset($allowed_attributes['class']) && is_array($allowed_attributes['class'])) {
                    $disallowed_classes = $get_attribute_values($allowed_attributes['class'], FALSE);
                    if (isset($disallowed_classes)) {
                        $disallowed[$tag]['classes'] = $disallowed_classes;
                    }
                }
            }
        }
        ksort($allowed);
        ksort($disallowed);
        return [
            $allowed,
            $disallowed,
        ];
    }
}

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