[BUGFIX] Remove attribute 'selected' if its value is false 14/57814/4
authorGeorg Ringer <georg.ringer@gmail.com>
Thu, 22 Mar 2018 13:34:13 +0000 (14:34 +0100)
committerAnja Leichsenring <aleichsenring@ab-softlab.de>
Tue, 14 Aug 2018 17:18:00 +0000 (19:18 +0200)
If the selected attribute is set to false (or zero), the
attribute itself must not be shown as even if it is empty it would be
meant to set the option to selected.

Resolves: #83229
Releases: master, 8.7
Change-Id: Ic2c87bf7b603eac288a4ce9d38a4ce75c5817f3d
Reviewed-on: https://review.typo3.org/57814
Tested-by: TYPO3com <no-reply@typo3.com>
Tested-by: Mona Muzaffar <mona.muzaffar@gmx.de>
Reviewed-by: Christian Kuhn <lolli@schwarzbu.ch>
Reviewed-by: Anja Leichsenring <aleichsenring@ab-softlab.de>
Tested-by: Anja Leichsenring <aleichsenring@ab-softlab.de>
typo3/sysext/fluid/Classes/ViewHelpers/Form/Select/OptionViewHelper.php
typo3/sysext/fluid/Tests/Unit/ViewHelpers/Form/Select/OptionViewHelperTest.php [new file with mode: 0644]

index 981fd32..715fe5c 100644 (file)
@@ -33,10 +33,10 @@ class OptionViewHelper extends \TYPO3\CMS\Fluid\ViewHelpers\Form\AbstractFormFie
     public function initializeArguments()
     {
         $this->registerUniversalTagAttributes();
+        $this->registerArgument('selected', 'boolean', 'If set, overrides automatic detection of selected state for this option.');
         $this->registerArgument('additionalAttributes', 'array', 'Additional tag attributes. They will be added directly to the resulting HTML tag.');
         $this->registerArgument('data', 'array', 'Additional data-* attributes. They will each be added with a "data-" prefix.');
         $this->registerTagAttribute('value', 'mixed', 'Value to be inserted in HTML tag - must be convertible to string!');
-        $this->registerTagAttribute('selected', 'boolean', 'If filled, overrides automatic detection of selected state for this option');
     }
 
     /**
@@ -44,14 +44,8 @@ class OptionViewHelper extends \TYPO3\CMS\Fluid\ViewHelpers\Form\AbstractFormFie
      */
     public function render()
     {
-        if ($this->arguments['selected'] === null) {
-            // user did not provide a tag attribute value. Determine if we need to
-            // set this attribute - or remove it entirely to prevent an empty attribute.
-            if ($this->isValueSelected($this->arguments['value'])) {
-                $this->tag->addAttribute('selected', 'selected');
-            } else {
-                $this->tag->removeAttribute('selected');
-            }
+        if ($this->arguments['selected'] ?? $this->isValueSelected($this->arguments['value'])) {
+            $this->tag->addAttribute('selected', 'selected');
         }
         $childContent = $this->renderChildren();
         $this->tag->setContent($childContent);
diff --git a/typo3/sysext/fluid/Tests/Unit/ViewHelpers/Form/Select/OptionViewHelperTest.php b/typo3/sysext/fluid/Tests/Unit/ViewHelpers/Form/Select/OptionViewHelperTest.php
new file mode 100644 (file)
index 0000000..65e0d38
--- /dev/null
@@ -0,0 +1,137 @@
+<?php
+declare(strict_types = 1);
+
+namespace TYPO3\CMS\Fluid\Tests\Unit\ViewHelpers\Form\Select;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Fluid\ViewHelpers\Form\Select\OptionViewHelper;
+use TYPO3\TestingFramework\Core\AccessibleObjectInterface;
+use TYPO3\TestingFramework\Fluid\Unit\ViewHelpers\ViewHelperBaseTestcase;
+use TYPO3Fluid\Fluid\Core\ViewHelper\TagBuilder;
+
+/**
+ * Test for the "Option" Form view helper
+ */
+class OptionViewHelperTest extends ViewHelperBaseTestcase
+{
+    /**
+     * @var OptionViewHelper|\PHPUnit_Framework_MockObject_MockObject|AccessibleObjectInterface
+     */
+    protected $viewHelper;
+
+    protected function setUp()
+    {
+        parent::setUp();
+        $this->viewHelper = $this->getAccessibleMock(
+            OptionViewHelper::class,
+            ['isValueSelected', 'registerFieldNameForFormTokenGeneration', 'renderChildren']
+        );
+        $this->arguments['selected'] = null;
+        $this->arguments['value'] = null;
+        $this->tagBuilder = new TagBuilder();
+        $this->viewHelper->_set('tag', $this->tagBuilder);
+        $this->injectDependenciesIntoViewHelper($this->viewHelper);
+    }
+
+    /**
+     * @test
+     */
+    public function optionTagNameIsSet()
+    {
+        $tagBuilder = $this->createMock(TagBuilder::class);
+        $tagBuilder->expects($this->once())->method('setTagName')->with('option');
+
+        $this->viewHelper->_set('tag', $tagBuilder);
+        $this->viewHelper->initializeArgumentsAndRender();
+    }
+
+    /**
+     * @test
+     */
+    public function childrenContentIsUsedAsValueAndLabelByDefault()
+    {
+        $this->viewHelper->expects($this->once())->method('renderChildren')->will($this->returnValue('Option Label'));
+        $expected = '<option value="Option Label">Option Label</option>';
+        $this->assertEquals($expected, $this->viewHelper->initializeArgumentsAndRender());
+    }
+
+    /**
+     * @test
+     */
+    public function valueCanBeOverwrittenByArgument()
+    {
+        $this->arguments['value'] = 'value';
+        $this->viewHelper->setArguments($this->arguments);
+        $this->viewHelper->expects($this->once())->method('renderChildren')->will($this->returnValue('Option Label'));
+        $expected = '<option value="value">Option Label</option>';
+        $this->assertEquals($expected, $this->viewHelper->initializeArgumentsAndRender());
+    }
+
+    /**
+     * @test
+     */
+    public function selectedIsAddedToSelectedOptionForNoSelectionOverride()
+    {
+        $this->arguments['selected'] = null;
+        $this->viewHelper->setArguments($this->arguments);
+
+        $this->viewHelper->expects($this->once())->method('isValueSelected')->will($this->returnValue(true));
+        $this->viewHelper->expects($this->once())->method('renderChildren')->will($this->returnValue('Option Label'));
+
+        $expected = '<option selected="selected" value="Option Label">Option Label</option>';
+        $this->assertEquals($expected, $this->viewHelper->initializeArgumentsAndRender());
+    }
+
+    /**
+     * @test
+     */
+    public function selectedIsNotAddedToUnselectedOptionForNoSelectionOverride()
+    {
+        $this->arguments['selected'] = null;
+        $this->viewHelper->setArguments($this->arguments);
+
+        $this->viewHelper->expects($this->once())->method('isValueSelected')->will($this->returnValue(false));
+        $this->viewHelper->expects($this->once())->method('renderChildren')->will($this->returnValue('Option Label'));
+
+        $expected = '<option value="Option Label">Option Label</option>';
+        $this->assertEquals($expected, $this->viewHelper->initializeArgumentsAndRender());
+    }
+
+    /**
+     * @test
+     */
+    public function selectedIsNotAddedToOptionForExplicitOverride()
+    {
+        $this->arguments['selected'] = false;
+        $this->viewHelper->setArguments($this->arguments);
+        $this->viewHelper->expects($this->once())->method('renderChildren')->will($this->returnValue('Option Label'));
+
+        $expected = '<option value="Option Label">Option Label</option>';
+        $this->assertEquals($expected, $this->viewHelper->initializeArgumentsAndRender());
+    }
+
+    /**
+     * @test
+     */
+    public function selectedIsAddedToOptionForExplicitOverride()
+    {
+        $this->arguments['selected'] = true;
+        $this->viewHelper->setArguments($this->arguments);
+        $this->viewHelper->expects($this->once())->method('renderChildren')->will($this->returnValue('Option Label'));
+
+        $expected = '<option selected="selected" value="Option Label">Option Label</option>';
+        $this->assertEquals($expected, $this->viewHelper->initializeArgumentsAndRender());
+    }
+}