Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix required form radio/checkbox fields #1643

Merged
merged 13 commits into from
Sep 3, 2020
Merged
1 change: 1 addition & 0 deletions .dev/config/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ module.exports = {

'js/coblocks-accordion-polyfill': path.resolve( process.cwd(), 'src/js/coblocks-accordion-polyfill.js' ),
'js/coblocks-accordion-carousel': path.resolve( process.cwd(), 'src/js/coblocks-accordion-carousel.js' ),
'js/coblocks-checkbox-required': path.resolve( process.cwd(), 'src/js/coblocks-checkbox-required.js' ),
'js/coblocks-datepicker': path.resolve( process.cwd(), 'src/js/coblocks-datepicker.js' ),
'js/coblocks-events': path.resolve( process.cwd(), 'src/js/coblocks-events.js' ),
'js/coblocks-fromEntries': path.resolve( process.cwd(), 'src/js/coblocks-fromEntries.js' ),
Expand Down
25 changes: 24 additions & 1 deletion .dev/tests/phpunit/includes/test-coblocks-form.php
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,7 @@ public function test_render_field_radio_empty_options() {
*/
public function test_render_field_radio() {

$this->expectOutputRegex( '/<label class="coblocks-radio-label" for="radio-option-1">Option 1<\/label><input id="radio-option-2" type="radio" name="field-radio\[value\]" value="Option 2" class="radio">/' );
$this->expectOutputRegex( '/<label class="coblocks-radio-label" for="choose-one-option-1">Option 1<\/label><input id="choose-one-option-2" type="radio" name="field-choose-one\[value\]" value="Option 2" class="radio">/' );

echo $this->coblocks_form->render_field_radio(
[
Expand Down Expand Up @@ -508,6 +508,29 @@ public function test_render_field_checkbox_inline() {

}

/**
* Test that the required checkbox field script is loaded when checkboxes
* are set to required
*/
public function test_required_checkbox_script() {

echo $this->coblocks_form->render_field_checkbox(
[
'options' => [
'option-1' => 'Option 1',
'option-2' => 'Option 2',
],
'required' => true
],
''
);

global $wp_scripts;

$this->assertArrayHasKey( 'coblocks-datepicker', $wp_scripts->registered );

}

/**
* Test the website field markup is as expected
*/
Expand Down
2 changes: 2 additions & 0 deletions .dev/tests/phpunit/test-class-coblocks.php
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@ public function test_final_build_assets_exist() {
'js' => [
'dist/coblocks.js',
'dist/js/coblocks-accordion-polyfill.js',
'dist/js/coblocks-checkbox-required.js',
'dist/js/coblocks-datepicker.js',
'dist/js/coblocks-fromEntries.js',
'dist/js/coblocks-google-maps.js',
Expand All @@ -195,6 +196,7 @@ public function test_final_build_assets_exist() {
'dist/js/vendors/flickity.js',
'dist/js/vendors/slick.js',
'src/js/coblocks-accordion-polyfill.js',
'src/js/coblocks-checkbox-required.js',
'src/js/coblocks-datepicker.js',
'src/js/coblocks-fromEntries.js',
'src/js/coblocks-google-maps.js',
Expand Down
43 changes: 36 additions & 7 deletions includes/class-coblocks-form.php
Original file line number Diff line number Diff line change
Expand Up @@ -475,9 +475,10 @@ public function render_field_radio( $atts ) {

$the_options = array_filter( $atts['options'] );

$label = isset( $atts['label'] ) ? $atts['label'] : __( 'Choose one', 'coblocks' );
$label_desc = sanitize_title( $label ) !== 'choose-one' ? sanitize_title( $label ) : 'radio';
$label_slug = $radio_count > 1 ? sanitize_title( $label_desc . '-' . $radio_count ) : sanitize_title( $label_desc );
$label = isset( $atts['label'] ) ? $atts['label'] : __( 'Choose one', 'coblocks' );
$label_desc = sanitize_title( $label ) !== 'choose-one' ? sanitize_title( $label ) : 'choose-one';
$label_slug = $radio_count > 1 ? sanitize_title( $label_desc . '-' . $radio_count ) : sanitize_title( $label_desc );
$required_attr = ( isset( $atts['required'] ) && $atts['required'] ) ? ' required' : '';

ob_start();

Expand All @@ -491,14 +492,15 @@ public function render_field_radio( $atts ) {

}

foreach ( $the_options as $value ) {
foreach ( $the_options as $key => $value ) {

printf(
'<input id="%1$s" type="radio" name="field-%2$s[value]" value="%3$s" class="radio">
<label class="coblocks-radio-label" for="%1$s">%4$s</label>',
'<input id="%1$s" type="radio" name="field-%2$s[value]" value="%3$s" class="radio"%4$s>
<label class="coblocks-radio-label" for="%1$s">%5$s</label>',
esc_attr( $label_slug . '-' . sanitize_title( $value ) ),
esc_attr( $label_slug ),
esc_attr( $value ),
$key === 0 ? esc_attr( $required_attr ) : '',
esc_html( $value )
);

Expand Down Expand Up @@ -588,10 +590,37 @@ public function render_field_checkbox( $atts ) {

$label = isset( $atts['label'] ) ? $atts['label'] : __( 'Select', 'coblocks' );
$label_slug = $checkbox_count > 1 ? sanitize_title( $label . '-' . $checkbox_count ) : sanitize_title( $label );
$required = ( isset( $atts['required'] ) && $atts['required'] );

if ( $checkbox_count === 1 && $required ) {

wp_enqueue_script(
'coblocks-checkbox-required',
CoBlocks()->asset_source( 'js' ) . 'coblocks-checkbox-required.js',
array( 'jquery' ),
COBLOCKS_VERSION,
true
);

}

ob_start();

print( '<div class="coblocks-field">' );
printf(
'<div class="coblocks-field checkbox%1$s">
%2$s',
$required ? esc_attr( ' required' ) : '',
$required ? sprintf(
'<div class="required-error hidden">%s</div>',
/**
* Filter the checkbox required text that displays when no checkbox is
* selected when the form is submitted.
*
* @param string $error_text Error text displayed to the user.
*/
(string) apply_filters( 'coblocks_form_checkbox_required_text', esc_html__( 'Please select at least one checkbox.', 'coblocks' ) )
) : ''
);

$this->render_field_label( $atts, $label, $checkbox_count );

Expand Down
4 changes: 4 additions & 0 deletions src/blocks/form/styles/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@
margin: 1.25rem 0 3px 0;
}

.required-error.hidden {
display: none;
}

.coblocks-field,
select {
margin: 0 0 1.25rem 0;
Expand Down
30 changes: 30 additions & 0 deletions src/js/coblocks-checkbox-required.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import jQuery from 'jquery';

jQuery( function( $ ) {
/**
* Prevent the form from being submitted when no checkbox is selected, when one is required
*/
$( 'body' ).on( 'click', '.coblocks-form__submit button[type="submit"]', function( e ) {
if ( ! $( '.coblocks-field.checkbox.required' ).length ) {
return;
}

var submittedForm = $( this ).closest( 'form' );
var selectedCheckboxes = submittedForm.find( '.coblocks-field.checkbox.required input[type="checkbox"]:checked' ).length;

if ( selectedCheckboxes === 0 ) {
submittedForm.find( '.required-error' ).show();
e.preventDefault();
return;
}

submittedForm.find( '.required-error' ).hide();
} );

/**
* Toggle the `.required-error` visibility when a checkbox is selected
*/
$( 'body' ).on( 'change', '.coblocks-field.checkbox.required input[type="checkbox"]', function() {
$( this ).closest( '.coblocks-field.checkbox.required' ).find( '.required-error' ).hide();
} );
} );