diff --git a/core/lib/Drupal/Core/Render/Element/Tableselect.php b/core/lib/Drupal/Core/Render/Element/Tableselect.php index 17a5fcc167..5d7058ab87 100644 --- a/core/lib/Drupal/Core/Render/Element/Tableselect.php +++ b/core/lib/Drupal/Core/Render/Element/Tableselect.php @@ -33,13 +33,11 @@ * $options = [ * 1 => ['first_name' => 'Indy', 'last_name' => 'Jones'], * 2 => ['first_name' => 'Darth', 'last_name' => 'Vader'], + * // Prevent users from selecting a row by adding a '#disabled' property set + * // to TRUE. * 3 => ['first_name' => 'Super', 'last_name' => 'Man', '#disabled' => TRUE], * ]; * - * Selecting a row could be prevented by adding a boolean #disabled property set - * to TRUE, just like in the 3rd row from the above example. This property is - * ignored when #multiple is FALSE. - * * $form['table'] = array( * '#type' => 'tableselect', * '#header' => $header, @@ -245,6 +243,7 @@ public static function processTableselect(&$element, FormStateInterface $form_st foreach ($element['#options'] as $key => $choice) { // Do not overwrite manually created children. if (!isset($element[$key])) { + $disabled = !empty($element['#options'][$key]['#disabled']); if ($element['#multiple']) { $title = ''; if (isset($element['#options'][$key]['title']) && is_array($element['#options'][$key]['title'])) { @@ -261,7 +260,7 @@ public static function processTableselect(&$element, FormStateInterface $form_st '#return_value' => $key, '#default_value' => isset($value[$key]) ? $key : NULL, '#attributes' => $element['#attributes'], - '#disabled' => !empty($element['#options'][$key]['#disabled']), + '#disabled' => $disabled, '#ajax' => isset($element['#ajax']) ? $element['#ajax'] : NULL, ]; } @@ -277,6 +276,7 @@ public static function processTableselect(&$element, FormStateInterface $form_st '#attributes' => $element['#attributes'], '#parents' => $element['#parents'], '#id' => HtmlUtility::getUniqueId('edit-' . implode('-', $parents_for_id)), + '#disabled' => $disabled, '#ajax' => isset($element['#ajax']) ? $element['#ajax'] : NULL, ]; } diff --git a/core/modules/system/tests/modules/form_test/form_test.routing.yml b/core/modules/system/tests/modules/form_test/form_test.routing.yml index ce4dfa98fb..219a40c0da 100644 --- a/core/modules/system/tests/modules/form_test/form_test.routing.yml +++ b/core/modules/system/tests/modules/form_test/form_test.routing.yml @@ -164,6 +164,14 @@ form_test.tableselect_js: requirements: _access: 'TRUE' +form_test.tableselect_disabled_rows: + path: '/form_test/tableselect/disabled-rows/{test_action}' + defaults: + _form: '\Drupal\form_test\Form\FormTestTableSelectDisabledRowsForm' + _title: 'Tableselect disabled rows tests' + requirements: + _access: 'TRUE' + form_test.vertical_tabs: path: '/form_test/vertical-tabs' defaults: diff --git a/core/modules/system/tests/modules/form_test/src/Form/FormTestTableSelectDisabledRowsForm.php b/core/modules/system/tests/modules/form_test/src/Form/FormTestTableSelectDisabledRowsForm.php new file mode 100644 index 0000000000..8b00bfb7d4 --- /dev/null +++ b/core/modules/system/tests/modules/form_test/src/Form/FormTestTableSelectDisabledRowsForm.php @@ -0,0 +1,44 @@ + TRUE, 'multiple-false' => FALSE][$test_action]; + $form = $this->tableselectFormBuilder($form, $form_state, [ + '#multiple' => $multiple, + '#js_select' => TRUE, + '#ajax' => NULL, + ]); + + // Disable the second row. + $form['tableselect']['#options']['row2']['#disabled'] = TRUE; + + return $form; + } + + /** + * {@inheritdoc} + */ + public function submitForm(array &$form, FormStateInterface $form_state) { + } + +} diff --git a/core/modules/system/tests/src/FunctionalJavascript/Form/ElementsTableSelectTest.php b/core/modules/system/tests/src/FunctionalJavascript/Form/ElementsTableSelectTest.php index b565bfd743..4d39bd0e35 100644 --- a/core/modules/system/tests/src/FunctionalJavascript/Form/ElementsTableSelectTest.php +++ b/core/modules/system/tests/src/FunctionalJavascript/Form/ElementsTableSelectTest.php @@ -55,4 +55,55 @@ public function testAjax() { } } + /** + * Tests table select with disabled rows. + */ + public function testDisabledRows() { + // Asserts that a row number (1 based) is enabled. + $assert_row_enabled = function ($delta) { + $rows = $this->xpath("//table/tbody/tr[$delta]"); + $row = reset($rows); + $this->assertFalse($row->hasClass('disabled')); + $input = $row->find('css', 'input[value="row' . $delta . '"]'); + $this->assertFalse($input->hasAttribute('disabled')); + }; + // Asserts that a row number (1 based) is disabled. + $assert_row_disabled = function ($delta) { + $rows = $this->xpath("//table/tbody/tr[$delta]"); + $row = reset($rows); + $this->assertTrue($row->hasClass('disabled')); + $input = $row->find('css', 'input[value="row' . $delta . '"]'); + $this->assertTrue($input->hasAttribute('disabled')); + $this->assertEquals('disabled', $input->getAttribute('disabled')); + }; + + // Test radios (#multiple == FALSE). + $this->drupalGet('form_test/tableselect/disabled-rows/multiple-false'); + + // Check that only 'row2' is disabled. + $assert_row_enabled(1); + $assert_row_disabled(2); + $assert_row_enabled(3); + + // Test checkboxes (#multiple == TRUE). + $this->drupalGet('form_test/tableselect/disabled-rows/multiple-true'); + + // Check that only 'row2' is disabled. + $assert_row_enabled(1); + $assert_row_disabled(2); + $assert_row_enabled(3); + + // Table select with checkboxes allow selection of all options. + $checkboxes = $this->xpath('//table/thead/tr/th/input'); + $select_all_checkbox = reset($checkboxes); + $select_all_checkbox->check(); + + // Check that the disabled option was not enabled or selected. + $page = $this->getSession()->getPage(); + $page->hasCheckedField('row1'); + $page->hasUncheckedField('row2'); + $assert_row_disabled(2); + $page->hasCheckedField('row3'); + } + } diff --git a/core/tests/Drupal/KernelTests/Core/Element/TableselectTest.php b/core/tests/Drupal/KernelTests/Core/Element/TableselectTest.php deleted file mode 100644 index 5f46d27884..0000000000 --- a/core/tests/Drupal/KernelTests/Core/Element/TableselectTest.php +++ /dev/null @@ -1,94 +0,0 @@ -container->get('form_builder'); - /** @var \Drupal\Core\Render\RendererInterface $renderer */ - $renderer = $this->container->get('renderer'); - - $form = $form_builder->getForm($this); - $this->setRawContent($renderer->renderRoot($form)); - - $disabled = []; - foreach ($this->xpath('//tr[@class="disabled"]//input[@type="checkbox" and @disabled="disabled"]') as $delta => $checkbox) { - $disabled[] = (string) $checkbox['value']; - } - - $this->assertSame(['row2', 'row4'], $disabled); - } - - /** - * {@inheritdoc} - */ - public function buildForm(array $form, FormStateInterface $form_state) { - // Rows 2 and 4 are disabled. - return [ - 'tableselect' => [ - '#type' => 'tableselect', - '#options' => [ - 'row1' => [ - 'col1' => '1.1', - 'col2' => '1.2', - ], - 'row2' => [ - 'col1' => '2.1', - 'col2' => '2.2', - '#disabled' => TRUE, - ], - 'row3' => [ - 'col1' => '3.1', - 'col2' => '3.2', - ], - 'row4' => [ - 'col1' => '4.1', - 'col2' => '4.2', - '#disabled' => TRUE, - ], - ], - '#header' => [ - 'col1' => 'Column 1', - 'col2' => 'Column 2', - ], - ], - ]; - } - - /** - * {@inheritdoc} - */ - public function getFormId() { - return strtolower($this->randomMachineName()); - } - - /** - * {@inheritdoc} - */ - public function validateForm(array &$form, FormStateInterface $form_state) {} - - /** - * {@inheritdoc} - */ - public function submitForm(array &$form, FormStateInterface $form_state) {} - -}