| @@ -20,8 +20,24 @@ | ||
| 20 | 20 | * @since 0.0.1 |
| 21 | 21 | */ |
| 22 | 22 | class Textarea_Markup extends Base { |
| 23 | 23 | /** |
| 24 | + * Minimum length of text required for the textarea. | |
| 25 | + * | |
| 26 | + * @var string | |
| 27 | + * @since 2.8.2 | |
| 28 | + */ | |
| 29 | + protected $min_length; | |
| 30 | + | |
| 31 | + /** | |
| 32 | + * HTML attribute string for the minimum length. | |
| 33 | + * | |
| 34 | + * @var string | |
| 35 | + * @since 2.8.2 | |
| 36 | + */ | |
| 37 | + protected $min_length_attr; | |
| 38 | + | |
| 39 | + /** | |
| 24 | 40 | * Maximum length of text allowed for the textarea. |
| 25 | 41 | * |
| 26 | 42 | * @var string |
| 27 | 43 | * @since 0.0.2 |
| @@ -93,13 +109,26 @@ | ||
| 93 | 109 | public function __construct( $attributes ) { |
| 94 | 110 | $this->set_properties( $attributes ); |
| 95 | 111 | $this->set_input_label( __( 'Textarea', 'sureforms' ) ); |
| 96 | 112 | $this->set_error_msg( $attributes, 'srfm_textarea_block_required_text' ); |
| 97 | - $this->slug = 'textarea'; | |
| 113 | + $this->slug = 'textarea'; | |
| 114 | + $this->is_richtext = $attributes['isRichText'] ?? false; | |
| 115 | + // Min-length only applies to plain textareas; the rich-text submission contains HTML markup. | |
| 116 | + $this->min_length = $this->is_richtext ? '' : ( $attributes['minLength'] ?? '' ); | |
| 98 | 117 | $this->max_length = $attributes['maxLength'] ?? ''; |
| 99 | - $this->rows = $attributes['rows'] ?? ''; | |
| 100 | - $this->read_only = ! empty( trim( $this->default ) ) && $attributes['readOnly']; | |
| 118 | + // Misconfiguration guard — if min exceeds max, drop min so the form stays submittable. | |
| 119 | + // The editor already warns the form-builder when this happens. | |
| 120 | + if ( | |
| 121 | + '' !== $this->min_length && | |
| 122 | + '' !== $this->max_length && | |
| 123 | + (int) $this->min_length > (int) $this->max_length | |
| 124 | + ) { | |
| 125 | + $this->min_length = ''; | |
| 126 | + } | |
| 127 | + $this->rows = $attributes['rows'] ?? ''; | |
| 128 | + $this->read_only = ! empty( trim( $this->default ) ) && $attributes['readOnly']; | |
| 101 | 129 | // html attributes. |
| 130 | + $this->min_length_attr = $this->min_length ? ' data-minlength="' . esc_attr( $this->min_length ) . '" ' : ''; | |
| 102 | 131 | $this->max_length_attr = $this->max_length ? ' maxLength="' . esc_attr( $this->max_length ) . '" ' : ''; |
| 103 | 132 | $this->rows_attr = $this->rows ? ' rows="' . esc_attr( $this->rows ) . '" ' : ''; |
| 104 | 133 | $this->max_length_html = '' !== $this->max_length ? '0/' . $this->max_length : ''; |
| 105 | 134 | $this->random_id = wp_rand( 1000, 9999 ); |
| @@ -104,12 +133,11 @@ | ||
| 104 | 133 | $this->max_length_html = '' !== $this->max_length ? '0/' . $this->max_length : ''; |
| 105 | 134 | $this->random_id = wp_rand( 1000, 9999 ); |
| 106 | 135 | $this->set_unique_slug(); |
| 107 | 136 | $this->set_field_name( $this->unique_slug ); |
| 108 | - $this->set_markup_properties( $this->input_label . '-' . $this->random_id ); | |
| 137 | + $this->set_markup_properties( $this->input_label . '-' . $this->random_id, ! empty( $this->min_length ) ); | |
| 109 | 138 | $this->set_aria_described_by(); |
| 110 | 139 | $this->set_label_as_placeholder( $this->input_label ); |
| 111 | - $this->is_richtext = $attributes['isRichText'] ?? false; | |
| 112 | 140 | } |
| 113 | 141 | |
| 114 | 142 | /** |
| 115 | 143 | * Render the sureforms textarea classic styling |
| @@ -129,10 +157,12 @@ | ||
| 129 | 157 | $this->is_richtext ? 'srfm-richtext' : '', |
| 130 | 158 | $this->read_only ? 'srfm-read-only' : '', |
| 131 | 159 | ]; |
| 132 | 160 | |
| 133 | - $classes = Helper::join_strings( $classes ); | |
| 134 | - $random_id = $this->unique_slug . '-' . $this->random_id; | |
| 161 | + $classes = Helper::join_strings( $classes ); | |
| 162 | + $random_id = $this->unique_slug . '-' . $this->random_id; | |
| 163 | + $has_counter = ! $this->is_richtext && ( '' !== $this->min_length || '' !== $this->max_length ); | |
| 164 | + $display_limit = $has_counter ? ( '' !== $this->max_length ? $this->max_length : $this->min_length ) : ''; | |
| 135 | 165 | |
| 136 | 166 | ob_start(); ?> |
| 137 | 167 | <div data-block-id="<?php echo esc_attr( $this->block_id ); ?>" class="<?php echo esc_attr( $classes ); ?>"> |
| 138 | 168 | <?php echo wp_kses_post( $this->label_markup ); ?> |
| @@ -142,9 +172,9 @@ | ||
| 142 | 172 | class="srfm-input-common srfm-input-<?php echo esc_attr( $this->slug ); ?>" |
| 143 | 173 | name="<?php echo esc_attr( $this->field_name ); ?>" |
| 144 | 174 | id="<?php echo esc_attr( $random_id ); ?>" |
| 145 | 175 | <?php echo ! empty( $this->aria_described_by ) ? "aria-describedby='" . esc_attr( trim( $this->aria_described_by ) ) . "'" : ''; ?> |
| 146 | - data-required="<?php echo esc_attr( $this->data_require_attr ); ?>" aria-required="<?php echo esc_attr( $this->data_require_attr ); ?>" <?php echo wp_kses_post( $this->max_length_attr . '' . $this->rows_attr ); ?> <?php echo wp_kses_post( $this->placeholder_attr ); ?> | |
| 176 | + data-required="<?php echo esc_attr( $this->data_require_attr ); ?>" aria-required="<?php echo esc_attr( $this->data_require_attr ); ?>" <?php echo wp_kses_post( $this->min_length_attr . $this->max_length_attr . $this->rows_attr ); ?> <?php echo wp_kses_post( $this->placeholder_attr ); ?> | |
| 147 | 177 | <?php echo $this->is_richtext ? 'data-is-richtext="true"' : ''; ?> |
| 148 | 178 | <?php echo $this->read_only ? 'readonly' : ''; ?> |
| 149 | 179 | ><?php echo esc_html( $this->default ); ?></textarea> |
| 150 | 180 | <?php if ( $this->is_richtext ) { ?> |
| @@ -154,8 +184,19 @@ | ||
| 154 | 184 | <?php } ?> |
| 155 | 185 | </div> |
| 156 | 186 | <div class="srfm-error-wrap"> |
| 157 | 187 | <?php echo wp_kses_post( $this->error_msg_markup ); ?> |
| 188 | + <?php if ( $has_counter ) { ?> | |
| 189 | + <div class="srfm-char-counter-wrap"> | |
| 190 | + <span class="srfm-char-counter" | |
| 191 | + data-counter-limit="<?php echo esc_attr( $display_limit ); ?>" | |
| 192 | + <?php if ( '' !== $this->min_length ) { ?> | |
| 193 | + data-counter-min="<?php echo esc_attr( $this->min_length ); ?>" | |
| 194 | + <?php } ?> | |
| 195 | + aria-live="polite" | |
| 196 | + >0/<?php echo esc_html( $display_limit ); ?></span> | |
| 197 | + </div> | |
| 198 | + <?php } ?> | |
| 158 | 199 | </div> |
| 159 | 200 | </div> |
| 160 | 201 | |
| 161 | 202 | <?php |