From 6fb16bc30f2efb63e9033d89d7d7a60d663480f8 Mon Sep 17 00:00:00 2001 From: Anton Date: Mon, 27 Dec 2021 21:44:48 +0300 Subject: [PATCH] Fix #19098: Add `yii\helper\BaseHtml::$normalizeClassAttribute` to fix duplicate classes --- framework/CHANGELOG.md | 1 + framework/helpers/BaseHtml.php | 18 +++++++++++++++--- tests/framework/helpers/HtmlTest.php | 4 +++- 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/framework/CHANGELOG.md b/framework/CHANGELOG.md index 722a7e90e23..626950422eb 100644 --- a/framework/CHANGELOG.md +++ b/framework/CHANGELOG.md @@ -36,6 +36,7 @@ Yii Framework 2 Change Log - Bug #19031: Fix displaying console help for parameters with declared types (WinterSilence) - Bug #19030: Add DI container usage to `yii\base\Widget::end()` (papppeter) - Bug #19096: Fix `Request::getIsConsoleRequest()` may return erroneously when testing a Web application in Codeception (WinterSilence) +- Enh #19098: Add `yii\helper\BaseHtml::$normalizeClassAttribute` to fix duplicate classes (WinterSilence) - Enh #19108: Optimize `Component::hasEventHandlers()` and `Component::trigger()` (WinterSilence) diff --git a/framework/helpers/BaseHtml.php b/framework/helpers/BaseHtml.php index 5d89314971f..156e34fe97e 100644 --- a/framework/helpers/BaseHtml.php +++ b/framework/helpers/BaseHtml.php @@ -94,8 +94,15 @@ class BaseHtml * @since 2.0.3 */ public static $dataAttributes = ['aria', 'data', 'data-ng', 'ng']; - - + /** + * @var bool whether to removes duplicate class names in tag attribute `class` + * @see mergeCssClasses() + * @see renderTagAttributes() + * @since 2.0.44 + */ + public static $normalizeClassAttribute = false; + + /** * Encodes special characters into HTML entities. * The [[\yii\base\Application::charset|application charset]] will be used for encoding. @@ -1981,6 +1988,11 @@ public static function renderTagAttributes($attributes) if (empty($value)) { continue; } + if (static::$normalizeClassAttribute === true && count($value) > 1) { + // removes duplicate classes + $value = explode(' ', implode(' ', $value)); + $value = array_unique($value); + } $html .= " $name=\"" . static::encode(implode(' ', $value)) . '"'; } elseif ($name === 'style') { if (empty($value)) { @@ -2047,7 +2059,7 @@ private static function mergeCssClasses(array $existingClasses, array $additiona } } - return array_unique($existingClasses); + return static::$normalizeClassAttribute ? array_unique($existingClasses) : $existingClasses; } /** diff --git a/tests/framework/helpers/HtmlTest.php b/tests/framework/helpers/HtmlTest.php index 5b2c9de0090..3dfd9f83345 100644 --- a/tests/framework/helpers/HtmlTest.php +++ b/tests/framework/helpers/HtmlTest.php @@ -1082,12 +1082,14 @@ public function testRenderOptions() $this->assertEqualsWithoutLE($expected, Html::renderSelectOptions(['1.10'], $data, $attributes)); } - public function testRenderAttributes() + public function testRenderTagAttributes() { $this->assertEquals('', Html::renderTagAttributes([])); $this->assertEquals(' name="test" value="1<>"', Html::renderTagAttributes(['name' => 'test', 'empty' => null, 'value' => '1<>'])); $this->assertEquals(' checked disabled', Html::renderTagAttributes(['checked' => true, 'disabled' => true, 'hidden' => false])); $this->assertEquals(' class="first second"', Html::renderTagAttributes(['class' => ['first', 'second']])); + Html::$normalizeClassAttribute = true; + $this->assertEquals(' class="first second"', Html::renderTagAttributes(['class' => ['first second', 'first']])); $this->assertEquals('', Html::renderTagAttributes(['class' => []])); $this->assertEquals(' style="width: 100px; height: 200px;"', Html::renderTagAttributes(['style' => ['width' => '100px', 'height' => '200px']])); $this->assertEquals('', Html::renderTagAttributes(['style' => []]));