feature#9171 [Form] Rewrite boolean attributes to match HTML spec (bschussek)
This PR was merged into the master branch. Discussion ---------- [Form] Rewrite boolean attributes to match HTML spec | Q | A | ------------- | --- | Bug fix? | no | New feature? | yes | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | - | License | MIT | Doc PR | - Same as #7856 > 'The presence of a boolean attribute on an element represents the true value, and the absence of the attribute represents the false value.' - http://www.w3.org/html/wg/drafts/html/master/infrastructure.html#boolean-attribute This commit modifies widget_container_attributes and widget_attributes so that: * `true` values render as the attribute name with the attribute name repeated as the value * `false` values are not rendered The comparison is strict using sames() in twig. Previously `false` values would have been rendered as `some-attribute=""` which according to the spec would actually make them a boolean attribute and therefore equal to true. Commits -------b85577b
[Form] Improved test coverage of widget_attributes and widget_container_attributes blocks8e4c2a7
[Form] Rewrite boolean attributes to match HTML spec
This commit is contained in:
commit
164c1cbfec
@ -373,21 +373,53 @@
|
||||
|
||||
{% block widget_attributes %}
|
||||
{% spaceless %}
|
||||
id="{{ id }}" name="{{ full_name }}"{% if read_only %} readonly="readonly"{% endif %}{% if disabled %} disabled="disabled"{% endif %}{% if required %} required="required"{% endif %}{% if max_length %} maxlength="{{ max_length }}"{% endif %}{% if pattern %} pattern="{{ pattern }}"{% endif %}
|
||||
{% for attrname, attrvalue in attr %}{% if attrname in ['placeholder', 'title'] %}{{ attrname }}="{{ attrvalue|trans({}, translation_domain) }}" {% else %}{{ attrname }}="{{ attrvalue }}" {% endif %}{% endfor %}
|
||||
id="{{ id }}" name="{{ full_name }}"
|
||||
{%- if read_only %} readonly="readonly"{% endif -%}
|
||||
{%- if disabled %} disabled="disabled"{% endif -%}
|
||||
{%- if required %} required="required"{% endif -%}
|
||||
{%- if max_length %} maxlength="{{ max_length }}"{% endif -%}
|
||||
{%- if pattern %} pattern="{{ pattern }}"{% endif -%}
|
||||
{%- for attrname, attrvalue in attr -%}
|
||||
{{- " " -}}
|
||||
{%- if attrname in ['placeholder', 'title'] -%}
|
||||
{{- attrname }}="{{ attrvalue|trans({}, translation_domain) }}"
|
||||
{%- elseif attrvalue is sameas(true) -%}
|
||||
{{- attrname }}="{{ attrname }}"
|
||||
{%- elseif attrvalue is not sameas(false) -%}
|
||||
{{- attrname }}="{{ attrvalue }}"
|
||||
{%- endif -%}
|
||||
{%- endfor -%}
|
||||
{% endspaceless %}
|
||||
{% endblock widget_attributes %}
|
||||
|
||||
{% block widget_container_attributes %}
|
||||
{% spaceless %}
|
||||
{% if id is not empty %}id="{{ id }}" {% endif %}
|
||||
{% for attrname, attrvalue in attr %}{{ attrname }}="{{ attrvalue }}" {% endfor %}
|
||||
{%- if id is not empty %}id="{{ id }}"{% endif -%}
|
||||
{%- for attrname, attrvalue in attr -%}
|
||||
{{- " " -}}
|
||||
{%- if attrname in ['placeholder', 'title'] -%}
|
||||
{{- attrname }}="{{ attrvalue|trans({}, translation_domain) }}"
|
||||
{%- elseif attrvalue is sameas(true) -%}
|
||||
{{- attrname }}="{{ attrname }}"
|
||||
{%- elseif attrvalue is not sameas(false) -%}
|
||||
{{- attrname }}="{{ attrvalue }}"
|
||||
{%- endif -%}
|
||||
{%- endfor -%}
|
||||
{% endspaceless %}
|
||||
{% endblock widget_container_attributes %}
|
||||
|
||||
{% block button_attributes %}
|
||||
{% spaceless %}
|
||||
id="{{ id }}" name="{{ full_name }}"{% if disabled %} disabled="disabled"{% endif %}
|
||||
{% for attrname, attrvalue in attr %}{{ attrname }}="{{ attrvalue }}" {% endfor %}
|
||||
id="{{ id }}" name="{{ full_name }}"{% if disabled %} disabled="disabled"{% endif -%}
|
||||
{%- for attrname, attrvalue in attr -%}
|
||||
{{- " " -}}
|
||||
{%- if attrname in ['placeholder', 'title'] -%}
|
||||
{{- attrname }}="{{ attrvalue|trans({}, translation_domain) }}"
|
||||
{%- elseif attrvalue is sameas(true) -%}
|
||||
{{- attrname }}="{{ attrname }}"
|
||||
{%- elseif attrvalue is not sameas(false) -%}
|
||||
{{- attrname }}="{{ attrvalue }}"
|
||||
{%- endif -%}
|
||||
{%- endfor -%}
|
||||
{% endspaceless %}
|
||||
{% endblock button_attributes %}
|
||||
|
@ -1,6 +1,10 @@
|
||||
id="<?php echo $view->escape($id) ?>"
|
||||
name="<?php echo $view->escape($full_name) ?>"
|
||||
<?php if ($disabled): ?>disabled="disabled" <?php endif ?>
|
||||
id="<?php echo $view->escape($id) ?>" name="<?php echo $view->escape($full_name) ?>" <?php if ($disabled): ?>disabled="disabled" <?php endif ?>
|
||||
<?php foreach ($attr as $k => $v): ?>
|
||||
<?php printf('%s="%s" ', $view->escape($k), $view->escape($v)) ?>
|
||||
<?php endforeach; ?>
|
||||
<?php if (in_array($v, array('placeholder', 'title'), true)): ?>
|
||||
<?php printf('%s="%s" ', $view->escape($k), $view->escape($view['translator']->trans($v, array(), $translation_domain))) ?>
|
||||
<?php elseif ($v === true): ?>
|
||||
<?php printf('%s="%s" ', $view->escape($k), $view->escape($k)) ?>
|
||||
<?php elseif ($v !== false): ?>
|
||||
<?php printf('%s="%s" ', $view->escape($k), $view->escape($v)) ?>
|
||||
<?php endif ?>
|
||||
<?php endforeach ?>
|
||||
|
@ -1,5 +1 @@
|
||||
<input
|
||||
type="<?php echo isset($type) ? $view->escape($type) : 'text' ?>"
|
||||
<?php if (!empty($value)): ?>value="<?php echo $view->escape($value) ?>"<?php endif ?>
|
||||
<?php echo $view['form']->block($form, 'widget_attributes') ?>
|
||||
/>
|
||||
<input type="<?php echo isset($type) ? $view->escape($type) : 'text' ?>" <?php echo $view['form']->block($form, 'widget_attributes') ?><?php if (!empty($value)): ?> value="<?php echo $view->escape($value) ?>"<?php endif ?> />
|
||||
|
@ -1,10 +1,14 @@
|
||||
id="<?php echo $view->escape($id) ?>"
|
||||
name="<?php echo $view->escape($full_name) ?>"
|
||||
<?php if ($read_only): ?>readonly="readonly" <?php endif ?>
|
||||
id="<?php echo $view->escape($id) ?>" name="<?php echo $view->escape($full_name) ?>" <?php if ($read_only): ?>readonly="readonly" <?php endif ?>
|
||||
<?php if ($disabled): ?>disabled="disabled" <?php endif ?>
|
||||
<?php if ($required): ?>required="required" <?php endif ?>
|
||||
<?php if ($max_length): ?>maxlength="<?php echo $view->escape($max_length) ?>" <?php endif ?>
|
||||
<?php if ($pattern): ?>pattern="<?php echo $view->escape($pattern) ?>" <?php endif ?>
|
||||
<?php foreach ($attr as $k => $v): ?>
|
||||
<?php printf('%s="%s" ', $view->escape($k), $view->escape(in_array($v, array('placeholder', 'title')) ? $view['translator']->trans($v, array(), $translation_domain) : $v)) ?>
|
||||
<?php endforeach; ?>
|
||||
<?php if (in_array($v, array('placeholder', 'title'), true)): ?>
|
||||
<?php printf('%s="%s" ', $view->escape($k), $view->escape($view['translator']->trans($v, array(), $translation_domain))) ?>
|
||||
<?php elseif ($v === true): ?>
|
||||
<?php printf('%s="%s" ', $view->escape($k), $view->escape($k)) ?>
|
||||
<?php elseif ($v !== false): ?>
|
||||
<?php printf('%s="%s" ', $view->escape($k), $view->escape($v)) ?>
|
||||
<?php endif ?>
|
||||
<?php endforeach ?>
|
||||
|
@ -1,2 +1,10 @@
|
||||
<?php if (!empty($id)): ?>id="<?php echo $view->escape($id) ?>" <?php endif; ?>
|
||||
<?php foreach ($attr as $k => $v) { printf('%s="%s" ', $view->escape($k), $view->escape($v)); } ?>
|
||||
<?php if (!empty($id)): ?>id="<?php echo $view->escape($id) ?>" <?php endif ?>
|
||||
<?php foreach ($attr as $k => $v): ?>
|
||||
<?php if (in_array($v, array('placeholder', 'title'), true)): ?>
|
||||
<?php printf('%s="%s" ', $view->escape($k), $view->escape($view['translator']->trans($v, array(), $translation_domain))) ?>
|
||||
<?php elseif ($v === true): ?>
|
||||
<?php printf('%s="%s" ', $view->escape($k), $view->escape($k)) ?>
|
||||
<?php elseif ($v !== false): ?>
|
||||
<?php printf('%s="%s" ', $view->escape($k), $view->escape($v)) ?>
|
||||
<?php endif ?>
|
||||
<?php endforeach ?>
|
||||
|
@ -729,4 +729,42 @@ abstract class AbstractDivLayoutTest extends AbstractLayoutTest
|
||||
|
||||
$this->assertEquals('</form>', $html);
|
||||
}
|
||||
|
||||
public function testWidgetContainerAttributes()
|
||||
{
|
||||
$form = $this->factory->createNamed('form', 'form', null, array(
|
||||
'attr' => array('class' => 'foobar', 'data-foo' => 'bar'),
|
||||
));
|
||||
|
||||
$form->add('text', 'text');
|
||||
|
||||
$html = $this->renderWidget($form->createView());
|
||||
|
||||
// compare plain HTML to check the whitespace
|
||||
$this->assertContains('<div id="form" class="foobar" data-foo="bar">', $html);
|
||||
}
|
||||
|
||||
public function testWidgetContainerAttributeNameRepeatedIfTrue()
|
||||
{
|
||||
$form = $this->factory->createNamed('form', 'form', null, array(
|
||||
'attr' => array('foo' => true),
|
||||
));
|
||||
|
||||
$html = $this->renderWidget($form->createView());
|
||||
|
||||
// foo="foo"
|
||||
$this->assertContains('<div id="form" foo="foo">', $html);
|
||||
}
|
||||
|
||||
public function testWidgetContainerAttributeHiddenIfFalse()
|
||||
{
|
||||
$form = $this->factory->createNamed('form', 'form', null, array(
|
||||
'attr' => array('foo' => false),
|
||||
));
|
||||
|
||||
$html = $this->renderWidget($form->createView());
|
||||
|
||||
// no foo
|
||||
$this->assertContains('<div id="form">', $html);
|
||||
}
|
||||
}
|
||||
|
@ -302,8 +302,9 @@ abstract class AbstractLayoutTest extends \Symfony\Component\Form\Test\FormInteg
|
||||
);
|
||||
}
|
||||
|
||||
public function testWidgetById()
|
||||
public function testOverrideWidgetBlock()
|
||||
{
|
||||
// see custom_widgets.html.twig
|
||||
$form = $this->factory->createNamed('text_id', 'text');
|
||||
$html = $this->renderWidget($form->createView());
|
||||
|
||||
@ -1891,4 +1892,82 @@ abstract class AbstractLayoutTest extends \Symfony\Component\Form\Test\FormInteg
|
||||
|
||||
$this->assertSame('<form name="form" method="get" action="http://example.com/directory" class="foobar">', $html);
|
||||
}
|
||||
|
||||
public function testWidgetAttributes()
|
||||
{
|
||||
$form = $this->factory->createNamed('text', 'text', 'value', array(
|
||||
'required' => true,
|
||||
'disabled' => true,
|
||||
'read_only' => true,
|
||||
'max_length' => 10,
|
||||
'pattern' => '\d+',
|
||||
'attr' => array('class' => 'foobar', 'data-foo' => 'bar'),
|
||||
));
|
||||
|
||||
$html = $this->renderWidget($form->createView());
|
||||
|
||||
// compare plain HTML to check the whitespace
|
||||
$this->assertSame('<input type="text" id="text" name="text" readonly="readonly" disabled="disabled" required="required" maxlength="10" pattern="\d+" class="foobar" data-foo="bar" value="value" />', $html);
|
||||
}
|
||||
|
||||
public function testWidgetAttributeNameRepeatedIfTrue()
|
||||
{
|
||||
$form = $this->factory->createNamed('text', 'text', 'value', array(
|
||||
'attr' => array('foo' => true),
|
||||
));
|
||||
|
||||
$html = $this->renderWidget($form->createView());
|
||||
|
||||
// foo="foo"
|
||||
$this->assertSame('<input type="text" id="text" name="text" required="required" foo="foo" value="value" />', $html);
|
||||
}
|
||||
|
||||
public function testWidgetAttributeHiddenIfFalse()
|
||||
{
|
||||
$form = $this->factory->createNamed('text', 'text', 'value', array(
|
||||
'attr' => array('foo' => false),
|
||||
));
|
||||
|
||||
$html = $this->renderWidget($form->createView());
|
||||
|
||||
// no foo
|
||||
$this->assertSame('<input type="text" id="text" name="text" required="required" value="value" />', $html);
|
||||
}
|
||||
|
||||
public function testButtonAttributes()
|
||||
{
|
||||
$form = $this->factory->createNamed('button', 'button', null, array(
|
||||
'disabled' => true,
|
||||
'attr' => array('class' => 'foobar', 'data-foo' => 'bar'),
|
||||
));
|
||||
|
||||
$html = $this->renderWidget($form->createView());
|
||||
|
||||
// compare plain HTML to check the whitespace
|
||||
$this->assertSame('<button type="button" id="button" name="button" disabled="disabled" class="foobar" data-foo="bar">[trans]Button[/trans]</button>', $html);
|
||||
}
|
||||
|
||||
public function testButtonAttributeNameRepeatedIfTrue()
|
||||
{
|
||||
$form = $this->factory->createNamed('button', 'button', null, array(
|
||||
'attr' => array('foo' => true),
|
||||
));
|
||||
|
||||
$html = $this->renderWidget($form->createView());
|
||||
|
||||
// foo="foo"
|
||||
$this->assertSame('<button type="button" id="button" name="button" foo="foo">[trans]Button[/trans]</button>', $html);
|
||||
}
|
||||
|
||||
public function testButtonAttributeHiddenIfFalse()
|
||||
{
|
||||
$form = $this->factory->createNamed('button', 'button', null, array(
|
||||
'attr' => array('foo' => false),
|
||||
));
|
||||
|
||||
$html = $this->renderWidget($form->createView());
|
||||
|
||||
// no foo
|
||||
$this->assertSame('<button type="button" id="button" name="button">[trans]Button[/trans]</button>', $html);
|
||||
}
|
||||
}
|
||||
|
@ -506,4 +506,42 @@ abstract class AbstractTableLayoutTest extends AbstractLayoutTest
|
||||
|
||||
$this->assertEquals('</form>', $html);
|
||||
}
|
||||
|
||||
public function testWidgetContainerAttributes()
|
||||
{
|
||||
$form = $this->factory->createNamed('form', 'form', null, array(
|
||||
'attr' => array('class' => 'foobar', 'data-foo' => 'bar'),
|
||||
));
|
||||
|
||||
$form->add('text', 'text');
|
||||
|
||||
$html = $this->renderWidget($form->createView());
|
||||
|
||||
// compare plain HTML to check the whitespace
|
||||
$this->assertContains('<table id="form" class="foobar" data-foo="bar">', $html);
|
||||
}
|
||||
|
||||
public function testWidgetContainerAttributeNameRepeatedIfTrue()
|
||||
{
|
||||
$form = $this->factory->createNamed('form', 'form', null, array(
|
||||
'attr' => array('foo' => true),
|
||||
));
|
||||
|
||||
$html = $this->renderWidget($form->createView());
|
||||
|
||||
// foo="foo"
|
||||
$this->assertContains('<table id="form" foo="foo">', $html);
|
||||
}
|
||||
|
||||
public function testWidgetContainerAttributeHiddenIfFalse()
|
||||
{
|
||||
$form = $this->factory->createNamed('form', 'form', null, array(
|
||||
'attr' => array('foo' => false),
|
||||
));
|
||||
|
||||
$html = $this->renderWidget($form->createView());
|
||||
|
||||
// no foo
|
||||
$this->assertContains('<table id="form">', $html);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user