Funnel all invocations of wagtailadmin/shared/field.html through the formattedfield tag

At this point wagtailadmin/shared/field.html is still used by FieldPanel, as well as third-party code. Replace this by a template that simply pulls the relevant context variables from the template and passes them on to `{% formattedfield %}` (which renders them using the old template, now renamed formatted_field.html). This will allow us to move logic from the template to the tag function without breaking the existing wagtailadmin/shared/field.html API.
pull/11271/head
Matt Westcott 2023-11-21 22:56:45 +00:00
rodzic b3bdc0be4a
commit e97449dc5f
4 zmienionych plików z 96 dodań i 92 usunięć

Wyświetl plik

@ -16,7 +16,7 @@ export class FieldBlock {
this.blockDef = blockDef;
this.type = blockDef.name;
// See field.html for the reference implementation of this markup.
// See wagtailadmin/shared/formatted_field.html for the reference implementation of this markup.
const dom = $(`
<div class="w-field__wrapper" data-field-wrapper>
<div class="${h(this.blockDef.meta.classname)}" data-field>

Wyświetl plik

@ -1,88 +1,2 @@
{% load wagtailadmin_tags i18n %}
{% comment "text/markdown" %}
The field template is very flexible to cater for a wide range of use cases. It has two main attributes that support different use cases:
1. `field` to render a Django form field. This may be done through the `{% formattedfield my_field %}` template tag, or a direct `include` of this template.
2. `rendered_field` to render arbitrary HTML. This may be done through the tag pair `{% rawformattedfield %}<select>[…]</select>{% endrawformattedfield %}`,
or a direct `include` of this template.
If both `field` and `rendered_field` are passed, `rendered_field` will be used as the actual form rendering, but metadata
for the surrounding elements (such as help text and ID) will be picked up from `field`.
A unified template for both use cases is messy, but it guarantees we are keeping form field styles the same everywhere.
- `classname` - For legacy patterns requiring field-specific classes. Avoid if possible.
- `show_label` - Hide the label if it is rendered outside of the field.
- `id_for_label` - Manually set this this if the fields HTML isnt rendered by Django (for example hard-coded in HTML).
- `sr_only_label` - Make the label invisible for all but screen reader users. Use this if the field is displayed without a label.
- `icon` - Some fields have an icon, though this is generally a legacy pattern.
- `help_text` - Manually set this if the fields HTML is hard-coded.
- `help_text_id` - The help texts id, necessary so it can be attached to the field with `aria-describedby`.
- `show_add_comment_button` - Display a comment control within Wagtail forms.
- `label_text` - Manually set this if the fields HTML is hard-coded.
- `error_message_id` - ID of the error message container element.
{% endcomment %}
{% firstof id_for_label field.id_for_label as label_for %}
{% fragment as label_id %}{{ label_for }}-label{% endfragment %}
<div class="w-field__wrapper {{ classname }}" data-field-wrapper>
{# Render custom label attributes if provided, or the bound fields label attributes otherwise. #}
{% if show_label|default_if_none:True %}
{# Add an id to the label so we can use it as a descriptor for the "Add comment" button. #}
<label class="w-field__label{% if sr_only_label %} w-sr-only{% endif %}" for="{{ label_for }}" id="{{ label_id }}">
{% firstof label_text field.label %}{% if field.field.required %}<span class="w-required-mark">*</span>{% endif %}
</label>
{% endif %}
{# Its possible to customise the fields layout based on widget type. #}
{# Customising fields based on the field type is only supported for backwards compatibility. #}
<div class="w-field{% if field %} w-field--{{ field|fieldtype }} w-field--{{ field|widgettype }}{% endif %}{% if field.errors %} w-field--error{% endif %}{% if show_add_comment_button %} w-field--commentable{% endif %}" data-field data-contentpath="{{ field.name }}">
{# Always associate a wrapping div with the field, so JS error rendering knows where to put error messages. #}
<div class="w-field__errors" data-field-errors {% if error_message_id %}id="{{ error_message_id }}"{% endif %}>
{# Avoid rendering errors here if the widget itself is taking responsibility for its error rendering. #}
{% if field and field|has_unrendered_errors %}
{% icon name="warning" classname="w-field__errors-icon" %}
<p class="error-message">
{% for error in field.errors %}{{ error|escape }} {% endfor %}
</p>
{% endif %}
</div>
{# If help_text_id is in the context, use it. #}
{# Otherwise, if the field has help_text and id_for_label, automatically generate the id with that. #}
<div class="w-field__help" {% if help_text_id %}id="{{ help_text_id }}"{% elif field.help_text and field.id_for_label %}id="{{ field.id_for_label }}-helptext"{% endif %} data-field-help>
{% firstof help_text field.help_text as help_text_value %}
{% if help_text_value %}
<div class="help">{{ help_text_value }}</div>
{% endif %}
</div>
{# Separate container for the widget with prefix icon and suffix comment button #}
<div class="w-field__input" data-field-input>
{% if icon %}
{% icon name=icon classname="w-field__icon" %}
{% endif %}
{% block form_field %}
{% if rendered_field %}
{{ rendered_field }}
{% elif field %}
{{ field|render_with_errors }}
{% endif %}
{% endblock %}
{% if show_add_comment_button %}
<button class="w-field__comment-button w-field__comment-button--add" type="button" data-component="add-comment-button" data-comment-add aria-label="{% trans 'Add comment' %}" {% if label_for %}aria-describedby="{{ label_id }}"{% endif %}>
{% icon name="comment-add" %}
{% icon name="comment-add-reversed" %}
</button>
{% endif %}
</div>
</div>
</div>
{% load wagtailadmin_tags %}
{% formattedfield field=field rendered_field=rendered_field classname=classname show_label=show_label id_for_label=id_for_label sr_only_label=sr_only_label icon=icon help_text=help_text help_text_id=help_text_id show_add_comment_button=show_add_comment_button label_text=label_text error_message_id=error_message_id %}

Wyświetl plik

@ -0,0 +1,88 @@
{% load wagtailadmin_tags i18n %}
{% comment "text/markdown" %}
The field template is very flexible to cater for a wide range of use cases. It has two main attributes that support different use cases:
1. `field` to render a Django form field. This may be done through the `{% formattedfield my_field %}` template tag, or a direct `include` of this template.
2. `rendered_field` to render arbitrary HTML. This may be done through the tag pair `{% rawformattedfield %}<select>[…]</select>{% endrawformattedfield %}`,
or a direct `include` of this template.
If both `field` and `rendered_field` are passed, `rendered_field` will be used as the actual form rendering, but metadata
for the surrounding elements (such as help text and ID) will be picked up from `field`.
A unified template for both use cases is messy, but it guarantees we are keeping form field styles the same everywhere.
- `classname` - For legacy patterns requiring field-specific classes. Avoid if possible.
- `show_label` - Hide the label if it is rendered outside of the field.
- `id_for_label` - Manually set this this if the fields HTML isnt rendered by Django (for example hard-coded in HTML).
- `sr_only_label` - Make the label invisible for all but screen reader users. Use this if the field is displayed without a label.
- `icon` - Some fields have an icon, though this is generally a legacy pattern.
- `help_text` - Manually set this if the fields HTML is hard-coded.
- `help_text_id` - The help texts id, necessary so it can be attached to the field with `aria-describedby`.
- `show_add_comment_button` - Display a comment control within Wagtail forms.
- `label_text` - Manually set this if the fields HTML is hard-coded.
- `error_message_id` - ID of the error message container element.
{% endcomment %}
{% firstof id_for_label field.id_for_label as label_for %}
{% fragment as label_id %}{{ label_for }}-label{% endfragment %}
<div class="w-field__wrapper {{ classname }}" data-field-wrapper>
{# Render custom label attributes if provided, or the bound fields label attributes otherwise. #}
{% if show_label|default_if_none:True %}
{# Add an id to the label so we can use it as a descriptor for the "Add comment" button. #}
<label class="w-field__label{% if sr_only_label %} w-sr-only{% endif %}" for="{{ label_for }}" id="{{ label_id }}">
{% firstof label_text field.label %}{% if field.field.required %}<span class="w-required-mark">*</span>{% endif %}
</label>
{% endif %}
{# Its possible to customise the fields layout based on widget type. #}
{# Customising fields based on the field type is only supported for backwards compatibility. #}
<div class="w-field{% if field %} w-field--{{ field|fieldtype }} w-field--{{ field|widgettype }}{% endif %}{% if field.errors %} w-field--error{% endif %}{% if show_add_comment_button %} w-field--commentable{% endif %}" data-field data-contentpath="{{ field.name }}">
{# Always associate a wrapping div with the field, so JS error rendering knows where to put error messages. #}
<div class="w-field__errors" data-field-errors {% if error_message_id %}id="{{ error_message_id }}"{% endif %}>
{# Avoid rendering errors here if the widget itself is taking responsibility for its error rendering. #}
{% if field and field|has_unrendered_errors %}
{% icon name="warning" classname="w-field__errors-icon" %}
<p class="error-message">
{% for error in field.errors %}{{ error|escape }} {% endfor %}
</p>
{% endif %}
</div>
{# If help_text_id is in the context, use it. #}
{# Otherwise, if the field has help_text and id_for_label, automatically generate the id with that. #}
<div class="w-field__help" {% if help_text_id %}id="{{ help_text_id }}"{% elif field.help_text and field.id_for_label %}id="{{ field.id_for_label }}-helptext"{% endif %} data-field-help>
{% firstof help_text field.help_text as help_text_value %}
{% if help_text_value %}
<div class="help">{{ help_text_value }}</div>
{% endif %}
</div>
{# Separate container for the widget with prefix icon and suffix comment button #}
<div class="w-field__input" data-field-input>
{% if icon %}
{% icon name=icon classname="w-field__icon" %}
{% endif %}
{% block form_field %}
{% if rendered_field %}
{{ rendered_field }}
{% elif field %}
{{ field|render_with_errors }}
{% endif %}
{% endblock %}
{% if show_add_comment_button %}
<button class="w-field__comment-button w-field__comment-button--add" type="button" data-component="add-comment-button" data-comment-add aria-label="{% trans 'Add comment' %}" {% if label_for %}aria-describedby="{{ label_id }}"{% endif %}>
{% icon name="comment-add" %}
{% icon name="comment-add-reversed" %}
</button>
{% endif %}
</div>
</div>
</div>

Wyświetl plik

@ -1104,7 +1104,7 @@ class RawFormattedFieldNode(BlockInclusionNode):
register.tag("rawformattedfield", RawFormattedFieldNode.handle)
@register.inclusion_tag("wagtailadmin/shared/field.html")
@register.inclusion_tag("wagtailadmin/shared/formatted_field.html")
def formattedfield(
field=None,
rendered_field=None,
@ -1134,11 +1134,13 @@ def formattedfield(
- `label_text` - Manually set this if the fields HTML is hard-coded.
- `error_message_id` - ID of the error message container element.
"""
# for classname and show_label, need to explicitly handle None values rather than relying on the argument defaults,
# as this is how they'll come through from wagtailadmin/shared/field.html if those variables were undefined
return {
"field": field,
"rendered_field": rendered_field,
"classname": classname,
"show_label": show_label,
"classname": classname or "",
"show_label": True if show_label is None else show_label,
"id_for_label": id_for_label,
"sr_only_label": sr_only_label,
"icon": icon,