diff --git a/core/lib/Drupal/Core/Render/Element/Weight.php b/core/lib/Drupal/Core/Render/Element/Weight.php index 649de315fd72c9dec980d80827ff879405ddd1b7..029c9e4a4975c40a0eeed91d397562a0b8d774f3 100644 --- a/core/lib/Drupal/Core/Render/Element/Weight.php +++ b/core/lib/Drupal/Core/Render/Element/Weight.php @@ -45,16 +45,16 @@ public function getInfo() { } /** - * Expands a weight element into a select element. + * Expands a weight element into a select/number element. */ public static function processWeight(&$element, FormStateInterface $form_state, &$complete_form) { + // If the number of options is small enough, use a select field. Otherwise, + // use a number field. + $type = $element['#delta'] <= \Drupal::config('system.site')->get('weight_select_max') ? 'select' : 'number'; + $element = array_merge($element, \Drupal::service('element_info')->getInfo($type)); $element['#is_weight'] = TRUE; - $element_info_manager = \Drupal::service('element_info'); - // If the number of options is small enough, use a select field. - $max_elements = \Drupal::config('system.site')->get('weight_select_max'); - if ($element['#delta'] <= $max_elements) { - $element['#type'] = 'select'; + if ($type === 'select') { $weights = []; for ($n = (-1 * $element['#delta']); $n <= $element['#delta']; $n++) { $weights[$n] = $n; @@ -65,14 +65,10 @@ public static function processWeight(&$element, FormStateInterface $form_state, ksort($weights); } $element['#options'] = $weights; - $element += $element_info_manager->getInfo('select'); } - // Otherwise, use a text field. else { - $element['#type'] = 'number'; // Use a field big enough to fit most weights. $element['#size'] = 10; - $element += $element_info_manager->getInfo('number'); } return $element; diff --git a/core/modules/system/tests/modules/element_info_test/element_info_test.info.yml b/core/modules/system/tests/modules/element_info_test/element_info_test.info.yml new file mode 100644 index 0000000000000000000000000000000000000000..9e43148ee610038e9459d9f960a56dd9fd2bded2 --- /dev/null +++ b/core/modules/system/tests/modules/element_info_test/element_info_test.info.yml @@ -0,0 +1,5 @@ +name: 'Element info test' +type: module +package: Testing +version: VERSION +core: 8.x diff --git a/core/modules/system/tests/modules/element_info_test/element_info_test.module b/core/modules/system/tests/modules/element_info_test/element_info_test.module new file mode 100644 index 0000000000000000000000000000000000000000..58ebc889e2a063ab1fc1483f68d353b03b9b9b63 --- /dev/null +++ b/core/modules/system/tests/modules/element_info_test/element_info_test.module @@ -0,0 +1,24 @@ +<?php + +/** + * @file + * Element info test. + */ + +/** + * Implements hook_element_info_alter(). + */ +function element_info_test_element_info_alter(array &$info) { + $info['number'] += ['#pre_render' => []]; + /* @see \Drupal\KernelTests\Core\Render\Element\WeightTest::testProcessWeightSelectMax() */ + $info['number']['#pre_render'][] = 'element_info_test_element_pre_render'; +} + +/** + * {@inheritdoc} + * + * @see \Drupal\KernelTests\Core\Render\Element\WeightTest::testProcessWeightSelectMax() + */ +function element_info_test_element_pre_render(array $element) { + return $element; +} diff --git a/core/tests/Drupal/KernelTests/Core/Render/Element/WeightTest.php b/core/tests/Drupal/KernelTests/Core/Render/Element/WeightTest.php index 123c5e6521451b0a41910fffe5d2be626f0a2cb8..b44b98cf12833f27dbd3df4cfe7ea84279abadae 100644 --- a/core/tests/Drupal/KernelTests/Core/Render/Element/WeightTest.php +++ b/core/tests/Drupal/KernelTests/Core/Render/Element/WeightTest.php @@ -3,6 +3,8 @@ namespace Drupal\KernelTests\Core\Render\Element; use Drupal\Core\Form\FormState; +use Drupal\Core\Render\Element\Number; +use Drupal\Core\Render\Element\Select; use Drupal\Core\Render\Element\Weight; use Drupal\KernelTests\KernelTestBase; @@ -15,7 +17,7 @@ class WeightTest extends KernelTestBase { /** * {@inheritdoc} */ - protected static $modules = ['system']; + protected static $modules = ['system', 'element_info_test']; /** * {@inheritdoc} @@ -49,4 +51,76 @@ public function testProcessWeight() { ); } + /** + * Test transformation from "select" to "number" for MAX_DELTA + 1. + * + * @throws \Exception + * + * @covers ::processWeight + */ + public function testProcessWeightSelectMax() { + $form_state = new FormState(); + $definition = [ + '#type' => 'weight', + '#delta' => $this->container + ->get('config.factory') + ->get('system.site') + ->get('weight_select_max'), + // Expected by the "doBuildForm()" method of "form_builder" service. + '#parents' => [], + ]; + + $assert = function ($type, array $element, array $expected) use ($form_state) { + // Pretend we have a form to trigger the "#process" callbacks. + $element = $this->container + ->get('form_builder') + ->doBuildForm(__FUNCTION__, $element, $form_state); + + $expected['#type'] = $type; + + foreach ($expected as $property => $value) { + static::assertSame($value, $element[$property]); + } + + return $element; + }; + + // When the "#delta" is less or equal to maximum the "weight" must be + // rendered as a "select". + $select = $definition; + $assert('select', $select, [ + '#process' => [ + [Select::class, 'processSelect'], + [Select::class, 'processAjaxForm'], + ], + '#pre_render' => [ + [Select::class, 'preRenderSelect'], + ], + ]); + + $number = $definition; + // Increase "#delta" in order to start rendering "number" elements + // instead of "select". + $number['#delta']++; + // The "number" element definition has the "#pre_render" declaration by + // default. The "hook_element_info_alter()" allows to modify the definition + // of an element. We must be sure the standard "#pre_render" callbacks + // are presented (unless explicitly removed) even in a case when the array + // is modified by the alter hook. + $assert('number', $number, [ + '#process' => [ + [Number::class, 'processAjaxForm'], + ], + '#element_validate' => [ + [Number::class, 'validateNumber'], + ], + '#pre_render' => [ + [Number::class, 'preRenderNumber'], + // The custom callback is appended. + /* @see element_info_test_element_info_alter() */ + 'element_info_test_element_pre_render', + ], + ]); + } + }