angrybeanie_wagtail/env/lib/python3.12/site-packages/wagtail/admin/panels/group.py

178 lines
6.1 KiB
Python
Raw Permalink Normal View History

2025-07-25 21:32:16 +10:00
from django.forms import Media
from django.utils.functional import cached_property
from .base import Panel
class PanelGroup(Panel):
"""
Abstract class for panels that manage a set of sub-panels.
Concrete subclasses must attach a 'children' property
"""
def __init__(self, children=(), *args, **kwargs):
permission = kwargs.pop("permission", None)
super().__init__(*args, **kwargs)
self.children = children
self.permission = permission
def clone_kwargs(self):
kwargs = super().clone_kwargs()
kwargs["children"] = self.children
kwargs["permission"] = self.permission
return kwargs
def get_form_options(self):
if self.model is None:
raise AttributeError(
"%s is not bound to a model yet. Use `.bind_to_model(model)` "
"before using this method." % self.__class__.__name__
)
options = {}
# Merge in form options from each child in turn, combining values that are types that we
# know how to combine (i.e. lists, dicts and sets)
for child in self.children:
child_options = child.get_form_options()
for key, new_val in child_options.items():
if key not in options:
# if val is a known mutable container type that we're going to merge subsequent
# child values into, create a copy so that we don't risk that change leaking
# back into the child's internal state
if (
isinstance(new_val, list)
or isinstance(new_val, dict)
or isinstance(new_val, set)
):
options[key] = new_val.copy()
else:
options[key] = new_val
else:
current_val = options[key]
if isinstance(current_val, list) and isinstance(
new_val, (list, tuple)
):
current_val.extend(new_val)
elif isinstance(current_val, tuple) and isinstance(
new_val, (list, tuple)
):
options[key] = list(current_val).extend(new_val)
elif isinstance(current_val, dict) and isinstance(new_val, dict):
current_val.update(new_val)
elif isinstance(current_val, set) and isinstance(new_val, set):
current_val.update(new_val)
else:
raise ValueError(
"Don't know how to merge values %r and %r for form option %r"
% (current_val, new_val, key)
)
return options
def on_model_bound(self):
from .model_utils import expand_panel_list
child_panels = expand_panel_list(self.model, self.children)
self.children = [child.bind_to_model(self.model) for child in child_panels]
@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,
prefix=(f"{self.prefix}-child-{identifier}"),
)
for child, identifier in zip(
self.panel.children, self.panel.child_identifiers
)
]
@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 show_panel_furniture(self):
return any(child.show_panel_furniture() for child in self.children)
def is_shown(self):
"""
Check permissions on the panel group overall then check if any children
are shown.
"""
if self.panel.permission:
if not self.request.user.has_perm(self.panel.permission):
return False
return any(child.is_shown() for child in self.children)
@property
def media(self):
media = Media()
for item in self.visible_children:
media += item.media
return media
def get_comparison(self):
comparators = []
for child in self.children:
comparators.extend(child.get_comparison())
return comparators
class TabbedInterface(PanelGroup):
class BoundPanel(PanelGroup.BoundPanel):
template_name = "wagtailadmin/panels/tabbed_interface.html"
class ObjectList(PanelGroup):
class BoundPanel(PanelGroup.BoundPanel):
template_name = "wagtailadmin/panels/object_list.html"
class FieldRowPanel(PanelGroup):
class BoundPanel(PanelGroup.BoundPanel):
template_name = "wagtailadmin/panels/field_row_panel.html"
class MultiFieldPanel(PanelGroup):
class BoundPanel(PanelGroup.BoundPanel):
template_name = "wagtailadmin/panels/multi_field_panel.html"