diff --git a/docs/RELEASE-NOTES.md b/docs/RELEASE-NOTES.md index e4398bbe..7b8e2b0a 100644 --- a/docs/RELEASE-NOTES.md +++ b/docs/RELEASE-NOTES.md @@ -63,7 +63,7 @@ Tidy YAML files # Run single tests cd /var/www/sites/d8_webform - php core/scripts/run-tests.sh --verbose --class "Drupal\webform\Tests\WebformSubmissionStorageTest" + php core/scripts/run-tests.sh --url http://localhost/wf --verbose --class "Drupal\Tests\webform\Functional\WebformListBuilderTest" [PHPUnit](https://www.drupal.org/node/2116263) @@ -83,6 +83,7 @@ References # Execute individual PHPUnit tests. export SIMPLETEST_DB=mysql://drupal_d8_webform:drupal.@dm1n@localhost/drupal_d8_webform; + export SIMPLETEST_BASE_URL='http://localhost/wf'; # Functional test. php ../vendor/phpunit/phpunit/phpunit --printer="\Drupal\Tests\Listeners\HtmlOutputPrinter" ../modules/sandbox/webform/tests/src/Functional/WebformExampleFunctionalTest.php diff --git a/includes/webform.theme.inc b/includes/webform.theme.inc index e55fc7a0..1ba24d29 100644 --- a/includes/webform.theme.inc +++ b/includes/webform.theme.inc @@ -305,6 +305,13 @@ function webform_preprocess_fieldset(&$variables) { if (isset($variables['legend']['title'])) { _webform_preprocess_help_title($variables['legend']['title'], $element); } + + // Add .js-webform-form-composite class to be used #states API. + // @see js/webform.states.js + if (isset($element['#type']) && in_array($element['#type'], ['checkboxes', 'radios'])) { + $variables['attributes']['class'][] = 'js-webform-type-' . $element['#type']; + $variables['attributes']['class'][] = 'webform-type-' . $element['#type']; + } } /** diff --git a/js/webform.element.radios.js b/js/webform.element.radios.js deleted file mode 100644 index e6fc4964..00000000 --- a/js/webform.element.radios.js +++ /dev/null @@ -1,60 +0,0 @@ -/** - * @file - * JavaScript behaviors for radio buttons. - * - * Fix #states and #required for radios buttons. - * - * @see Issue #2856795: If radio buttons are required but not filled form is nevertheless submitted. - * @see Issue #2856315: Conditional Logic - Requiring Radios in a Fieldset. - * @see Issue #2731991: Setting required on radios marks all options required. - * @see css/webform.form.css - * @see /core/misc/states.js - */ - -(function ($, Drupal) { - - 'use strict'; - - /** - * Attach handler to add .js-webform-radios-fieldset to radios wrapper fieldset. - * - * @type {Drupal~behavior} - */ - Drupal.behaviors.webformRadios = { - attach: function (context) { - $('.js-webform-radios', context).closest('fieldset.form-composite').addClass('js-webform-radios-fieldset'); - } - }; - - // Make absolutely sure the below event handlers are triggered after - // the /core/misc/states.js event handlers by attaching them after DOM load. - $(function () { - Drupal.behaviors.webformRadios.attach($(document)); - - function setRequired($target, required) { - if (!$target.hasClass('js-webform-radios-fieldset') && !$target.hasClass('js-webform-radios-other')) { - return; - } - - if (required) { - $target.find('input[type="radio"]').attr({'required': 'required', 'aria-required': 'aria-required'}); - $target.find('legend span').addClass('js-form-required form-required'); - } - else { - $target.find('input[type="radio"]').removeAttr('required aria-required'); - $target.find('legend span').removeClass('js-form-required form-required'); - } - } - - $('.js-webform-radios-fieldset[required="required"], .js-form-type-webform-radios-other[required="required"]').each(function() { - setRequired($(this), true); - }); - - $(document).on('state:required', function (e) { - if (e.trigger) { - setRequired($(e.target), e.value); - } - }); - }); - -})(jQuery, Drupal); diff --git a/js/webform.states.js b/js/webform.states.js index eaa339a3..4d90596f 100644 --- a/js/webform.states.js +++ b/js/webform.states.js @@ -50,16 +50,56 @@ var $document = $(document); - // Issue #2860529: Conditional required File upload field don't work. $document.on('state:required', function (e) { if (e.trigger) { + var $target = $(e.target); + // Fix #required file upload. + // @see Issue #2860529: Conditional required File upload field don't work. if (e.value) { - $(e.target).find('input[type="file"]').attr({'required': 'required', 'aria-required': 'aria-required'}); + $target.find('input[type="file"]').attr({'required': 'required', 'aria-required': 'aria-required'}); } else { - $(e.target).find('input[type="file"]').removeAttr('required aria-required'); + $target.find('input[type="file"]').removeAttr('required aria-required'); + } + + // Fix #required for radios buttons. + // @see Issue #2856795: If radio buttons are required but not filled form is nevertheless submitted. + if ($target.is('.js-webform-type-radios, .js-form-type-webform-radios-other')) { + if (e.value) { + $target.find('input[type="radio"]').attr({'required': 'required', 'aria-required': 'aria-required'}); + } + else { + $target.find('input[type="radio"]').removeAttr('required aria-required'); + } + } + + // Fix #required for checkboxes buttons. + // @see Issue #2938414: Checkboxes don't support #states required + if ($target.is('.js-webform-type-checkboxes, .js-form-type-webform-checkboxes-other')) { + if (e.value) { + $target.find('input[type="checkbox"]').attr({'required': 'required', 'aria-required': 'aria-required'}); + $target.find('input[type="checkbox"]').bind('click', checkboxRequiredhandler); + } + else { + $target.find('input[type="checkbox"]').removeAttr('required aria-required'); + $target.find('input[type="checkbox"]').unbind('click', checkboxRequiredhandler); + } + } + + // Fix required label for checkboxes and radios. + // @see Issue #2938414: Checkboxes don't support #states required + // @see Issue #2731991: Setting required on radios marks all options required. + // @see Issue #2856315: Conditional Logic - Requiring Radios in a Fieldset. + if ($target.is('.js-webform-type-radios, .js-webform-type-checkboxes')) { + if (e.value) { + $target.find('legend span').addClass('js-form-required form-required'); + } + else { + $target.find('legend span').removeClass('js-form-required form-required'); + } } } + }); $document.on('state:readonly', function (e) { @@ -102,6 +142,21 @@ } }); + /** + * Trigger custom HTML5 multiple checkboxes validation. + * + * @see https://stackoverflow.com/a/37825072/145846 + */ + function checkboxRequiredhandler() { + var $checkboxes = $(this).closest('.js-webform-type-checkboxes, .js-form-type-webform-checkboxes-other').find('input[type="checkbox"]'); + if ($checkboxes.is(':checked')) { + $checkboxes.removeAttr('required aria-required'); + } + else { + $checkboxes.attr({'required': 'required', 'aria-required': 'aria-required'}); + } + } + /** * Trigger an input's event handlers. * diff --git a/src/Plugin/WebformElement/Radios.php b/src/Plugin/WebformElement/Radios.php index a44a5766..c4f52bb8 100644 --- a/src/Plugin/WebformElement/Radios.php +++ b/src/Plugin/WebformElement/Radios.php @@ -30,16 +30,4 @@ class Radios extends OptionsBase { ] + parent::getDefaultProperties(); } - /** - * {@inheritdoc} - */ - public function prepare(array &$element, WebformSubmissionInterface $webform_submission = NULL) { - parent::prepare($element, $webform_submission); - - // Issue #2856795: If radio buttons are required but not filled form is - // nevertheless submitted. - // Issue #2856315: Conditional Logic - Requiring Radios in a Fieldset. - $element['#attached']['library'][] = 'webform/webform.element.radios'; - } - } diff --git a/tests/modules/webform_test/config/install/webform.webform.test_element_checkboxes.yml b/tests/modules/webform_test/config/install/webform.webform.test_element_checkboxes.yml index 6f36efc5..4e6baa00 100644 --- a/tests/modules/webform_test/config/install/webform.webform.test_element_checkboxes.yml +++ b/tests/modules/webform_test/config/install/webform.webform.test_element_checkboxes.yml @@ -49,6 +49,30 @@ elements: | '#title_display': inline '#options': yes_no '#options_display': side_by_side + checkboxes_required_conditional_example: + '#type': details + '#title': 'Checkboxes required conditional' + '#open': true + checkboxes_required_conditional_trigger: + '#type': checkbox + '#title': 'Require the below checkboxes' + '#default_value': true + checkboxes_required_conditions: + '#type': checkboxes + '#title': checkboxes_required + '#options': yes_no + '#states': + required: + ':input[name="checkboxes_required_conditional_trigger"]': + checked: true + checkboxes_other_required_conditions: + '#type': webform_checkboxes_other + '#title': checkboxes_other_required + '#options': yes_no + '#states': + required: + ':input[name="checkboxes_required_conditional_trigger"]': + checked: true css: '' javascript: '' settings: diff --git a/tests/modules/webform_test/config/install/webform.webform.test_element_radios.yml b/tests/modules/webform_test/config/install/webform.webform.test_element_radios.yml index 89b68898..8eb3074a 100644 --- a/tests/modules/webform_test/config/install/webform.webform.test_element_radios.yml +++ b/tests/modules/webform_test/config/install/webform.webform.test_element_radios.yml @@ -28,7 +28,7 @@ elements: | '#open': true radios_required_conditional_trigger: '#type': checkbox - '#title': 'Required the below radio button' + '#title': 'Require the below radio button' '#default_value': true radios_required_conditions: '#type': radios @@ -38,6 +38,14 @@ elements: | required: ':input[name="radios_required_conditional_trigger"]': checked: true + radios_other_required_conditions: + '#type': webform_radios_other + '#title': radios_other_required + '#options': yes_no + '#states': + required: + ':input[name="radios_required_conditional_trigger"]': + checked: true buttons_required_conditional_example: '#type': details '#title': 'Buttons required conditional' diff --git a/webform.libraries.yml b/webform.libraries.yml index 67da03e3..b7f53163 100644 --- a/webform.libraries.yml +++ b/webform.libraries.yml @@ -653,15 +653,6 @@ webform.element.other: - core/jquery - core/jquery.once -webform.element.radios: - version: VERSION - js: - js/webform.element.radios.js: {} - dependencies: - - core/drupal - - core/jquery - - core/jquery.once - webform.element.range: version: VERSION css: