diff --git a/src/View/Helper/FormHelper.php b/src/View/Helper/FormHelper.php index 34a64b51..12ba9a22 100644 --- a/src/View/Helper/FormHelper.php +++ b/src/View/Helper/FormHelper.php @@ -5,6 +5,7 @@ use Cake\Core\Configure\Engine\PhpConfig; use Cake\Utility\Hash; +use Cake\Utility\Inflector; use Cake\View\Helper\FormHelper as Helper; use Cake\View\View; use InvalidArgumentException; @@ -559,6 +560,7 @@ public function control(string $fieldName, array $options = []): string $options = $this->_containerOptions($fieldName, $options); $options = $this->_feedbackStyleOptions($fieldName, $options); $options = $this->_ariaOptions($fieldName, $options); + $options = $this->_placeholderOptions($fieldName, $options); $options = $this->_helpOptions($fieldName, $options); $options = $this->_tooltipOptions($fieldName, $options); @@ -1039,6 +1041,40 @@ protected function _ariaOptions(string $fieldName, array $options): array return $options; } + /** + * Modify options for placeholders. + * + * @param string $fieldName Field name. + * @param array $options Options. See `$options` argument of `control()` method. + * @return array + */ + protected function _placeholderOptions(string $fieldName, array $options): array + { + if ( + !isset($options['placeholder']) && + isset($options['label']['floating']) && + $options['label']['floating'] && + in_array($options['type'], ['text', 'textarea'], true) + ) { + if (isset($options['label']['text'])) { + $options['placeholder'] = $options['label']['text']; + } else { + $text = $fieldName; + if (strpos($text, '.') !== false) { + $fieldElements = explode('.', $text); + $text = array_pop($fieldElements); + } + if (substr($text, -3) === '_id') { + $text = substr($text, 0, -3); + } + + $options['placeholder'] = __(Inflector::humanize(Inflector::underscore($text))); + } + } + + return $options; + } + /** * Modify options for control's help. * diff --git a/tests/TestCase/View/Helper/FormHelper/DefaultAlign/TextControlTest.php b/tests/TestCase/View/Helper/FormHelper/DefaultAlign/TextControlTest.php index 63525c0b..85db4ff5 100644 --- a/tests/TestCase/View/Helper/FormHelper/DefaultAlign/TextControlTest.php +++ b/tests/TestCase/View/Helper/FormHelper/DefaultAlign/TextControlTest.php @@ -39,6 +39,90 @@ public function testDefaultAlignTextControlWithFloatingLabel() 'floating' => true, ], ]); + $expected = [ + 'div' => ['class' => 'mb-3 form-floating form-group text'], + 'input' => [ + 'type' => 'text', + 'name' => 'title', + 'id' => 'title', + 'placeholder' => 'Title', + 'class' => 'form-control', + ], + ['label' => ['for' => 'title']], + 'Title', + '/label', + '/div', + ]; + $this->assertHtml($expected, $result); + } + + public function testDefaultAlignTextControlWithFloatingLabelAndCustomLabelText() + { + unset($this->article['required']['title']); + $this->Form->create($this->article); + + $result = $this->Form->control('title', [ + 'label' => [ + 'floating' => true, + 'text' => 'Custom Label', + ], + ]); + $expected = [ + 'div' => ['class' => 'mb-3 form-floating form-group text'], + 'input' => [ + 'type' => 'text', + 'name' => 'title', + 'id' => 'title', + 'placeholder' => 'Custom Label', + 'class' => 'form-control', + ], + ['label' => ['for' => 'title']], + 'Custom Label', + '/label', + '/div', + ]; + $this->assertHtml($expected, $result); + } + + public function testDefaultAlignTextControlWithFloatingLabelAndCustomPlaceholder() + { + unset($this->article['required']['title']); + $this->Form->create($this->article); + + $result = $this->Form->control('title', [ + 'label' => [ + 'floating' => true, + ], + 'placeholder' => 'Custom Placeholder', + ]); + $expected = [ + 'div' => ['class' => 'mb-3 form-floating form-group text'], + 'input' => [ + 'type' => 'text', + 'name' => 'title', + 'id' => 'title', + 'placeholder' => 'Custom Placeholder', + 'class' => 'form-control', + ], + ['label' => ['for' => 'title']], + 'Title', + '/label', + '/div', + ]; + $this->assertHtml($expected, $result); + } + + public function testDefaultAlignTextControlWithFloatingLabelAndDisabledPlaceholder() + { + unset($this->article['required']['title']); + $this->Form->create($this->article); + + $result = $this->Form->control('title', [ + 'label' => [ + 'floating' => true, + ], + 'placeholder' => false, + ]); $expected = [ 'div' => ['class' => 'mb-3 form-floating form-group text'], 'input' => [ diff --git a/tests/TestCase/View/Helper/FormHelper/HorizontalAlign/TextControlTest.php b/tests/TestCase/View/Helper/FormHelper/HorizontalAlign/TextControlTest.php index 658e9230..f630985a 100644 --- a/tests/TestCase/View/Helper/FormHelper/HorizontalAlign/TextControlTest.php +++ b/tests/TestCase/View/Helper/FormHelper/HorizontalAlign/TextControlTest.php @@ -56,6 +56,117 @@ public function testHorizontalAlignTextControlWithFloatingLabel() 'floating' => true, ], ]); + $expected = [ + 'div' => ['class' => 'mb-3 form-group row text'], + ['div' => ['class' => 'offset-sm-5 col-sm-7 form-floating']], + 'input' => [ + 'type' => 'text', + 'name' => 'title', + 'id' => 'title', + 'placeholder' => 'Title', + 'class' => 'form-control', + ], + 'label' => ['class' => 'ps-4', 'for' => 'title'], + 'Title', + '/label', + '/div', + '/div', + ]; + $this->assertHtml($expected, $result); + } + + public function testHorizontalAlignTextControlWithFloatingLabelAndCustomLabelText() + { + unset($this->article['required']['title']); + $this->Form->create($this->article, [ + 'align' => [ + 'sm' => [ + FormHelper::GRID_COLUMN_ONE => 5, + FormHelper::GRID_COLUMN_TWO => 7, + ], + ], + ]); + + $result = $this->Form->control('title', [ + 'label' => [ + 'floating' => true, + 'text' => 'Custom Label', + ], + ]); + $expected = [ + 'div' => ['class' => 'mb-3 form-group row text'], + ['div' => ['class' => 'offset-sm-5 col-sm-7 form-floating']], + 'input' => [ + 'type' => 'text', + 'name' => 'title', + 'id' => 'title', + 'placeholder' => 'Custom Label', + 'class' => 'form-control', + ], + 'label' => ['class' => 'ps-4', 'for' => 'title'], + 'Custom Label', + '/label', + '/div', + '/div', + ]; + $this->assertHtml($expected, $result); + } + + public function testHorizontalAlignTextControlWithFloatingLabelAndCustomPlaceholder() + { + unset($this->article['required']['title']); + $this->Form->create($this->article, [ + 'align' => [ + 'sm' => [ + FormHelper::GRID_COLUMN_ONE => 5, + FormHelper::GRID_COLUMN_TWO => 7, + ], + ], + ]); + + $result = $this->Form->control('title', [ + 'label' => [ + 'floating' => true, + ], + 'placeholder' => 'Custom Placeholder', + ]); + $expected = [ + 'div' => ['class' => 'mb-3 form-group row text'], + ['div' => ['class' => 'offset-sm-5 col-sm-7 form-floating']], + 'input' => [ + 'type' => 'text', + 'name' => 'title', + 'id' => 'title', + 'placeholder' => 'Custom Placeholder', + 'class' => 'form-control', + ], + 'label' => ['class' => 'ps-4', 'for' => 'title'], + 'Title', + '/label', + '/div', + '/div', + ]; + $this->assertHtml($expected, $result); + } + + public function testHorizontalAlignTextControlWithFloatingLabelAndDisabledPlaceholder() + { + unset($this->article['required']['title']); + $this->Form->create($this->article, [ + 'align' => [ + 'sm' => [ + FormHelper::GRID_COLUMN_ONE => 5, + FormHelper::GRID_COLUMN_TWO => 7, + ], + ], + ]); + + $result = $this->Form->control('title', [ + 'label' => [ + 'floating' => true, + ], + 'placeholder' => false, + ]); $expected = [ 'div' => ['class' => 'mb-3 form-group row text'], ['div' => ['class' => 'offset-sm-5 col-sm-7 form-floating']], diff --git a/tests/TestCase/View/Helper/FormHelper/InlineAlign/TextControlTest.php b/tests/TestCase/View/Helper/FormHelper/InlineAlign/TextControlTest.php index ffda13bb..a5dd73b7 100644 --- a/tests/TestCase/View/Helper/FormHelper/InlineAlign/TextControlTest.php +++ b/tests/TestCase/View/Helper/FormHelper/InlineAlign/TextControlTest.php @@ -45,6 +45,102 @@ public function testInlineAlignTextControlWithFloatingLabel() 'floating' => true, ], ]); + $expected = [ + ['div' => ['class' => 'col-auto']], + 'div' => ['class' => 'form-floating form-group text'], + 'input' => [ + 'type' => 'text', + 'name' => 'title', + 'id' => 'title', + 'placeholder' => 'Title', + 'class' => 'form-control', + ], + 'label' => ['for' => 'title'], + 'Title', + '/label', + '/div', + '/div', + ]; + $this->assertHtml($expected, $result); + } + + public function testInlineAlignTextControlWithFloatingLabelAndCustomLabelText() + { + unset($this->article['required']['title']); + $this->Form->create($this->article, [ + 'align' => 'inline', + ]); + + $result = $this->Form->control('title', [ + 'label' => [ + 'floating' => true, + 'text' => 'Custom Label', + ], + ]); + $expected = [ + ['div' => ['class' => 'col-auto']], + 'div' => ['class' => 'form-floating form-group text'], + 'input' => [ + 'type' => 'text', + 'name' => 'title', + 'id' => 'title', + 'placeholder' => 'Custom Label', + 'class' => 'form-control', + ], + 'label' => ['for' => 'title'], + 'Custom Label', + '/label', + '/div', + '/div', + ]; + $this->assertHtml($expected, $result); + } + + public function testInlineAlignTextControlWithFloatingLabelAndCustomPlaceholder() + { + unset($this->article['required']['title']); + $this->Form->create($this->article, [ + 'align' => 'inline', + ]); + + $result = $this->Form->control('title', [ + 'label' => [ + 'floating' => true, + ], + 'placeholder' => 'Custom Placeholder', + ]); + $expected = [ + ['div' => ['class' => 'col-auto']], + 'div' => ['class' => 'form-floating form-group text'], + 'input' => [ + 'type' => 'text', + 'name' => 'title', + 'id' => 'title', + 'placeholder' => 'Custom Placeholder', + 'class' => 'form-control', + ], + 'label' => ['for' => 'title'], + 'Title', + '/label', + '/div', + '/div', + ]; + $this->assertHtml($expected, $result); + } + + public function testInlineAlignTextControlWithFloatingLabelAndDisabledPlaceholder() + { + unset($this->article['required']['title']); + $this->Form->create($this->article, [ + 'align' => 'inline', + ]); + + $result = $this->Form->control('title', [ + 'label' => [ + 'floating' => true, + ], + 'placeholder' => false, + ]); $expected = [ ['div' => ['class' => 'col-auto']], 'div' => ['class' => 'form-floating form-group text'], diff --git a/tests/TestCase/View/Helper/FormHelperTest.php b/tests/TestCase/View/Helper/FormHelperTest.php index 6d608ffa..143a40b5 100644 --- a/tests/TestCase/View/Helper/FormHelperTest.php +++ b/tests/TestCase/View/Helper/FormHelperTest.php @@ -1616,4 +1616,85 @@ public function testDisableSpacingFromCreateConfigViaControlConfig() $this->Form->end(); } + + public function testFloatingLabelPlaceholderGeneration() + { + $this->article['required']['title'] = false; + $this->Form->create($this->article); + + $result = $this->Form->control('title', [ + 'label' => [ + 'floating' => true, + ], + ]); + $expected = [ + 'div' => ['class' => 'mb-3 form-floating form-group text'], + 'input' => [ + 'type' => 'text', + 'name' => 'title', + 'id' => 'title', + 'placeholder' => 'Title', + 'class' => 'form-control', + ], + ['label' => ['for' => 'title']], + 'Title', + '/label', + '/div', + ]; + $this->assertHtml($expected, $result); + } + + public function testFloatingLabelPlaceholderGenerationForNestedField() + { + $this->Form->create($this->article); + + $result = $this->Form->control('author.name', [ + 'label' => [ + 'floating' => true, + ], + ]); + $expected = [ + 'div' => ['class' => 'mb-3 form-floating form-group text'], + 'input' => [ + 'type' => 'text', + 'name' => 'author[name]', + 'id' => 'author-name', + 'placeholder' => 'Name', + 'class' => 'form-control', + ], + ['label' => ['for' => 'author-name']], + 'Name', + '/label', + '/div', + ]; + $this->assertHtml($expected, $result); + } + + public function testFloatingLabelPlaceholderGenerationForIdField() + { + unset($this->article['required']['author_id']); + $this->Form->create($this->article); + + $result = $this->Form->control('author_id', [ + 'type' => 'text', + 'label' => [ + 'floating' => true, + ], + ]); + $expected = [ + 'div' => ['class' => 'mb-3 form-floating form-group text'], + 'input' => [ + 'type' => 'text', + 'name' => 'author_id', + 'id' => 'author-id', + 'placeholder' => 'Author', + 'class' => 'form-control', + ], + ['label' => ['for' => 'author-id']], + 'Author', + '/label', + '/div', + ]; + $this->assertHtml($expected, $result); + } }