Further modules included.
[yaffs-website] / web / modules / contrib / better_formats / better_formats.module
diff --git a/web/modules/contrib/better_formats/better_formats.module b/web/modules/contrib/better_formats/better_formats.module
new file mode 100644 (file)
index 0000000..5680144
--- /dev/null
@@ -0,0 +1,429 @@
+<?php
+
+/**
+ * @file
+ * Enhances the core input format system by managing input format defaults and settings.
+ */
+
+use Drupal\Core\Config\Entity\ThirdPartySettingsInterface;
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Render\Element;
+
+/**
+ * Implements hook_element_info_alter().
+ */
+function better_formats_element_info_alter(array &$types) {
+  // Our process callback must run immediately after
+  // TextFormat::processFormat().
+  if (isset($types['text_format']) && isset($types['text_format']['#process'])) {
+    $search_value = ['Drupal\filter\Element\TextFormat', 'processFormat'];
+    $key = array_search($search_value, $types['text_format']['#process']);
+
+    if ($key !== FALSE) {
+      $key++;
+      array_splice($types['text_format']['#process'], $key, 0, 'better_formats_filter_process_format');
+    }
+    else {
+      $types['text_format']['#process'][] = 'better_formats_filter_process_format';
+    }
+  }
+}
+
+/**
+ * Process callback for form elements that have a text format selector attached.
+ *
+ * This callback runs after filter_process_format() and performs additional
+ * modifications to the form element.
+ *
+ * @see \Drupal\filter\Element\TextFormat::processFormat()
+ */
+function better_formats_filter_process_format(array &$element, FormStateInterface $form_state, array $complete_form) {
+  // Before we make any modifications to the element, record whether or not
+  // TextFormat::processFormat() has determined that (for security reasons) the
+  // user is not allowed to make any changes to this field. This will happen if
+  // the user does not have permission to use the currently-assigned text
+  // format.
+  $access_denied_for_security = isset($element['format']['format']['#access']) && !$element['format']['format']['#access'];
+
+  $form_object = $form_state->getFormObject();
+
+  if ($form_object instanceof Drupal\Core\Entity\ContentEntityForm) {
+    $entity = $form_state->getFormObject()->getEntity();
+    $entity_type = $entity->getEntityTypeId();
+    $field_name = reset($element['#parents']);
+    $field_definition = $entity->getFieldDefinition($field_name);
+
+    if ($field_definition instanceof ThirdPartySettingsInterface) {
+      $bf = $field_definition->getThirdPartySettings('better_formats');
+
+      if (Drupal::config('better_formats.settings')->get('per_field_core')) {
+        $field_defaults = $field_definition->getDefaultValue($entity);
+        $default_value = array_shift($field_defaults);
+        better_formats_set_default_format($element, $default_value['format']);
+      }
+    }
+  }
+  elseif ($form_object instanceof Drupal\field_ui\Form\FieldConfigEditForm) {
+    $entity = $form_state->getFormObject()->getEntity();
+    $entity_type = $entity->getTargetEntityTypeId();
+    $bf = $entity->getThirdPartySettings('better_formats');
+  }
+  else {
+    return $element;
+  }
+
+  // Now hide several parts of the element for cosmetic reasons (depending on
+  // the permissions of the current user).
+  $user = \Drupal::currentUser();
+  $user_is_admin = $user->hasPermission('administer filters');
+
+  // The selection should be shown unless proven otherwise.
+  $hide_selection = FALSE;
+
+  // If an entity is available then allow Better Formats permission to control
+  // visibility.
+  if ($entity_type != NULL) {
+    $hide_selection = $user->hasPermission('hide format selection for ' . $entity_type);
+  }
+
+  // Privileged users should still be able to change the format selection.
+  if ($hide_selection && !$user_is_admin) {
+    $element['format']['format']['#access'] = FALSE;
+  }
+
+  // Allow formats tips to be hidden.
+  $hide_tips = $user->hasPermission('hide format tips');
+
+  if ($hide_tips && !$user_is_admin) {
+    $element['format']['guidelines']['#access'] = FALSE;
+  }
+
+  // Allow format tips link to be hidden.
+  $hide_tips_link = $user->hasPermission('hide more format tips link');
+
+  if ($hide_tips_link && !$user_is_admin) {
+    $element['format']['help']['#access'] = FALSE;
+  }
+
+  // If the element represents a field attached to an entity, we may need to
+  // adjust the allowed text format options. However, we don't want to touch
+  // this if TextFormat::processFormat() has determined that (for security
+  // reasons) the user is not allowed to make any changes; in that case, Drupal
+  // core will hide the format selector and force the field to be saved with its
+  // current values, and we should not do anything to alter that process.
+  if ($entity_type != NULL && !$access_denied_for_security) {
+    $eid = $entity->id();
+
+    // Need to only do this on create forms.
+    if (empty($eid) && isset($bf) && !empty($bf['default_order_toggle']) && !empty($bf['default_order_wrapper']['formats'])) {
+      $order = $bf['default_order_wrapper']['formats'];
+      uasort($order, 'better_formats_text_format_sort');
+
+      $options = [];
+
+      foreach ($order as $id => $weight) {
+        if (isset($element['format']['format']['#options'][$id])) {
+          $options[$id] = $element['format']['format']['#options'][$id];
+        }
+      }
+
+      $element['format']['format']['#options'] = $options;
+      $options_keys = array_keys($options);
+
+      if (!Drupal::config('better_formats.settings')->get('per_field_core')) {
+        better_formats_set_default_format($element, array_shift($options_keys));
+      }
+    }
+    if (isset($bf) && !empty($bf['allowed_formats_toggle']) && !empty($bf['allowed_formats'])) {
+      // Filter the list of available formats to those allowed on this field.
+      $allowed_fields = array_filter($bf['allowed_formats']);
+      $options = &$element['format']['format']['#options'];
+      $options = array_intersect_key($options, $allowed_fields);
+
+      // If there is only one allowed format, deny access to the text format
+      // selector for cosmetic reasons, just like filter_process_format() does.
+      if (count($options) == 1) {
+        $element['format']['format']['#access'] = FALSE;
+        $hide_selection = TRUE;
+      }
+
+      // If there are no allowed formats, we need to deny access to the entire
+      // field, since it doesn't make sense to add or edit content that does
+      // not have a text format.
+      if (empty($options)) {
+        $element['#access'] = FALSE;
+      }
+      // Otherwise, if the current default format is no longer one of the
+      // allowed options, a new default format must be assigned.
+      elseif (!isset($options[$element['format']['format']['#default_value']])) {
+        // If there is no text in the field, it is safe to automatically assign
+        // a new default format. We pick the first available option to be
+        // consistent with what filter_default_format() does.
+        if (!isset($element['value']['#default_value']) || $element['value']['#default_value'] === '') {
+          $formats = array_keys($options);
+          better_formats_set_default_format($element, reset($formats));
+        }
+        // Otherwise, it is unsafe to automatically assign a new default format
+        // (since this will display the content in a way that was not
+        // originally intended and might be dangerous, e.g. if the content
+        // contains an attempted XSS attack). A human must explicitly decide
+        // which new format to assign, so we force the field to be required but
+        // with no default value, similar to what filter_process_format() does.
+        // Although filter_process_format() limits this functionality to users
+        // with the 'administer filters' permission, we can allow it for any
+        // user here since we know that the user already has permission to use
+        // the current format; thus, there is no danger of exposing unformatted
+        // text (for example, raw PHP code) that they are otherwise not allowed
+        // to see.
+        else {
+          $element['format']['format']['#required'] = TRUE;
+          better_formats_set_default_format($element, NULL);
+          // Force access to the format selector (it may have been denied
+          // previously for cosmetic reasons).
+          $element['format']['#access'] = TRUE;
+          $element['format']['format']['#access'] = TRUE;
+        }
+      }
+    }
+  }
+
+  // If the user is not supposed to see the text format selector, hide all
+  // guidelines except those associated with the default format. We need to do
+  // this at the end, since the above code may have altered the default format.
+  if ($hide_selection && isset($element['format']['format']['#default_value'])) {
+    foreach (Element::children($element['format']['guidelines']) as $format) {
+      if ($format != $element['format']['format']['#default_value']) {
+        $element['format']['guidelines'][$format]['#access'] = FALSE;
+      }
+    }
+  }
+
+  // Keep the format for validation and submit processing but don't sent it to
+  // the browser if the user is not supposed to see anything inside of it.
+  if ($hide_selection && $hide_tips && $hide_tips_link) {
+    unset($element['format']['#type']);
+  }
+
+  return $element;
+}
+
+/**
+ * Determine if text field type uses text formatter.
+ *
+ * @param string $type
+ *   The field type to check.
+ *
+ * @return bool
+ *   TRUE if input field type uses text formatter, FALSE if it does not.
+ */
+function better_formats_is_text_format($type) {
+  if (in_array($type, ['text', 'text_long', 'text_with_summary'], TRUE)) {
+    return TRUE;
+  }
+  else {
+    return FALSE;
+  }
+}
+
+/**
+ * Set the default format for the element.
+ *
+ * @param array $element
+ *    The form element to set the default format on.
+ * @param string $default_value
+ *    The id for the format to set as default.
+ */
+function better_formats_set_default_format(array &$element, $default_value) {
+  $element['#format'] = $default_value;
+  $element['format']['format']['#default_value'] = $default_value;
+}
+
+/**
+ * Sort text formats by weight.
+ *
+ * @param array $a
+ *   Array containing weight value to compare.
+ * @param array $b
+ *   Array containing weight value to compare.
+ *
+ * @return bool
+ *   TRUE if the weight of $a is greater than $b, FALSE if weight of $b is
+ *   greater than $a or equal to $a.
+ */
+function better_formats_text_format_sort($a, $b) {
+  return $a['weight'] > $b['weight'];
+}
+
+/**
+ * Implements hook_form_FORM_ID_alter().
+ */
+function better_formats_form_field_config_edit_form_alter(&$form, FormStateInterface $form_state, $form_id) {
+  $entity = $form_state->getFormObject()->getEntity();
+
+  // Only alter fields with text processing and if admin has chosen.
+  $text_processing = better_formats_is_text_format($entity->getType());
+  $config = Drupal::config('better_formats.settings');
+
+  if ($text_processing && $config->get('per_field_core')) {
+    // Add a submit handler to save default values on empty fields.
+    $form['actions']['submit']['#submit'][] = 'better_formats_field_config_edit_form_submit';
+  }
+
+  // If the field is a format-using text field, allow the admin to configure
+  // which formats are allowed here.
+  if ($text_processing) {
+    // We have to set an explicit weight here so that we can put the allowed
+    // formats list after it.
+    $bf_settings = $entity->getThirdPartySettings('better_formats') != NULL ? $entity->getThirdPartySettings('better_formats') : [];
+
+    // Add in the better formats table.
+    $form['third_party_settings'] += better_formats_field_settings_form($bf_settings);
+    $form['third_party_settings']['#weight'] = -4;
+  }
+}
+
+/**
+ * Build the settings form for Field API fields.
+ *
+ * @param array $bf_form
+ *   The existing better formats settings form from the form element.
+ *
+ * @return array
+ *   The array of better formats form items.
+ */
+function better_formats_field_settings_form($bf_form = []) {
+  $formats = filter_formats();
+  // Plain Text Format should not be an option, that is a separate field type.
+  unset($formats['plain_text']);
+
+  $form = [];
+  $form['better_formats'] = [
+    '#tree' => TRUE,
+    '#type' => 'fieldset',
+    '#title' => t('Text Formats'),
+    '#weight' => 0,
+  ];
+
+  $allowed_options = [];
+
+  foreach ($formats as $format) {
+    $allowed_options[$format->id()] = $format->label();
+  }
+
+  $allowed_toggle_default = isset($bf_form['allowed_formats_toggle']) ? $bf_form['allowed_formats_toggle'] : FALSE;
+  $allowed_defaults = isset($bf_form['allowed_formats']) ? $bf_form['allowed_formats'] : [];
+
+  if (empty($allowed_defaults)) {
+    $allowed_defaults = array_keys($allowed_options);
+  }
+
+  $form['better_formats']['allowed_formats_toggle'] = [
+    '#type' => 'checkbox',
+    '#title' => t('Limit allowed text formats'),
+    '#description' => t('Check the allowed formats below. If checked available text formats can be chosen.'),
+    '#weight' => 1,
+    '#default_value' => $allowed_toggle_default,
+  ];
+  $form['better_formats']['allowed_formats'] = [
+    '#type' => 'checkboxes',
+    '#title' => t('Allowed formats'),
+    '#options' => $allowed_options,
+    '#description' => t('Select the text formats allowed for this field. Note that not all of these may appear on the form if a user does not have permission to use them. <strong>Warning:</strong> This affects existing content which may leave you unable to edit some fields. If that happens you must allow the format that field was saved in here.'),
+    '#weight' => 2,
+    '#default_value' => $allowed_defaults,
+    '#states' => [
+      'visible' => [
+        ':input[name="third_party_settings[better_formats][allowed_formats_toggle]"]' => ['checked' => TRUE],
+      ],
+    ],
+  ];
+
+  $order_toggle_default = isset($bf_form['default_order_toggle']) ? $bf_form['default_order_toggle'] : FALSE;
+
+  $form['better_formats']['default_order_toggle'] = [
+    '#type' => 'checkbox',
+    '#title' => t('Override default order'),
+    '#description' => t('Override the gloabl order that will determine the default text format a user will get <strong>only on entity creation</strong>.'),
+    '#weight' => 3,
+    '#default_value' => $order_toggle_default,
+  ];
+  $form['better_formats']['default_order_wrapper'] = [
+    '#tree' => TRUE,
+    '#type' => 'container',
+    '#weight' => 4,
+    '#states' => [
+      'visible' => [
+        ':input[name="third_party_settings[better_formats][default_order_toggle]"]' => ['checked' => TRUE],
+      ],
+    ],
+  ];
+
+  // Formats ordering table.
+  $form['better_formats']['default_order_wrapper']['formats'] = [
+    '#type' => 'table',
+    '#header' => [t('Format'), t('Weight')],
+    '#empty' => t('There are no items yet.'),
+    '#tabledrag' => [
+      [
+        'action' => 'order',
+        'relationship' => 'sibling',
+        'group' => 'format-order-weight',
+      ],
+    ],
+  ];
+
+  foreach ($formats as $id => $format) {
+    $default = isset($bf_form['default_order_wrapper']['formats'][$id]) ? $bf_form['default_order_wrapper']['formats'][$id] : NULL;
+    $weight = isset($default['weight']) ? $default['weight'] : $format->get('weight');
+
+    // TableDrag: Mark the table row as draggable.
+    $form['better_formats']['default_order_wrapper']['formats'][$id]['#attributes']['class'][] = 'draggable';
+    // TableDrag: Sort the table row according to its existing/configured weight.
+    $form['better_formats']['default_order_wrapper']['formats'][$id]['#weight'] = $weight;
+
+    // Some table columns containing raw markup.
+    $form['better_formats']['default_order_wrapper']['formats'][$id]['label'] = [
+      '#markup' => $format->label(),
+    ];
+
+    // TableDrag: Weight column element.
+    $form['better_formats']['default_order_wrapper']['formats'][$id]['weight'] = [
+      '#type' => 'weight',
+      '#title' => t('Weight for @title', ['@title' => $format->label()]),
+      '#title_display' => 'invisible',
+      '#default_value' => $weight,
+      // Classify the weight element for #tabledrag.
+      '#attributes' => ['class' => ['format-order-weight']],
+    ];
+  }
+
+  // Sort formats according to weight.
+  Element::children($form['better_formats']['default_order_wrapper']['formats'], TRUE);
+
+  return $form;
+}
+
+/**
+ * Submit handler for field instance edit form.
+ *
+ * Copied and slightly modifed from FieldConfigEditForm::submitForm().
+ *
+ * @see \Drupal\field_ui\Form\FieldConfigEditForm::submitForm()
+ */
+function better_formats_field_config_edit_form_submit(array &$form, FormStateInterface $form_state) {
+  $entity = $form_state->getFormObject()->getEntity();
+  $text_processing = better_formats_is_text_format($entity->getType());
+
+  // Only act on fields that have text processing enabled.
+  if ($text_processing) {
+    // Handle the default value.
+    $default_value = [];
+    $default_input_value = $form_state->getValue(['default_value_input', $entity->getName()]);
+
+    if ($default_input_value != NULL) {
+      $default_value = $default_input_value;
+    }
+
+    $entity->setDefaultValue($default_value)->save();
+  }
+}