menu: include parenthood in subentries hint class logic (#86069)
gitea/combo/pipeline/head This commit looks good Details

This commit is contained in:
Paul Marillonnet 2024-01-24 11:40:31 +01:00
parent 17e7166841
commit e06ea594d6
3 changed files with 96 additions and 2 deletions

View File

@ -355,6 +355,16 @@ class Page(models.Model):
return self._children
return Page.objects.filter(parent_id=self.id)
def has_navigable_children(self):
if hasattr(self, '_children'):
for child in self._children:
if not getattr(child, 'exclude_from_navigation', True):
return True
return Page.objects.filter(
parent_id=self.id,
exclude_from_navigation=False,
).exists()
def has_children(self):
if hasattr(self, '_children'):
return bool(self._children)

View File

@ -3,7 +3,7 @@
<ul class="{{ is_submenu|yesno:"submenu,menu" }} {% if is_submenu %}hide-on-escape{% endif %}">
{% spaceless %}
{% for menuitem in menuitems %}
<li data-menu-page-id="{{ menuitem.page.id }}" class="{% if depth > 1 %}contains-hidden-elements{% endif %} {{ is_submenu|yesno:"submenu,menu" }}--item menu-{{ menuitem.page.slug }} {% if menuitem.selected %}selected{% endif %}">
<li data-menu-page-id="{{ menuitem.page.id }}" class="{% if depth > 1 and menuitem.page.has_navigable_children %}contains-subentries{% endif %} {{ is_submenu|yesno:"submenu,menu" }}--item menu-{{ menuitem.page.slug }} {% if menuitem.selected %}selected{% endif %}">
<a
{% if menuitem.selected %}title="{{ menuitem.page.title }} - {% trans "active page" %}"{% endif %}
href="{% page_absolute_url menuitem.page %}"

View File

@ -15,6 +15,7 @@ from django.test import override_settings
from django.test.utils import CaptureQueriesContext
from django.urls import reverse
from django.utils.http import quote
from lxml import etree
try:
import mellon # pylint: disable=unused-import
@ -655,7 +656,9 @@ def test_repeated_slug(app):
assert 'Grand child of second (named third)' in resp.text
def test_menu(app):
def test_menu(app, admin_user):
from combo.public.menu import render_menu
Page.objects.all().delete()
page = Page.objects.create(
title='Page1', slug='index', template_name='standard', exclude_from_navigation=False
@ -669,6 +672,87 @@ def test_menu(app):
assert 'data-menu-page-id="%s"' % page.id
assert 'menu-page2' in resp.text
assert 'menu-page3' in resp.text
assert not resp.pyquery('.contains-subentries')
page4 = Page.objects.create(
title='Page4', slug='page4', template_name='standard', parent=page, exclude_from_navigation=False
)
page5 = Page.objects.create(
title='Page5', slug='page5', template_name='standard', parent=page4, exclude_from_navigation=False
)
page6 = Page.objects.create(
title='Page6', slug='page6', template_name='standard', parent=page4, exclude_from_navigation=False
)
page7 = Page.objects.create(
title='Page7', slug='page7', template_name='standard', parent=page5, exclude_from_navigation=False
)
resp = app.get('/', status=200)
# default menu depth is 1, children not rendered therefore not marked as potentially hidden
assert not resp.pyquery('.contains-subentries')
request = mock.Mock()
request.user = admin_user
context = {
'request': request,
'page': page,
'root_page': page,
}
# on the contrary, Publik templates use the custom show_menu templatetag calling the render_menu util directly:
rendered = render_menu(
context=context,
level=1,
root_page=None,
depth=3, # dig deeper & retrieve Page4's hidden children in its own submenu
ignore_visibility=False,
)
contains_children = [page4.id, page5.id]
childfree = [page6.id, page7.id]
descendants = list(etree.fromstring(rendered).iterdescendants())
assert descendants
for element in descendants:
# check that only parent pages are classified as containers of hidden elements
assert bool(int(element.attrib.get('data-menu-page-id', '-1')) in contains_children) is bool(
'contains-subentries' in element.attrib.get('class', '')
)
if (page_id := int(element.attrib.get('data-menu-page-id', '-1'))) in contains_children:
contains_children.remove(page_id)
elif page_id in childfree:
childfree.remove(page_id)
# check that all pages have been rendered and parsed in the previous assert
assert not contains_children
assert not childfree
# page7 is now excluded from navigation, as it is page5's only child, the latter
# should not bear the "contains-subentries" class
page7.exclude_from_navigation = True
page7.save()
rendered = render_menu(
context=context,
level=1,
root_page=None,
depth=3,
ignore_visibility=False,
)
contains_children = [page4.id]
childfree = [page5.id, page6.id]
descendants = list(etree.fromstring(rendered).iterdescendants())
assert descendants
for element in descendants:
assert bool(int(element.attrib.get('data-menu-page-id', '-1')) in contains_children) is bool(
'contains-subentries' in element.attrib.get('class', '')
)
if (page_id := int(element.attrib.get('data-menu-page-id', '-1'))) in contains_children:
contains_children.remove(page_id)
elif page_id in childfree:
childfree.remove(page_id)
assert not contains_children
assert not childfree
def test_404(app):