kopia lustrzana https://github.com/wagtail/wagtail
Update panel templates for new designs (EditHandler rewrite)
Co-authored-by: Thibaud Colas <thibaudcolas@gmail.com>pull/8948/head
rodzic
3b84559b0f
commit
5521e3b59f
|
@ -104,8 +104,6 @@ See {ref}`collapsible` for more details on `collapsible` usage.
|
|||
|
||||
Use of FieldRowPanel particularly helps reduce the "snow-blindness" effect of seeing so many fields on the page, for complex models. It also improves the perceived association between fields of a similar nature. For example if you created a model representing an "Event" which had a starting date and ending date, it may be intuitive to find the start and end date on the same "row".
|
||||
|
||||
By default, the panel is divided into equal-width columns, but this can be overridden by adding ``col*`` class names to each of the child Panels of the FieldRowPanel. The Wagtail editing interface is laid out using a grid system, in which the maximum width of the editor is 12 columns. Classes ``col1``-``col12`` can be applied to each child of a FieldRowPanel. The class ``col3`` will ensure that field appears 3 columns wide or a quarter the width. ``col4`` would cause the field to be 4 columns wide, or a third the width.
|
||||
|
||||
.. attribute:: FieldRowPanel.children
|
||||
|
||||
A ``list`` or ``tuple`` of child panels to display on the row
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
.. automethod:: get_form_options
|
||||
.. automethod:: get_form_class
|
||||
.. automethod:: get_bound_panel
|
||||
.. autoproperty:: clean_name
|
||||
```
|
||||
|
||||
## `BoundPanel`
|
||||
|
@ -24,8 +25,13 @@
|
|||
|
||||
.. autoclass:: wagtail.admin.panels.Panel.BoundPanel
|
||||
|
||||
In addition to the standard template component functionality (see :ref:`creating_template_components`), this provides the following methods:
|
||||
In addition to the standard template component functionality (see :ref:`creating_template_components`), this provides the following attributes and methods:
|
||||
|
||||
.. autoattribute:: panel
|
||||
.. autoattribute:: instance
|
||||
.. autoattribute:: request
|
||||
.. autoattribute:: form
|
||||
.. autoattribute:: prefix
|
||||
.. automethod:: id_for_label
|
||||
.. automethod:: is_shown
|
||||
```
|
||||
|
|
|
@ -220,7 +220,7 @@ class CustomPanel(Panel):
|
|||
# are available here
|
||||
```
|
||||
|
||||
The template context for panels derived from `BaseChooserPanel` has changed. `BaseChooserPanel` is deprecated and now functionally identical to `FieldPanel`; as a result, the context variable `is_chosen`, and the variable name given by the panel's `object_type_name` property, are no longer available on the template. The only available variables are now `field` and `show_add_comment_button`. If your template depends on these additional variables, you will need to pass them explicitly by overriding the `render_as_field` method.
|
||||
The template context for panels derived from `BaseChooserPanel` has changed. `BaseChooserPanel` is deprecated and now functionally identical to `FieldPanel`; as a result, the context variable `is_chosen`, and the variable name given by the panel's `object_type_name` property, are no longer available on the template. The only available variables are now `field` and `show_add_comment_button`. If your template depends on these additional variables, you will need to pass them explicitly by overriding the `BoundPanel.get_context_data` method.
|
||||
|
||||
### API changes to ModelAdmin
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import functools
|
||||
import re
|
||||
from warnings import warn
|
||||
|
||||
from django import forms
|
||||
|
@ -12,7 +11,6 @@ from django.dispatch import receiver
|
|||
from django.forms import Media
|
||||
from django.forms.formsets import DELETION_FIELD_NAME, ORDERING_FIELD_NAME
|
||||
from django.forms.models import fields_for_model
|
||||
from django.template.loader import render_to_string
|
||||
from django.utils.functional import cached_property
|
||||
from django.utils.safestring import mark_safe
|
||||
from django.utils.translation import gettext_lazy
|
||||
|
@ -24,7 +22,7 @@ from wagtail.admin.templatetags.wagtailadmin_tags import avatar_url, user_displa
|
|||
from wagtail.admin.ui.components import Component
|
||||
from wagtail.admin.widgets import AdminPageChooser
|
||||
from wagtail.blocks import BlockField
|
||||
from wagtail.coreutils import camelcase_to_underscore
|
||||
from wagtail.coreutils import safe_snake_case
|
||||
from wagtail.models import COMMENTS_RELATION_NAME, Page
|
||||
from wagtail.utils.decorators import cached_classmethod
|
||||
from wagtail.utils.deprecation import RemovedInWagtail50Warning
|
||||
|
@ -225,7 +223,7 @@ class Panel:
|
|||
)
|
||||
return self.get_bound_panel(instance=instance, request=request, form=form)
|
||||
|
||||
def get_bound_panel(self, instance=None, request=None, form=None):
|
||||
def get_bound_panel(self, instance=None, request=None, form=None, prefix="panel"):
|
||||
"""
|
||||
Return a ``BoundPanel`` instance that can be rendered onto the template as a component. By default, this creates an instance
|
||||
of the panel class's inner ``BoundPanel`` class, which must inherit from ``Panel.BoundPanel``.
|
||||
|
@ -243,7 +241,7 @@ class Panel:
|
|||
)
|
||||
|
||||
return self.BoundPanel(
|
||||
panel=self, instance=instance, request=request, form=form
|
||||
panel=self, instance=instance, request=request, form=form, prefix=prefix
|
||||
)
|
||||
|
||||
def on_model_bound(self):
|
||||
|
@ -269,12 +267,6 @@ class Panel:
|
|||
return [self.classname]
|
||||
return []
|
||||
|
||||
def field_type(self):
|
||||
"""
|
||||
The kind of field it is e.g boolean_field. Useful for better semantic markup of field display based on type
|
||||
"""
|
||||
return ""
|
||||
|
||||
def id_for_label(self):
|
||||
"""
|
||||
The ID to be used as the 'for' attribute of any <label> elements that refer
|
||||
|
@ -283,17 +275,36 @@ class Panel:
|
|||
"""
|
||||
return ""
|
||||
|
||||
@property
|
||||
def clean_name(self):
|
||||
"""
|
||||
A name for this panel, consisting only of ASCII alphanumerics and underscores, suitable for use in identifiers.
|
||||
Usually generated from the panel heading. Note that this is not guaranteed to be unique or non-empty; anything
|
||||
making use of this and requiring uniqueness should validate and modify the return value as needed.
|
||||
"""
|
||||
return safe_snake_case(self.heading)
|
||||
|
||||
class BoundPanel(Component):
|
||||
"""
|
||||
A template component for a panel that has been associated with a model instance, form, and request.
|
||||
"""
|
||||
|
||||
def __init__(self, panel, instance, request, form):
|
||||
def __init__(self, panel, instance, request, form, prefix):
|
||||
#: The panel definition corresponding to this bound panel
|
||||
self.panel = panel
|
||||
|
||||
#: The model instance associated with this panel
|
||||
self.instance = instance
|
||||
|
||||
#: The request object associated with this panel
|
||||
self.request = request
|
||||
|
||||
#: The form object associated with this panel
|
||||
self.form = form
|
||||
|
||||
#: A unique prefix for this panel, for use in HTML IDs
|
||||
self.prefix = prefix
|
||||
|
||||
self.heading = self.panel.heading
|
||||
self.help_text = self.panel.help_text
|
||||
|
||||
|
@ -304,9 +315,6 @@ class Panel:
|
|||
def classes(self):
|
||||
return self.panel.classes()
|
||||
|
||||
def field_type(self):
|
||||
return self.panel.field_type()
|
||||
|
||||
def id_for_label(self):
|
||||
"""
|
||||
Returns an HTML ID to be used as the target for any label referencing this panel.
|
||||
|
@ -319,10 +327,23 @@ class Panel:
|
|||
"""
|
||||
return True
|
||||
|
||||
def is_required(self):
|
||||
return False
|
||||
|
||||
def render_as_object(self):
|
||||
warn(
|
||||
"Panel.render_as_object is deprecated. Use render_html instead",
|
||||
category=RemovedInWagtail50Warning,
|
||||
stacklevel=2,
|
||||
)
|
||||
return self.render_html()
|
||||
|
||||
def render_as_field(self):
|
||||
warn(
|
||||
"Panel.render_as_field is deprecated. Use render_html instead",
|
||||
category=RemovedInWagtail50Warning,
|
||||
stacklevel=2,
|
||||
)
|
||||
return self.render_html()
|
||||
|
||||
def get_context_data(self, parent_context=None):
|
||||
|
@ -355,7 +376,7 @@ class Panel:
|
|||
Render this as an 'object', ensuring that all fields necessary for a valid form
|
||||
submission are included
|
||||
"""
|
||||
return mark_safe(self.render_as_object() + self.render_missing_fields())
|
||||
return mark_safe(self.render_html() + self.render_missing_fields())
|
||||
|
||||
def __repr__(self):
|
||||
return "<%s with model=%s instance=%s request=%s form=%s>" % (
|
||||
|
@ -443,23 +464,56 @@ class PanelGroup(Panel):
|
|||
def on_model_bound(self):
|
||||
self.children = [child.bind_to_model(self.model) for child in self.children]
|
||||
|
||||
class BoundPanel(Panel.BoundPanel):
|
||||
def __init__(self, panel, instance, request, form):
|
||||
super().__init__(panel=panel, instance=instance, request=request, form=form)
|
||||
@cached_property
|
||||
def child_identifiers(self):
|
||||
"""
|
||||
A list of identifiers corresponding to child panels in ``self.children``, formed from the clean_name property
|
||||
but validated to be unique and non-empty.
|
||||
"""
|
||||
used_names = set()
|
||||
result = []
|
||||
for panel in self.children:
|
||||
base_name = panel.clean_name or "panel"
|
||||
candidate_name = base_name
|
||||
suffix = 0
|
||||
while candidate_name in used_names:
|
||||
suffix += 1
|
||||
candidate_name = "%s%d" % (base_name, suffix)
|
||||
|
||||
result.append(candidate_name)
|
||||
used_names.add(candidate_name)
|
||||
|
||||
return result
|
||||
|
||||
class BoundPanel(Panel.BoundPanel):
|
||||
@cached_property
|
||||
def children(self):
|
||||
return [
|
||||
child.get_bound_panel(
|
||||
instance=self.instance, request=self.request, form=self.form
|
||||
instance=self.instance,
|
||||
request=self.request,
|
||||
form=self.form,
|
||||
prefix=("%s-child-%s" % (self.prefix, identifier)),
|
||||
)
|
||||
for child, identifier in zip(
|
||||
self.panel.children, self.panel.child_identifiers
|
||||
)
|
||||
for child in self.panel.children
|
||||
]
|
||||
|
||||
@cached_property
|
||||
def visible_children(self):
|
||||
return [child for child in self.children if child.is_shown()]
|
||||
|
||||
@cached_property
|
||||
def visible_children_with_identifiers(self):
|
||||
return [
|
||||
(child, identifier)
|
||||
for child, identifier in zip(
|
||||
self.children, self.panel.child_identifiers
|
||||
)
|
||||
if child.is_shown()
|
||||
]
|
||||
|
||||
def is_shown(self):
|
||||
return any(child.is_shown() for child in self.children)
|
||||
|
||||
|
@ -501,24 +555,10 @@ class ObjectList(PanelGroup):
|
|||
|
||||
class FieldRowPanel(PanelGroup):
|
||||
class BoundPanel(PanelGroup.BoundPanel):
|
||||
template_name = "wagtailadmin/panels/field_row_panel.html"
|
||||
|
||||
def visible_children_with_classnames(self):
|
||||
visible_children = self.visible_children
|
||||
col_count = " col%s" % (12 // len(visible_children))
|
||||
for child in visible_children:
|
||||
classname = " ".join(child.classes())
|
||||
if not re.search(r"\bcol\d+\b", classname):
|
||||
classname += col_count
|
||||
yield child, classname
|
||||
template_name = "wagtailadmin/panels/multi_field_panel.html"
|
||||
|
||||
|
||||
class MultiFieldPanel(PanelGroup):
|
||||
def classes(self):
|
||||
classes = super().classes()
|
||||
classes.append("multi-field")
|
||||
return classes
|
||||
|
||||
class BoundPanel(PanelGroup.BoundPanel):
|
||||
template_name = "wagtailadmin/panels/multi_field_panel.html"
|
||||
|
||||
|
@ -543,9 +583,13 @@ class HelpPanel(Panel):
|
|||
)
|
||||
return kwargs
|
||||
|
||||
@property
|
||||
def clean_name(self):
|
||||
return super().clean_name or "help"
|
||||
|
||||
class BoundPanel(Panel.BoundPanel):
|
||||
def __init__(self, panel, instance, request, form):
|
||||
super().__init__(panel, instance, request, form)
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
self.template_name = self.panel.template
|
||||
self.content = self.panel.content
|
||||
|
||||
|
@ -617,6 +661,10 @@ class FieldPanel(Panel):
|
|||
|
||||
return model._meta.get_field(self.field_name)
|
||||
|
||||
@property
|
||||
def clean_name(self):
|
||||
return self.field_name
|
||||
|
||||
def __repr__(self):
|
||||
return "<%s '%s' with model=%s>" % (
|
||||
self.__class__.__name__,
|
||||
|
@ -625,11 +673,10 @@ class FieldPanel(Panel):
|
|||
)
|
||||
|
||||
class BoundPanel(Panel.BoundPanel):
|
||||
object_template_name = "wagtailadmin/panels/single_field_panel.html"
|
||||
field_template_name = "wagtailadmin/panels/field_panel_field.html"
|
||||
template_name = "wagtailadmin/panels/field_panel.html"
|
||||
|
||||
def __init__(self, panel, instance, request, form):
|
||||
super().__init__(panel=panel, instance=instance, request=request, form=form)
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
|
||||
if self.form is None:
|
||||
self.bound_field = None
|
||||
|
@ -666,26 +713,11 @@ class FieldPanel(Panel):
|
|||
|
||||
return True
|
||||
|
||||
def is_required(self):
|
||||
return self.bound_field.field.required
|
||||
|
||||
def classes(self):
|
||||
classes = self.panel.classes().copy()
|
||||
|
||||
if self.bound_field.field.required:
|
||||
classes.append("required")
|
||||
|
||||
# If field has any errors, add the classname 'error' to enable error styling
|
||||
# (e.g. red background), unless the widget has its own mechanism for rendering errors
|
||||
# via the render_with_errors mechanism (as StreamField does).
|
||||
if self.bound_field.errors and not hasattr(
|
||||
self.bound_field.field.widget, "render_with_errors"
|
||||
):
|
||||
classes.append("error")
|
||||
|
||||
classes.append(self.field_type())
|
||||
|
||||
return classes
|
||||
|
||||
def field_type(self):
|
||||
return camelcase_to_underscore(self.bound_field.field.__class__.__name__)
|
||||
return self.panel.classes()
|
||||
|
||||
def id_for_label(self):
|
||||
return self.bound_field.id_for_label
|
||||
|
@ -698,32 +730,66 @@ class FieldPanel(Panel):
|
|||
else:
|
||||
return not self.panel.disable_comments
|
||||
|
||||
def render_as_object(self):
|
||||
return render_to_string(
|
||||
self.object_template_name,
|
||||
{
|
||||
"self": self,
|
||||
self.panel.TEMPLATE_VAR: self,
|
||||
"field": self.bound_field,
|
||||
"show_add_comment_button": self.comments_enabled
|
||||
and getattr(
|
||||
self.bound_field.field.widget, "show_add_comment_button", True
|
||||
),
|
||||
},
|
||||
)
|
||||
def get_context_data(self, parent_context=None):
|
||||
context = super().get_context_data(parent_context)
|
||||
|
||||
def render_as_field(self):
|
||||
return render_to_string(
|
||||
self.field_template_name,
|
||||
widget_described_by_ids = []
|
||||
help_text = self.bound_field.help_text
|
||||
help_text_id = "%s-helptext" % self.prefix
|
||||
errors = None
|
||||
error_message_id = "%s-errors" % self.prefix
|
||||
|
||||
if help_text:
|
||||
widget_described_by_ids.append(help_text_id)
|
||||
|
||||
if self.bound_field.errors:
|
||||
widget = self.bound_field.field.widget
|
||||
if hasattr(widget, "render_with_errors"):
|
||||
widget_attrs = {
|
||||
"id": self.bound_field.auto_id,
|
||||
}
|
||||
if widget_described_by_ids:
|
||||
widget_attrs["aria-describedby"] = " ".join(
|
||||
widget_described_by_ids
|
||||
)
|
||||
|
||||
rendered_field = widget.render_with_errors(
|
||||
self.bound_field.html_name,
|
||||
self.bound_field.value(),
|
||||
attrs=widget_attrs,
|
||||
errors=self.bound_field.errors,
|
||||
)
|
||||
else:
|
||||
errors = self.bound_field.errors
|
||||
widget_described_by_ids.append(error_message_id)
|
||||
rendered_field = self.bound_field.as_widget(
|
||||
attrs={
|
||||
"aria-invalid": "true",
|
||||
"aria-describedby": " ".join(widget_described_by_ids),
|
||||
}
|
||||
)
|
||||
else:
|
||||
widget_attrs = {}
|
||||
if widget_described_by_ids:
|
||||
widget_attrs["aria-describedby"] = " ".join(widget_described_by_ids)
|
||||
|
||||
rendered_field = self.bound_field.as_widget(attrs=widget_attrs)
|
||||
|
||||
context.update(
|
||||
{
|
||||
"field": self.bound_field,
|
||||
"field_type": self.field_type(),
|
||||
"rendered_field": rendered_field,
|
||||
"help_text": help_text,
|
||||
"help_text_id": help_text_id,
|
||||
"errors": errors,
|
||||
"error_message_id": error_message_id,
|
||||
"show_add_comment_button": self.comments_enabled
|
||||
and getattr(
|
||||
self.bound_field.field.widget, "show_add_comment_button", True
|
||||
),
|
||||
},
|
||||
}
|
||||
)
|
||||
return context
|
||||
|
||||
def get_comparison(self):
|
||||
comparator_class = self.panel.get_comparison_class()
|
||||
|
@ -862,8 +928,8 @@ class InlinePanel(Panel):
|
|||
class BoundPanel(Panel.BoundPanel):
|
||||
template_name = "wagtailadmin/panels/inline_panel.html"
|
||||
|
||||
def __init__(self, panel, instance, request, form):
|
||||
super().__init__(panel, instance, request, form)
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
|
||||
self.label = self.panel.label
|
||||
|
||||
|
@ -874,7 +940,7 @@ class InlinePanel(Panel):
|
|||
self.child_edit_handler = self.panel.child_edit_handler
|
||||
|
||||
self.children = []
|
||||
for subform in self.formset.forms:
|
||||
for index, subform in enumerate(self.formset.forms):
|
||||
# override the DELETE field to have a hidden input
|
||||
subform.fields[DELETION_FIELD_NAME].widget = forms.HiddenInput()
|
||||
|
||||
|
@ -884,7 +950,10 @@ class InlinePanel(Panel):
|
|||
|
||||
self.children.append(
|
||||
self.child_edit_handler.get_bound_panel(
|
||||
instance=subform.instance, request=self.request, form=subform
|
||||
instance=subform.instance,
|
||||
request=self.request,
|
||||
form=subform,
|
||||
prefix=("%s-%d" % (self.prefix, index)),
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -901,16 +970,22 @@ class InlinePanel(Panel):
|
|||
empty_form.fields[ORDERING_FIELD_NAME].widget = forms.HiddenInput()
|
||||
|
||||
self.empty_child = self.child_edit_handler.get_bound_panel(
|
||||
instance=empty_form.instance, request=self.request, form=empty_form
|
||||
instance=empty_form.instance,
|
||||
request=self.request,
|
||||
form=empty_form,
|
||||
prefix=("%s-__prefix__" % self.prefix),
|
||||
)
|
||||
|
||||
def get_comparison(self):
|
||||
field_comparisons = []
|
||||
|
||||
for panel in self.panel.child_edit_handler.children:
|
||||
for index, panel in enumerate(self.panel.child_edit_handler.children):
|
||||
field_comparisons.extend(
|
||||
panel.get_bound_panel(
|
||||
instance=None, request=self.request, form=None
|
||||
instance=None,
|
||||
request=self.request,
|
||||
form=None,
|
||||
prefix=("%s-%d" % (self.prefix, index)),
|
||||
).get_comparison()
|
||||
)
|
||||
|
||||
|
@ -968,6 +1043,10 @@ class CommentPanel(Panel):
|
|||
},
|
||||
}
|
||||
|
||||
@property
|
||||
def clean_name(self):
|
||||
return super().clean_name or "commments"
|
||||
|
||||
class BoundPanel(Panel.BoundPanel):
|
||||
template_name = "wagtailadmin/panels/comments/comment_panel.html"
|
||||
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
{% load wagtailadmin_tags i18n %}
|
||||
<div id="{{ self.prefix }}-field" class="w-field {% if field.errors %}w-field--error{% endif %}" data-contentpath="{{ field.name }}">
|
||||
{% if errors %}
|
||||
<p id="{{ error_message_id }}" class="w-error"><svg width="16" height="16"><use href="#icon-cross"></use></svg>{% for error in errors %}{{ error }} {% endfor %}</p>
|
||||
{% endif %}
|
||||
|
||||
{{ rendered_field }}
|
||||
{% if help_text %}
|
||||
<p id="{{ help_text_id }}" class="w-help-text">{{ help_text }}</p>
|
||||
{% endif %}
|
||||
|
||||
{% if show_add_comment_button %}
|
||||
<div class="field-comment-control">
|
||||
<button type="button" data-component="add-comment-button" data-comment-add class="u-hidden" aria-label="{% trans 'Add comment' %}">
|
||||
{% icon name="comment-add" class_name="initial icon-default" %}
|
||||
{% icon name="comment-add-reversed" class_name="initial icon-reversed" %}
|
||||
</button>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
|
@ -1 +0,0 @@
|
|||
{% include "wagtailadmin/shared/field.html" %}
|
|
@ -1,7 +0,0 @@
|
|||
<ul class="field-row {{ self.classes|join:" " }}">
|
||||
{% for child, classname in self.visible_children_with_classnames %}
|
||||
<li class="field-col {{ classname }}">
|
||||
{{ child.render_as_field }}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
|
@ -1,8 +1,6 @@
|
|||
<fieldset>
|
||||
<legend>{{ self.heading }}</legend>
|
||||
<ul class="fields">
|
||||
{% for child in self.visible_children %}
|
||||
<li class="{{ child.classes|join:" " }}">{{ child.render_as_field }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</fieldset>
|
||||
{% load wagtailadmin_tags %}
|
||||
{% for child in self.visible_children %}
|
||||
<label {% if child.id_for_label %}for="{{ child.id_for_label }}"{% endif %} class="w-field__label">{{ child.heading }}{% if child.is_required %}<span class="w-error" aria-hidden="true">*</span>{% endif %}</label>
|
||||
|
||||
{% component child %}
|
||||
{% endfor %}
|
||||
|
|
|
@ -1,28 +1,33 @@
|
|||
{% load wagtailadmin_tags %}
|
||||
{% load wagtailadmin_tags %}
|
||||
|
||||
<ul class="objects">
|
||||
{% for child in self.visible_children %}
|
||||
<li class="object {{ child.classes|join:" " }}">
|
||||
{% if child.heading %}
|
||||
<div class="title-wrapper">
|
||||
<label {% if child.id_for_label %}for="{{ child.id_for_label }}"{% endif %}>
|
||||
{{ child.heading }}
|
||||
</label>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="object-layout">
|
||||
{% if child.help_text %}
|
||||
<div class="object-layout_small-part">
|
||||
<div class="object-help help">
|
||||
{% icon name="help" class_name="default" %}
|
||||
{{ child.help_text }}
|
||||
</div>
|
||||
</div>
|
||||
{% for child, identifier in self.visible_children_with_identifiers %}
|
||||
<section
|
||||
id="{{ self.prefix }}-childsection-{{ identifier }}"
|
||||
aria-labelledby="{{ self.prefix }}-childheading-{{ identifier }}"
|
||||
class="w-panel"
|
||||
>
|
||||
<div class="w-panel__header">
|
||||
<a href="#{{ self.prefix }}-childsection-{{ identifier }}" aria-label="Link to {{ child.heading }}">#</a>
|
||||
<button
|
||||
type="button"
|
||||
class="w-panel__toggle"
|
||||
aria-label="Toggle {{ child.heading }}"
|
||||
aria-controls="{{ self.prefix }}-childcontent-{{ identifier }}"
|
||||
aria-expanded="true"
|
||||
>
|
||||
<svg width="16" height="16"><use href="#icon-pilcrow"></use></svg>
|
||||
</button>
|
||||
<h2 id="{{ self.prefix }}-childheading-{{ identifier }}" class="w-panel__heading">
|
||||
{% if child.id_for_label %}
|
||||
<label for="{{ child.id_for_label }}">{{ child.heading }}{% if child.is_required %}<span class="w-error" aria-hidden="true">*</span>{% endif %}</label>
|
||||
{% else %}
|
||||
{{ child.heading }}{% if child.is_required %}<span class="w-error" aria-hidden="true">*</span>{% endif %}
|
||||
{% endif %}
|
||||
<div class="object-layout_big-part">
|
||||
{{ child.render_as_object }}
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
<div id="{{ self.prefix }}-childcontent-{{ identifier }}" class="w-panel__content">
|
||||
{% component child %}
|
||||
</div>
|
||||
</section>
|
||||
{% endfor %}
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
{% load i18n wagtailadmin_tags %}
|
||||
|
||||
<div data-contentpath="{{ self.field_name }}">
|
||||
<fieldset>
|
||||
<legend>{{ self.heading }}</legend>
|
||||
<ul class="fields">
|
||||
<li>
|
||||
{% include "wagtailadmin/shared/field.html" with show_label=False show_help_text=False show_add_comment_button=False include_contentpath=False %}
|
||||
</li>
|
||||
</ul>
|
||||
</fieldset>
|
||||
|
||||
{% if show_add_comment_button %}
|
||||
<div class="field-comment-control field-comment-control--object">
|
||||
<button type="button" data-component="add-comment-button" data-comment-add class="u-hidden" aria-label="{% trans 'Add comment' %}">
|
||||
{% icon name="comment-add" class_name="initial icon-default" %}
|
||||
{% icon name="comment-add-reversed" class_name="initial icon-reversed" %}
|
||||
</button>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
|
@ -3,8 +3,8 @@
|
|||
<div class="w-tabs" data-tabs>
|
||||
<div class="w-tabs__wrapper">
|
||||
<div role="tablist" class="w-tabs__list">
|
||||
{% for child in self.visible_children %}
|
||||
{% include 'wagtailadmin/shared/tabs/tab_nav_link.html' with tab_id=child.heading title=child.heading classes=child.classes|join:" " %}
|
||||
{% for child, identifier in self.visible_children_with_identifiers %}
|
||||
{% include 'wagtailadmin/shared/tabs/tab_nav_link.html' with tab_id=identifier title=child.heading classes=child.classes|join:" " %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
|
@ -21,15 +21,15 @@
|
|||
</div>
|
||||
|
||||
<div class="tab-content">
|
||||
{% for child in self.visible_children %}
|
||||
{% for child, identifier in self.visible_children_with_identifiers %}
|
||||
<section
|
||||
id="tab-{{ child.heading|cautious_slugify }}"
|
||||
id="tab-{{ identifier }}"
|
||||
class="w-tabs__panel {{ child.classes|join:" " }}"
|
||||
role="tabpanel"
|
||||
aria-labelledby="tab-label-{{ child.heading|cautious_slugify }}"
|
||||
aria-labelledby="tab-label-{{ identifier }}"
|
||||
hidden
|
||||
>
|
||||
{{ child.render_as_object }}
|
||||
{{ child.render_html }}
|
||||
</section>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
{% load wagtailadmin_tags i18n %}
|
||||
{% load i18n %}
|
||||
|
||||
{% comment %}
|
||||
Variables accepted by this template:
|
||||
|
||||
- `tab_id` - {string} A unique tab id
|
||||
- `tab_id` - {string} A unique tab id consisting only of ASCII alphanumerics, dashes and underscores
|
||||
- `title` - {string} Text that the tab button will display
|
||||
- `active` - {boolean?} Force this to be active
|
||||
- `classes` - {string?} Extra css classes to pass to this component
|
||||
- `errors_count` - {number?} Show above the tab for errors count
|
||||
{% endcomment %}
|
||||
|
||||
<a id="tab-label-{{ tab_id|cautious_slugify }}" href="#tab-{{ tab_id|cautious_slugify }}" class="w-tabs__tab {{ classes }}" role="tab" aria-selected="false" tabindex="-1">
|
||||
<a id="tab-label-{{ tab_id }}" href="#tab-{{ tab_id }}" class="w-tabs__tab {{ classes }}" role="tab" aria-selected="false" tabindex="-1">
|
||||
<div data-tabs-errors class="w-tabs__errors {% if errors_count %}!w-flex{% endif %}">
|
||||
<span class="w-sr-only">{% trans 'Errors Count: ' %}</span>
|
||||
<span data-tabs-errors-count>{{ errors_count }}</span>
|
||||
|
|
|
@ -117,7 +117,10 @@ class TestPageEdit(TestCase, WagtailTestUtils):
|
|||
self.assertContains(response, 'id="status-sidebar-live"')
|
||||
|
||||
# Test InlinePanel labels/headings
|
||||
self.assertContains(response, "<legend>Speaker lineup</legend>")
|
||||
self.assertContains(
|
||||
response,
|
||||
'<label for="id_speakers-__prefix__-last_name" class="w-field__label">Surname</label>',
|
||||
)
|
||||
self.assertContains(response, "Add speakers")
|
||||
|
||||
# test register_page_action_menu_item hook
|
||||
|
@ -985,8 +988,8 @@ class TestPageEdit(TestCase, WagtailTestUtils):
|
|||
reverse("wagtailadmin_pages:edit", args=(self.child_page.id,))
|
||||
)
|
||||
|
||||
input_field_for_draft_slug = '<input type="text" name="slug" value="revised-slug-in-draft-only" id="id_slug" maxlength="255" required />'
|
||||
input_field_for_live_slug = '<input type="text" name="slug" value="hello-world" id="id_slug" maxlength="255" required />'
|
||||
input_field_for_draft_slug = '<input type="text" name="slug" value="revised-slug-in-draft-only" aria-describedby="panel-child-promote-child-for_search_engines-child-slug-helptext" id="id_slug" maxlength="255" required />'
|
||||
input_field_for_live_slug = '<input type="text" name="slug" value="hello-world" aria-describedby="panel-child-promote-child-for_search_engines-child-slug-helptext" id="id_slug" maxlength="255" required />'
|
||||
|
||||
# Status Link should be the live page (not revision)
|
||||
self.assertNotContains(
|
||||
|
@ -1011,8 +1014,8 @@ class TestPageEdit(TestCase, WagtailTestUtils):
|
|||
reverse("wagtailadmin_pages:edit", args=(self.single_event_page.id,))
|
||||
)
|
||||
|
||||
input_field_for_draft_slug = '<input type="text" name="slug" value="revised-slug-in-draft-only" id="id_slug" maxlength="255" required />'
|
||||
input_field_for_live_slug = '<input type="text" name="slug" value="mars-landing" id="id_slug" maxlength="255" required />'
|
||||
input_field_for_draft_slug = '<input type="text" name="slug" value="revised-slug-in-draft-only" aria-describedby="panel-child-promote-child-common_page_configuration-child-slug-helptext" id="id_slug" maxlength="255" required />'
|
||||
input_field_for_live_slug = '<input type="text" name="slug" value="mars-landing" aria-describedby="panel-child-promote-child-common_page_configuration-child-slug-helptext" id="id_slug" maxlength="255" required />'
|
||||
|
||||
# Status Link should be the live page (not revision)
|
||||
self.assertNotContains(
|
||||
|
@ -2053,9 +2056,8 @@ class TestValidationErrorMessages(TestCase, WagtailTestUtils):
|
|||
# the error should only appear once: against the field, not in the header message
|
||||
self.assertContains(
|
||||
response,
|
||||
"""<p class="error-message"><span>This field is required.</span></p>""",
|
||||
"""<svg width="16" height="16"><use href="#icon-cross"></use></svg>This field is required.""",
|
||||
count=1,
|
||||
html=True,
|
||||
)
|
||||
self.assertContains(response, "This field is required", count=1)
|
||||
|
||||
|
@ -2146,9 +2148,8 @@ class TestValidationErrorMessages(TestCase, WagtailTestUtils):
|
|||
# Error on title shown against the title field
|
||||
self.assertContains(
|
||||
response,
|
||||
"""<p class="error-message"><span>This field is required.</span></p>""",
|
||||
"""<svg width="16" height="16"><use href="#icon-cross"></use></svg>This field is required.""",
|
||||
count=1,
|
||||
html=True,
|
||||
)
|
||||
# Error on title shown in the header message
|
||||
self.assertContains(
|
||||
|
|
|
@ -387,7 +387,7 @@ class TestCompareRevisionsWithNonModelField(TestCase, WagtailTestUtils):
|
|||
response = self.client.get(edit_url)
|
||||
self.assertContains(
|
||||
response,
|
||||
'<input type="text" name="code" required id="id_code" maxlength="5" />',
|
||||
'<input type="text" name="code" aria-describedby="panel-child-content-child-code-helptext" required id="id_code" maxlength="5" />',
|
||||
html=True,
|
||||
)
|
||||
|
||||
|
|
|
@ -425,7 +425,7 @@ class TestTabbedInterface(TestCase, WagtailTestUtils):
|
|||
|
||||
# result should contain tab buttons
|
||||
self.assertIn(
|
||||
'<a id="tab-label-event-details" href="#tab-event-details" class="w-tabs__tab shiny" role="tab" aria-selected="false" tabindex="-1">',
|
||||
'<a id="tab-label-event_details" href="#tab-event_details" class="w-tabs__tab shiny" role="tab" aria-selected="false" tabindex="-1">',
|
||||
result,
|
||||
)
|
||||
self.assertIn(
|
||||
|
@ -434,7 +434,7 @@ class TestTabbedInterface(TestCase, WagtailTestUtils):
|
|||
)
|
||||
|
||||
# result should contain tab panels
|
||||
self.assertIn('aria-labelledby="tab-label-event-details"', result)
|
||||
self.assertIn('aria-labelledby="tab-label-event_details"', result)
|
||||
self.assertIn('aria-labelledby="tab-label-speakers"', result)
|
||||
|
||||
# result should contain rendered content from descendants
|
||||
|
@ -560,14 +560,17 @@ class TestObjectList(TestCase):
|
|||
result = object_list.render_html()
|
||||
|
||||
# result should contain ObjectList furniture
|
||||
self.assertIn('<ul class="objects">', result)
|
||||
self.assertIn('<div class="w-panel__header">', result)
|
||||
|
||||
# result should contain labels for children
|
||||
self.assertInHTML('<label for="id_date_from">Start date</label>', result)
|
||||
self.assertInHTML(
|
||||
'<label for="id_date_from">Start date<span class="w-error" aria-hidden="true">*</span></label>',
|
||||
result,
|
||||
)
|
||||
|
||||
# result should include help text for children
|
||||
self.assertInHTML(
|
||||
'<div class="object-help help"> <svg class="icon icon-help default" aria-hidden="true"><use href="#icon-help"></use></svg> Not required if event is on a single day</div>',
|
||||
'<p id="panel-child-date_to-helptext" class="w-help-text">Not required if event is on a single day</p>',
|
||||
result,
|
||||
)
|
||||
|
||||
|
@ -632,7 +635,7 @@ class TestFieldPanel(TestCase):
|
|||
end_date_panel_with_overridden_heading.bound_field.label, "New heading"
|
||||
)
|
||||
|
||||
def test_render_as_object(self):
|
||||
def test_render_html(self):
|
||||
form = self.EventPageForm(
|
||||
{
|
||||
"title": "Pontypridd sheepdog trials",
|
||||
|
@ -649,53 +652,17 @@ class TestFieldPanel(TestCase):
|
|||
form=form,
|
||||
request=self.request,
|
||||
)
|
||||
result = field_panel.render_as_object()
|
||||
result = field_panel.render_html()
|
||||
|
||||
# check that label appears as a legend in the 'object' wrapper,
|
||||
# but not as a field label (that would be provided by ObjectList instead)
|
||||
self.assertIn("<legend>End date</legend>", result)
|
||||
self.assertNotIn('<label for="id_date_to">End date:</label>', result)
|
||||
|
||||
# check that help text is not included (it's provided by ObjectList instead)
|
||||
self.assertNotIn("Not required if event is on a single day", result)
|
||||
|
||||
# check that the populated form field is included
|
||||
self.assertIn('value="2014-07-22"', result)
|
||||
|
||||
# there should be no errors on this field
|
||||
self.assertNotIn('<p class="error-message">', result)
|
||||
|
||||
def test_render_as_field(self):
|
||||
form = self.EventPageForm(
|
||||
{
|
||||
"title": "Pontypridd sheepdog trials",
|
||||
"date_from": "2014-07-20",
|
||||
"date_to": "2014-07-22",
|
||||
},
|
||||
instance=self.event,
|
||||
)
|
||||
|
||||
form.is_valid()
|
||||
|
||||
field_panel = self.end_date_panel.get_bound_panel(
|
||||
instance=self.event,
|
||||
form=form,
|
||||
request=self.request,
|
||||
)
|
||||
result = field_panel.render_as_field()
|
||||
|
||||
# check that label is output in the 'field' style
|
||||
self.assertIn('<label for="id_date_to">End date:</label>', result)
|
||||
self.assertNotIn("<legend>End date</legend>", result)
|
||||
|
||||
# check that help text is included
|
||||
self.assertIn("Not required if event is on a single day", result)
|
||||
|
||||
# check that the populated form field is included
|
||||
self.assertIn('value="2014-07-22"', result)
|
||||
|
||||
# there should be no errors on this field
|
||||
self.assertNotIn('<p class="error-message">', result)
|
||||
self.assertNotIn(
|
||||
'<svg width="16" height="16"><use href="#icon-cross"></use></svg>', result
|
||||
)
|
||||
|
||||
def test_required_fields(self):
|
||||
result = self.end_date_panel.get_form_options()["fields"]
|
||||
|
@ -718,10 +685,12 @@ class TestFieldPanel(TestCase):
|
|||
form=form,
|
||||
request=self.request,
|
||||
)
|
||||
result = field_panel.render_as_field()
|
||||
result = field_panel.render_html()
|
||||
|
||||
self.assertIn('<p class="error-message">', result)
|
||||
self.assertIn("<span>Enter a valid date.</span>", result)
|
||||
self.assertIn(
|
||||
'<svg width="16" height="16"><use href="#icon-cross"></use></svg>Enter a valid date.',
|
||||
result,
|
||||
)
|
||||
|
||||
def test_repr(self):
|
||||
form = self.EventPageForm()
|
||||
|
@ -766,7 +735,7 @@ class TestFieldRowPanel(TestCase):
|
|||
]
|
||||
).bind_to_model(EventPage)
|
||||
|
||||
def test_render_as_object(self):
|
||||
def test_render_html(self):
|
||||
form = self.EventPageForm(
|
||||
{
|
||||
"title": "Pontypridd sheepdog trials",
|
||||
|
@ -783,39 +752,18 @@ class TestFieldRowPanel(TestCase):
|
|||
form=form,
|
||||
request=self.request,
|
||||
)
|
||||
result = field_panel.render_as_object()
|
||||
|
||||
# check that the populated form field is included
|
||||
self.assertIn('value="2014-07-22"', result)
|
||||
|
||||
# there should be no errors on this field
|
||||
self.assertNotIn('<p class="error-message">', result)
|
||||
|
||||
def test_render_as_field(self):
|
||||
form = self.EventPageForm(
|
||||
{
|
||||
"title": "Pontypridd sheepdog trials",
|
||||
"date_from": "2014-07-20",
|
||||
"date_to": "2014-07-22",
|
||||
},
|
||||
instance=self.event,
|
||||
)
|
||||
|
||||
form.is_valid()
|
||||
|
||||
field_panel = self.dates_panel.get_bound_panel(
|
||||
instance=self.event,
|
||||
form=form,
|
||||
request=self.request,
|
||||
)
|
||||
result = field_panel.render_as_field()
|
||||
result = field_panel.render_html()
|
||||
|
||||
# check that label is output in the 'field' style
|
||||
self.assertIn('<label for="id_date_to">End date:</label>', result)
|
||||
self.assertNotIn("<legend>End date</legend>", result)
|
||||
self.assertIn(
|
||||
'<label for="id_date_to" class="w-field__label">End date</label>', result
|
||||
)
|
||||
|
||||
# check that label is overridden with the 'heading' argument
|
||||
self.assertIn('<label for="id_date_from">Start:</label>', result)
|
||||
self.assertIn(
|
||||
'<label for="id_date_from" class="w-field__label">Start<span class="w-error" aria-hidden="true">*</span></label>',
|
||||
result,
|
||||
)
|
||||
|
||||
# check that help text is included
|
||||
self.assertIn("Not required if event is on a single day", result)
|
||||
|
@ -824,7 +772,9 @@ class TestFieldRowPanel(TestCase):
|
|||
self.assertIn('value="2014-07-22"', result)
|
||||
|
||||
# there should be no errors on this field
|
||||
self.assertNotIn('<p class="error-message">', result)
|
||||
self.assertNotIn(
|
||||
'<svg width="16" height="16"><use href="#icon-cross"></use></svg>', result
|
||||
)
|
||||
|
||||
def test_error_message_is_rendered(self):
|
||||
form = self.EventPageForm(
|
||||
|
@ -843,55 +793,13 @@ class TestFieldRowPanel(TestCase):
|
|||
form=form,
|
||||
request=self.request,
|
||||
)
|
||||
result = field_panel.render_as_field()
|
||||
result = field_panel.render_html()
|
||||
|
||||
self.assertIn('<p class="error-message">', result)
|
||||
self.assertIn("<span>Enter a valid date.</span>", result)
|
||||
|
||||
def test_add_col_when_wrong_in_panel_def(self):
|
||||
form = self.EventPageForm(
|
||||
{
|
||||
"title": "Pontypridd sheepdog trials",
|
||||
"date_from": "2014-07-20",
|
||||
"date_to": "2014-07-33",
|
||||
},
|
||||
instance=self.event,
|
||||
self.assertIn(
|
||||
'<svg width="16" height="16"><use href="#icon-cross"></use></svg>Enter a valid date.',
|
||||
result,
|
||||
)
|
||||
|
||||
form.is_valid()
|
||||
|
||||
field_panel = self.dates_panel.get_bound_panel(
|
||||
instance=self.event,
|
||||
form=form,
|
||||
request=self.request,
|
||||
)
|
||||
|
||||
result = field_panel.render_as_field()
|
||||
|
||||
self.assertIn('<li class="field-col coltwo error date_field col6">', result)
|
||||
|
||||
def test_added_col_doesnt_change_siblings(self):
|
||||
form = self.EventPageForm(
|
||||
{
|
||||
"title": "Pontypridd sheepdog trials",
|
||||
"date_from": "2014-07-20",
|
||||
"date_to": "2014-07-33",
|
||||
},
|
||||
instance=self.event,
|
||||
)
|
||||
|
||||
form.is_valid()
|
||||
|
||||
field_panel = self.dates_panel.get_bound_panel(
|
||||
instance=self.event,
|
||||
form=form,
|
||||
request=self.request,
|
||||
)
|
||||
|
||||
result = field_panel.render_as_field()
|
||||
|
||||
self.assertIn('<li class="field-col col4', result)
|
||||
|
||||
|
||||
class TestFieldRowPanelWithChooser(TestCase):
|
||||
def setUp(self):
|
||||
|
@ -918,7 +826,7 @@ class TestFieldRowPanelWithChooser(TestCase):
|
|||
]
|
||||
).bind_to_model(EventPage)
|
||||
|
||||
def test_render_as_object(self):
|
||||
def test_render_html(self):
|
||||
form = self.EventPageForm(
|
||||
{
|
||||
"title": "Pontypridd sheepdog trials",
|
||||
|
@ -935,13 +843,15 @@ class TestFieldRowPanelWithChooser(TestCase):
|
|||
form=form,
|
||||
request=self.request,
|
||||
)
|
||||
result = field_panel.render_as_object()
|
||||
result = field_panel.render_html()
|
||||
|
||||
# check that the populated form field is included
|
||||
self.assertIn('value="2014-07-20"', result)
|
||||
|
||||
# there should be no errors on this field
|
||||
self.assertNotIn('<p class="error-message">', result)
|
||||
self.assertNotIn(
|
||||
'<svg width="16" height="16"><use href="#icon-cross"></use></svg>', result
|
||||
)
|
||||
|
||||
|
||||
class TestPageChooserPanel(TestCase):
|
||||
|
@ -977,7 +887,7 @@ class TestPageChooserPanel(TestCase):
|
|||
self.assertEqual(type(self.form.fields["page"].widget), AdminPageChooser)
|
||||
|
||||
def test_render_js_init(self):
|
||||
result = self.page_chooser_panel.render_as_field()
|
||||
result = self.page_chooser_panel.render_html()
|
||||
expected_js = 'new PageChooser("{id}", {parent}, {{"model_names": ["{model}"], "can_choose_root": false, "user_perms": null}});'.format(
|
||||
id="id_page", model="wagtailcore.page", parent=self.events_index_page.id
|
||||
)
|
||||
|
@ -997,7 +907,7 @@ class TestPageChooserPanel(TestCase):
|
|||
page_chooser_panel = my_page_chooser_panel.get_bound_panel(
|
||||
instance=self.test_instance, form=form, request=self.request
|
||||
)
|
||||
result = page_chooser_panel.render_as_field()
|
||||
result = page_chooser_panel.render_html()
|
||||
|
||||
# the canChooseRoot flag on PageChooser should now be true
|
||||
expected_js = 'new PageChooser("{id}", {parent}, {{"model_names": ["{model}"], "can_choose_root": true, "user_perms": null}});'.format(
|
||||
|
@ -1005,9 +915,11 @@ class TestPageChooserPanel(TestCase):
|
|||
)
|
||||
self.assertIn(expected_js, result)
|
||||
|
||||
def test_render_as_field(self):
|
||||
result = self.page_chooser_panel.render_as_field()
|
||||
self.assertIn('<p class="help">help text</p>', result)
|
||||
def test_render_html(self):
|
||||
result = self.page_chooser_panel.render_html()
|
||||
self.assertIn(
|
||||
'<p id="panel-helptext" class="w-help-text">help text</p>', result
|
||||
)
|
||||
self.assertIn('<span class="title">Christmas</span>', result)
|
||||
self.assertIn(
|
||||
'<a href="/admin/pages/%d/edit/" class="edit-link button button-small button-secondary" target="_blank" rel="noreferrer">'
|
||||
|
@ -1021,9 +933,11 @@ class TestPageChooserPanel(TestCase):
|
|||
page_chooser_panel = self.my_page_chooser_panel.get_bound_panel(
|
||||
instance=test_instance, form=form, request=self.request
|
||||
)
|
||||
result = page_chooser_panel.render_as_field()
|
||||
result = page_chooser_panel.render_html()
|
||||
|
||||
self.assertIn('<p class="help">help text</p>', result)
|
||||
self.assertIn(
|
||||
'<p id="panel-helptext" class="w-help-text">help text</p>', result
|
||||
)
|
||||
self.assertIn('<span class="title"></span>', result)
|
||||
self.assertIn("Choose a page", result)
|
||||
|
||||
|
@ -1035,7 +949,8 @@ class TestPageChooserPanel(TestCase):
|
|||
instance=self.test_instance, form=form, request=self.request
|
||||
)
|
||||
self.assertIn(
|
||||
"<span>This field is required.</span>", page_chooser_panel.render_as_field()
|
||||
"""<svg width="16" height="16"><use href="#icon-cross"></use></svg>This field is required.""",
|
||||
page_chooser_panel.render_html(),
|
||||
)
|
||||
|
||||
def test_override_page_type(self):
|
||||
|
@ -1051,8 +966,16 @@ class TestPageChooserPanel(TestCase):
|
|||
instance=self.test_instance, form=form, request=self.request
|
||||
)
|
||||
|
||||
<<<<<<< HEAD
|
||||
result = page_chooser_panel.render_as_field()
|
||||
expected_js = 'new PageChooser("{id}", {parent}, {{"model_names": ["{model}"], "can_choose_root": false, "user_perms": null}});'.format(
|
||||
||||||| parent of 2346b6cb88 (Drop render_as_object / render_as_field distinction)
|
||||
result = page_chooser_panel.render_as_field()
|
||||
expected_js = 'createPageChooser("{id}", {parent}, {{"model_names": ["{model}"], "can_choose_root": false, "user_perms": null}});'.format(
|
||||
=======
|
||||
result = page_chooser_panel.render_html()
|
||||
expected_js = 'createPageChooser("{id}", {parent}, {{"model_names": ["{model}"], "can_choose_root": false, "user_perms": null}});'.format(
|
||||
>>>>>>> 2346b6cb88 (Drop render_as_object / render_as_field distinction)
|
||||
id="id_page", model="tests.eventpage", parent=self.events_index_page.id
|
||||
)
|
||||
|
||||
|
@ -1071,8 +994,16 @@ class TestPageChooserPanel(TestCase):
|
|||
instance=self.test_instance, form=form, request=self.request
|
||||
)
|
||||
|
||||
<<<<<<< HEAD
|
||||
result = page_chooser_panel.render_as_field()
|
||||
expected_js = 'new PageChooser("{id}", {parent}, {{"model_names": ["{model}"], "can_choose_root": false, "user_perms": null}});'.format(
|
||||
||||||| parent of 2346b6cb88 (Drop render_as_object / render_as_field distinction)
|
||||
result = page_chooser_panel.render_as_field()
|
||||
expected_js = 'createPageChooser("{id}", {parent}, {{"model_names": ["{model}"], "can_choose_root": false, "user_perms": null}});'.format(
|
||||
=======
|
||||
result = page_chooser_panel.render_html()
|
||||
expected_js = 'createPageChooser("{id}", {parent}, {{"model_names": ["{model}"], "can_choose_root": false, "user_perms": null}});'.format(
|
||||
>>>>>>> 2346b6cb88 (Drop render_as_object / render_as_field distinction)
|
||||
id="id_page", model="tests.eventpage", parent=self.events_index_page.id
|
||||
)
|
||||
|
||||
|
@ -1128,13 +1059,23 @@ class TestInlinePanel(TestCase, WagtailTestUtils):
|
|||
instance=event_page, form=form, request=self.request
|
||||
)
|
||||
|
||||
result = panel.render_as_field()
|
||||
result = panel.render_html()
|
||||
|
||||
self.assertIn('<li class="object classname-for-speakers">', result)
|
||||
self.assertIn('<label for="id_speakers-0-first_name">Name:</label>', result)
|
||||
# FIXME: reinstate when we pass classnames to the template again
|
||||
# self.assertIn('<li class="object classname-for-speakers">', result)
|
||||
self.assertIn(
|
||||
'<label for="id_speakers-0-first_name" class="w-field__label">Name</label>',
|
||||
result,
|
||||
)
|
||||
self.assertIn('value="Father"', result)
|
||||
self.assertIn('<label for="id_speakers-0-last_name">Surname:</label>', result)
|
||||
self.assertIn('<label for="id_speakers-0-image">Image:</label>', result)
|
||||
self.assertIn(
|
||||
'<label for="id_speakers-0-last_name" class="w-field__label">Surname</label>',
|
||||
result,
|
||||
)
|
||||
self.assertIn(
|
||||
'<label for="id_speakers-0-image" class="w-field__label">Image</label>',
|
||||
result,
|
||||
)
|
||||
self.assertIn("Choose an image", result)
|
||||
|
||||
# rendered panel must also contain hidden fields for id, DELETE and ORDER
|
||||
|
@ -1194,10 +1135,13 @@ class TestInlinePanel(TestCase, WagtailTestUtils):
|
|||
instance=event_page, form=form, request=self.request
|
||||
)
|
||||
|
||||
result = panel.render_as_field()
|
||||
result = panel.render_html()
|
||||
|
||||
# rendered panel should contain first_name rendered as a text area, but no last_name field
|
||||
self.assertIn('<label for="id_speakers-0-first_name">Name:</label>', result)
|
||||
self.assertIn(
|
||||
'<label for="id_speakers-0-first_name" class="w-field__label">Name</label>',
|
||||
result,
|
||||
)
|
||||
self.assertIn("Father</textarea>", result)
|
||||
self.assertNotIn(
|
||||
'<label for="id_speakers-0-last_name">Surname:</label>', result
|
||||
|
@ -1211,7 +1155,7 @@ class TestInlinePanel(TestCase, WagtailTestUtils):
|
|||
allow_extra_attrs=True,
|
||||
)
|
||||
|
||||
self.assertIn('<label for="id_speakers-0-image">Image:</label>', result)
|
||||
# self.assertIn('<label for="id_speakers-0-image">Image:</label>', result)
|
||||
self.assertIn("Choose an image", result)
|
||||
|
||||
# rendered panel must also contain hidden fields for id, DELETE and ORDER
|
||||
|
|
|
@ -2460,7 +2460,7 @@ class TestWorkflowStatus(TestCase, WagtailTestUtils):
|
|||
response = self.client.get(self.edit_url)
|
||||
|
||||
needle = "This page is awaiting <b>'test_task_1'</b> in the <b>'test_workflow'</b> workflow. Only reviewers for this task can edit the page."
|
||||
self.assertContains(response, needle)
|
||||
self.assertContains(response, needle, count=1)
|
||||
|
||||
self.login(self.moderator)
|
||||
response = self.client.get(self.edit_url)
|
||||
|
|
|
@ -413,9 +413,8 @@ class TestCreateView(TestCase, WagtailTestUtils):
|
|||
self.assertFormError(response, "form", "title", "This field is required.")
|
||||
self.assertContains(
|
||||
response,
|
||||
"""<p class="error-message"><span>This field is required.</span></p>""",
|
||||
"""<svg width="16" height="16"><use href="#icon-cross"></use></svg>This field is required.""",
|
||||
count=1,
|
||||
html=True,
|
||||
)
|
||||
|
||||
def test_exclude_passed_to_extract_panel_definitions(self):
|
||||
|
@ -687,9 +686,8 @@ class TestEditView(TestCase, WagtailTestUtils):
|
|||
self.assertFormError(response, "form", "title", "This field is required.")
|
||||
self.assertContains(
|
||||
response,
|
||||
"""<p class="error-message"><span>This field is required.</span></p>""",
|
||||
"""<svg width="16" height="16"><use href="#icon-cross"></use></svg>This field is required.""",
|
||||
count=1,
|
||||
html=True,
|
||||
)
|
||||
|
||||
def test_exclude_passed_to_extract_panel_definitions(self):
|
||||
|
|
|
@ -94,9 +94,8 @@ class TestSiteSettingCreateView(BaseTestSiteSettingView):
|
|||
self.assertContains(response, "The setting could not be saved due to errors.")
|
||||
self.assertContains(
|
||||
response,
|
||||
"""<p class="error-message"><span>This field is required.</span></p>""",
|
||||
"""<svg width="16" height="16"><use href="#icon-cross"></use></svg>This field is required.""",
|
||||
count=2,
|
||||
html=True,
|
||||
)
|
||||
self.assertContains(response, "This field is required", count=2)
|
||||
|
||||
|
@ -148,9 +147,8 @@ class TestSiteSettingEditView(BaseTestSiteSettingView):
|
|||
self.assertContains(response, "The setting could not be saved due to errors.")
|
||||
self.assertContains(
|
||||
response,
|
||||
"""<p class="error-message"><span>This field is required.</span></p>""",
|
||||
"""<svg width="16" height="16"><use href="#icon-cross"></use></svg>This field is required.""",
|
||||
count=2,
|
||||
html=True,
|
||||
)
|
||||
self.assertContains(response, "This field is required", count=2)
|
||||
|
||||
|
|
|
@ -525,9 +525,8 @@ class TestSnippetCreateView(TestCase, WagtailTestUtils):
|
|||
self.assertContains(response, "The snippet could not be created due to errors.")
|
||||
self.assertContains(
|
||||
response,
|
||||
"""<p class="error-message"><span>This field is required.</span></p>""",
|
||||
"""<svg width="16" height="16"><use href="#icon-cross"></use></svg>This field is required.""",
|
||||
count=1,
|
||||
html=True,
|
||||
)
|
||||
self.assertContains(response, "This field is required", count=1)
|
||||
|
||||
|
@ -934,9 +933,8 @@ class TestSnippetEditView(BaseTestSnippetEditView):
|
|||
self.assertContains(response, "The snippet could not be saved due to errors.")
|
||||
self.assertContains(
|
||||
response,
|
||||
"""<p class="error-message"><span>This field is required.</span></p>""",
|
||||
"""<svg width="16" height="16"><use href="#icon-cross"></use></svg>This field is required.""",
|
||||
count=1,
|
||||
html=True,
|
||||
)
|
||||
self.assertContains(response, "This field is required", count=1)
|
||||
|
||||
|
@ -1757,8 +1755,8 @@ class TestSnippetChooserPanel(TestCase, WagtailTestUtils):
|
|||
if getattr(panel, "field_name", None) == "advert"
|
||||
][0]
|
||||
|
||||
def test_render_as_field(self):
|
||||
field_html = self.snippet_chooser_panel.render_as_field()
|
||||
def test_render_html(self):
|
||||
field_html = self.snippet_chooser_panel.render_html()
|
||||
self.assertIn(self.advert_text, field_html)
|
||||
self.assertIn("Choose advert", field_html)
|
||||
self.assertIn("Choose another advert", field_html)
|
||||
|
@ -1776,14 +1774,14 @@ class TestSnippetChooserPanel(TestCase, WagtailTestUtils):
|
|||
if getattr(panel, "field_name", None) == "advert"
|
||||
][0]
|
||||
|
||||
field_html = snippet_chooser_panel.render_as_field()
|
||||
field_html = snippet_chooser_panel.render_html()
|
||||
self.assertIn("Choose advert", field_html)
|
||||
self.assertIn("Choose another advert", field_html)
|
||||
|
||||
def test_render_js(self):
|
||||
self.assertIn(
|
||||
'new SnippetChooser("id_advert");',
|
||||
self.snippet_chooser_panel.render_as_field(),
|
||||
self.snippet_chooser_panel.render_html(),
|
||||
)
|
||||
|
||||
def test_target_model_autodetected(self):
|
||||
|
@ -3120,8 +3118,8 @@ class TestSnippetChooserPanelWithCustomPrimaryKey(TestCase, WagtailTestUtils):
|
|||
if getattr(panel, "field_name", None) == "advertwithcustomprimarykey"
|
||||
][0]
|
||||
|
||||
def test_render_as_field(self):
|
||||
field_html = self.snippet_chooser_panel.render_as_field()
|
||||
def test_render_html(self):
|
||||
field_html = self.snippet_chooser_panel.render_html()
|
||||
self.assertIn(self.advert_text, field_html)
|
||||
self.assertIn("Choose advert with custom primary key", field_html)
|
||||
self.assertIn("Choose another advert with custom primary key", field_html)
|
||||
|
@ -3139,14 +3137,14 @@ class TestSnippetChooserPanelWithCustomPrimaryKey(TestCase, WagtailTestUtils):
|
|||
if getattr(panel, "field_name", None) == "advertwithcustomprimarykey"
|
||||
][0]
|
||||
|
||||
field_html = snippet_chooser_panel.render_as_field()
|
||||
field_html = snippet_chooser_panel.render_html()
|
||||
self.assertIn("Choose advert with custom primary key", field_html)
|
||||
self.assertIn("Choose another advert with custom primary key", field_html)
|
||||
|
||||
def test_render_js(self):
|
||||
self.assertIn(
|
||||
'new SnippetChooser("id_advertwithcustomprimarykey");',
|
||||
self.snippet_chooser_panel.render_as_field(),
|
||||
self.snippet_chooser_panel.render_html(),
|
||||
)
|
||||
|
||||
def test_target_model_autodetected(self):
|
||||
|
|
|
@ -1084,7 +1084,7 @@ StandardChild.edit_handler = TabbedInterface(
|
|||
),
|
||||
ObjectList(
|
||||
[
|
||||
HelpPanel("remember to check for asteroids"),
|
||||
HelpPanel("Watch out for asteroids"),
|
||||
],
|
||||
heading="Dinosaurs",
|
||||
),
|
||||
|
|
Ładowanie…
Reference in New Issue