1 ckeditor.module ckeditor_get_acf_settings($format)

Builds the ACF part of the CKEditor 4 JS settings.

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

Parameters

$format: The text format 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.

File

core/modules/ckeditor/ckeditor.module, line 579
Provides integration with the CKEditor 4 WYSIWYG editor.

Code

function ckeditor_get_acf_settings($format) {
  $html_restrictions = filter_format_allowed_html($format);

  // When all HTML is allowed, also set allowedContent to true and
  // disallowedContent to false.
  if ($html_restrictions === TRUE) {
    return array(TRUE, FALSE);
  }

  /**
   * Converts Backdrop-stored attribute values to CKEditor 4 attribute lists.
   */
  $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;
    }
  };

  $allowed = array();
  $disallowed = array();
  if (isset($html_restrictions['forbidden'])) {
    foreach ($html_restrictions['forbidden'] 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] = array(
        'attributes' => FALSE,
        'styles' => FALSE,
        'classes' => FALSE,
      );
    }
    // Tell CKEditor the tag is allowed, as well as any attribute on it. The
    // "style" and "class" attributes are handled separately by CKEditor:
    // they are disallowed even if you specify it in the list of allowed
    // attributes, unless you state specific values for them that are
    // allowed. Or, in this case: any value for them is allowed.
    elseif ($attributes === TRUE) {
      $allowed[$tag] = array(
        '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 to e.g. define any style, no
      // matter what the "*" tag's restrictions may be. If there's 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']);
            }
          }
        }
      }
    }
    // Tell CKEditor the tag is allowed, along with some tags.
    elseif (is_array($attributes)) {
      // 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']) && is_array($allowed_attributes['style'])) {
        $allowed_styles = $get_attribute_values($allowed_attributes['style'], TRUE);
        if (isset($allowed_styles)) {
          $allowed[$tag]['styles'] = $allowed_styles;
        }
      }
      if (isset($allowed_attributes['class']) && 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 disallow 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;
        }
      }
    }
  }

  return array($allowed, $disallowed);
}