better_formats.module in Better Formats 8
Same filename and directory in other branches
Enhances the core input format system by managing input format defaults and settings.
File
better_formats.moduleView source
<?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_field_widget_form_alter().
*
*/
function better_formats_field_widget_form_alter(&$element, FormStateInterface $form_state, $context) {
$field_definition = $context['items']
->getFieldDefinition();
if (!$field_definition instanceof ThirdPartySettingsInterface) {
return;
}
$betterFormatsSettings = $field_definition
->getThirdPartySettings('better_formats');
if (empty($betterFormatsSettings)) {
return;
}
$element['#better_formats']['settings'] = $betterFormatsSettings;
$element['#better_formats']['existing_entity'] = FALSE;
$entity = $context['items']
->getEntity();
if (!empty($entity)) {
// Determine if this is an existing entity.
if ($entity
->id()) {
$element['#better_formats']['existing_entity'] = TRUE;
}
$element['#better_formats']['entity_type'] = $entity
->getEntityTypeId();
$default_value = $field_definition
->getDefaultValue($entity);
$default_value = array_shift($default_value);
$element['#better_formats']['default_value'] = isset($default_value['format']) ? $default_value['format'] : NULL;
}
}
/**
* 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'];
if (!empty($element['#better_formats']['settings'])) {
$betterFormatsSettings = $element['#better_formats']['settings'];
}
else {
return $element;
}
if (!empty($element['#better_formats']['entity_type'])) {
$entity_type = $element['#better_formats']['entity_type'];
}
// Whether use the core field module default value to set the default format.
// See /admin/config/content/formats/settings.
if (Drupal::config('better_formats.settings')
->get('per_field_core')) {
better_formats_set_default_format($element, $element['#better_formats']['default_value']);
}
// 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) {
// Need to only do this on create forms.
if (!$element['#better_formats']['existing_entity'] && isset($betterFormatsSettings) && !empty($betterFormatsSettings['default_order_toggle']) && !empty($betterFormatsSettings['default_order_wrapper']['formats'])) {
$order = $betterFormatsSettings['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($betterFormatsSettings) && !empty($betterFormatsSettings['allowed_formats_toggle']) && !empty($betterFormatsSettings['allowed_formats'])) {
// Filter the list of available formats to those allowed on this field.
$allowed_fields = array_filter($betterFormatsSettings['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;
}
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));
}
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.
$betterFormatsSettings = $entity
->getThirdPartySettings('better_formats') != NULL ? $entity
->getThirdPartySettings('better_formats') : [];
// Add in the better formats table.
$form['third_party_settings'] += better_formats_field_settings_form($betterFormatsSettings);
$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 global 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();
}
}
Functions
Name | Description |
---|---|
better_formats_element_info_alter | Implements hook_element_info_alter(). |
better_formats_field_config_edit_form_submit | Submit handler for field instance edit form. |
better_formats_field_settings_form | Build the settings form for Field API fields. |
better_formats_field_widget_form_alter | Implements hook_field_widget_form_alter(). |
better_formats_filter_process_format | Process callback for form elements that have a text format selector attached. |
better_formats_form_field_config_edit_form_alter | Implements hook_form_FORM_ID_alter(). |
better_formats_is_text_format | Determine if text field type uses text formatter. |
better_formats_set_default_format | Set the default format for the element. |
better_formats_text_format_sort | Sort text formats by weight. |