file ProcessManager.php

Namespace

Drupal\bootstrap\Plugin
  1. <?php
  2. namespace Drupal\bootstrap\Plugin;
  3. use Drupal\bootstrap\Bootstrap;
  4. use Drupal\bootstrap\Theme;
  5. use Drupal\bootstrap\Utility\Element;
  6. use Drupal\Component\Utility\NestedArray;
  7. use Drupal\Core\Form\FormStateInterface;
  8. /**
  9. * Manages discovery and instantiation of Bootstrap form process callbacks.
  10. *
  11. * @ingroup plugins_process
  12. */
  13. class ProcessManager extends PluginManager {
  14. /**
  15. * Constructs a new \Drupal\bootstrap\Plugin\ProcessManager object.
  16. *
  17. * @param \Drupal\bootstrap\Theme $theme
  18. * The theme to use for discovery.
  19. */
  20. public function __construct(Theme $theme) {
  21. parent::__construct($theme, 'Plugin/Process', 'Drupal\bootstrap\Plugin\Process\ProcessInterface', 'Drupal\bootstrap\Annotation\BootstrapProcess');
  22. $this->setCacheBackend(\Drupal::cache('discovery'), 'theme:' . $theme->getName() . ':process', $this->getCacheTags());
  23. }
  24. /**
  25. * Global #process callback for form elements.
  26. *
  27. * @param array $element
  28. * The element render array.
  29. * @param \Drupal\Core\Form\FormStateInterface $form_state
  30. * The current state of the form.
  31. * @param array $complete_form
  32. * The complete form structure.
  33. *
  34. * @return array
  35. * The altered element array.
  36. *
  37. * @see \Drupal\bootstrap\Plugin\Alter\ElementInfo::alter
  38. */
  39. public static function process(array $element, FormStateInterface $form_state, array &$complete_form) {
  40. if (!empty($element['#bootstrap_ignore_process'])) {
  41. return $element;
  42. }
  43. static $theme;
  44. if (!isset($theme)) {
  45. $theme = Bootstrap::getTheme();
  46. }
  47. $e = Element::create($element, $form_state);
  48. // Process AJAX.
  49. if (($e->getProperty('ajax') && !$e->isButton()) || $e->getProperty('autocomplete_route_name')) {
  50. static::processAjax($e, $form_state, $complete_form);
  51. }
  52. // Add "form-inline" class.
  53. if ($e->hasClass('container-inline')) {
  54. $e->replaceClass('container-inline', 'form-inline');
  55. }
  56. if ($e->isType(['color', 'date', 'number', 'range', 'tel', 'weight'])) {
  57. $e->addClass('form-inline', 'wrapper_attributes');
  58. }
  59. // Process input groups.
  60. if ($e->getProperty('input') && ($e->getProperty('input_group') || $e->getProperty('input_group_button'))) {
  61. static::processInputGroups($e, $form_state, $complete_form);
  62. }
  63. return $element;
  64. }
  65. /**
  66. * Processes elements with AJAX properties.
  67. *
  68. * @param \Drupal\bootstrap\Utility\Element $element
  69. * The element object.
  70. * @param \Drupal\Core\Form\FormStateInterface $form_state
  71. * The current state of the form.
  72. * @param array $complete_form
  73. * The complete form structure.
  74. */
  75. public static function processAjax(Element $element, FormStateInterface $form_state, array &$complete_form) {
  76. $ajax = $element->getProperty('ajax');
  77. // Show throbber AJAX requests in an input button group.
  78. $ignore_types = ['checkbox', 'checkboxes', 'hidden', 'radio', 'radios'];
  79. if ((!isset($ajax['progress']['type']) || $ajax['progress']['type'] === 'throbber') && !$element->isType($ignore_types)) {
  80. // Use an icon for autocomplete "throbber".
  81. $icon = Bootstrap::glyphicon('refresh');
  82. $element->appendProperty('field_suffix', Element::create($icon)->addClass(['ajax-progress', 'ajax-progress-throbber']));
  83. $element->setProperty('input_group', TRUE);
  84. }
  85. }
  86. /**
  87. * Processes elements that have input groups.
  88. *
  89. * @param \Drupal\bootstrap\Utility\Element $element
  90. * The element object.
  91. * @param \Drupal\Core\Form\FormStateInterface $form_state
  92. * The current state of the form.
  93. * @param array $complete_form
  94. * The complete form structure.
  95. */
  96. protected static function processInputGroups(Element $element, FormStateInterface $form_state, array &$complete_form) {
  97. // Automatically inject the nearest button found after this element if
  98. // #input_group_button exists.
  99. if ($element->getProperty('input_group_button')) {
  100. // Obtain the parent array to limit search.
  101. $array_parents = $element->getProperty('array_parents', []);
  102. // Remove the current element from the array.
  103. array_pop($array_parents);
  104. // Retrieve the parent element.
  105. $parent = Element::create(NestedArray::getValue($complete_form, $array_parents), $form_state);
  106. // Find the closest button.
  107. if ($button = &$parent->findButton()) {
  108. // Since this button is technically being "moved", it needs to be
  109. // rendered now, so it doesn't get printed twice (in the original spot).
  110. $element->appendProperty('field_suffix', $button->setIcon()->render());
  111. }
  112. }
  113. $input_group_attributes = ['class' => ['input-group-' . ($element->getProperty('input_group_button') ? 'btn' : 'addon')]];
  114. if ($prefix = $element->getProperty('field_prefix')) {
  115. $element->setProperty('field_prefix', [
  116. '#type' => 'html_tag',
  117. '#tag' => 'span',
  118. '#attributes' => $input_group_attributes,
  119. '#value' => Element::create($prefix)->renderPlain(),
  120. '#weight' => -1,
  121. ]);
  122. }
  123. if ($suffix = $element->getProperty('field_suffix')) {
  124. $element->setProperty('field_suffix', [
  125. '#type' => 'html_tag',
  126. '#tag' => 'span',
  127. '#attributes' => $input_group_attributes,
  128. '#value' => Element::create($suffix)->renderPlain(),
  129. '#weight' => 1,
  130. ]);
  131. }
  132. }
  133. /**
  134. * Traverses an element to find the closest button.
  135. *
  136. * @param \Drupal\bootstrap\Utility\Element $element
  137. * The element to iterate over.
  138. *
  139. * @return \Drupal\bootstrap\Utility\Element|false
  140. * The first button element or FALSE if no button could be found.
  141. *
  142. * @deprecated Will be removed in a future release.
  143. * Use \Drupal\bootstrap\Utility\Element::findButton() directly.
  144. */
  145. protected static function &findButton(Element $element) {
  146. Bootstrap::deprecated();
  147. return $element->findButton();
  148. }
  149. }

Classes

Name Description
ProcessManager Manages discovery and instantiation of Bootstrap form process callbacks.