Skip to content
Snippets Groups Projects
Commit a8b24371 authored by Milton Lenis's avatar Milton Lenis
Browse files

Merge branch 'master' of github.com:LaLogiaDePython/django-menu-generator

parents ccecab7a 5a4149f3
No related branches found
No related tags found
No related merge requests found
...@@ -7,4 +7,4 @@ Val Kneeman under the name [django-menuware](https://github.com/un33k/django-men ...@@ -7,4 +7,4 @@ Val Kneeman under the name [django-menuware](https://github.com/un33k/django-men
* Milton Lenis - miltonln04@gmail.com * Milton Lenis - miltonln04@gmail.com
## Contributors: ## Contributors:
None yet. Why not be the first? * Jonathan Weth - dev@jonathanweth.de
\ No newline at end of file
...@@ -4,3 +4,8 @@ Authors ...@@ -4,3 +4,8 @@ Authors
`Milton Lenis <https://github.com/MiltonLn>`__ - miltonln04@gmail.com `Milton Lenis <https://github.com/MiltonLn>`__ - miltonln04@gmail.com
`Juan Diego García <https://github.com/yamijuan>`__ - juandgoc@gmail.com `Juan Diego García <https://github.com/yamijuan>`__ - juandgoc@gmail.com
Contributors
============
`Jonathan Weth <https://github.com/hansegucker>`__ - dev@jonathanweth.de
...@@ -10,6 +10,7 @@ Django Menu Generator uses python dictionaries to represent the menu items, usua ...@@ -10,6 +10,7 @@ Django Menu Generator uses python dictionaries to represent the menu items, usua
"icon_class": 'some icon class', "icon_class": 'some icon class',
"url": URL spec, "url": URL spec,
"root": True | False, "root": True | False,
"related_urls": [ list of related URLs ],
"validators": [ list of validators ], "validators": [ list of validators ],
"submenu": Dictionary like this "submenu": Dictionary like this
} }
...@@ -22,6 +23,8 @@ Where each key is as follows: ...@@ -22,6 +23,8 @@ Where each key is as follows:
- ``url``: See :doc:`urls` - ``url``: See :doc:`urls`
- ``related_urls``: If one of this URLs is part of the path on the currently opened page, the menu item will be marked as selected (format of URLs like described at :doc:`urls`)
- ``root``: A flag to indicate this item is the root of a path, with this you can correctly mark nested menus as selected. - ``root``: A flag to indicate this item is the root of a path, with this you can correctly mark nested menus as selected.
- ``validators``: See :doc:`validators` - ``validators``: See :doc:`validators`
......
...@@ -2,7 +2,7 @@ import copy ...@@ -2,7 +2,7 @@ import copy
import django import django
from django.core.exceptions import ImproperlyConfigured from django.core.exceptions import ImproperlyConfigured
from .utils import get_callable from .utils import get_callable, parse_url
if django.VERSION >= (1, 10): # pragma: no cover if django.VERSION >= (1, 10): # pragma: no cover
from django.urls import reverse, NoReverseMatch from django.urls import reverse, NoReverseMatch
...@@ -74,22 +74,33 @@ class MenuBase(object): ...@@ -74,22 +74,33 @@ class MenuBase(object):
Given a menu item dictionary, it returns the URL or an empty string. Given a menu item dictionary, it returns the URL or an empty string.
""" """
url = item_dict.get('url', '') url = item_dict.get('url', '')
try: return parse_url(url)
final_url = reverse(**url) if type(url) is dict else reverse(url)
except NoReverseMatch: def _get_related_urls(self, item_dict):
final_url = url """
return final_url Given a menu item dictionary, it returns the relateds URLs or an empty list.
"""
related_urls = item_dict.get('related_urls', [])
return [parse_url(url) for url in related_urls]
def _is_selected(self, item_dict): def _is_selected(self, item_dict):
""" """
Given a menu item dictionary, it returns true if `url` is on path, Given a menu item dictionary, it returns true if `url` is on path,
unless the item is marked as a root, in which case returns true if `url` is part of path. unless the item is marked as a root, in which case returns true if `url` is part of path.
If related URLS are given, it also returns true if one of the related URLS is part of path.
""" """
url = self._get_url(item_dict) url = self._get_url(item_dict)
if self._is_root(item_dict): if self._is_root(item_dict) and url in self.path:
return url in self.path return True
elif url == self.path:
return True
else: else:
return url == self.path # Go through all related URLs and test
for related_url in self._get_related_urls(item_dict):
if related_url in self.path:
return True
return False
def _is_root(self, item_dict): def _is_root(self, item_dict):
""" """
......
...@@ -261,3 +261,48 @@ class MenuTestCase(TestCase): ...@@ -261,3 +261,48 @@ class MenuTestCase(TestCase):
nav = self.menu.generate_menu(list_dict) nav = self.menu.generate_menu(list_dict)
self.assertEqual(len(nav), 1) self.assertEqual(len(nav), 1)
self.assertIsNone(nav[0]["submenu"]) self.assertIsNone(nav[0]["submenu"])
def test_generate_menu_selected_related_urls_simple(self):
self.request.user = TestUser(authenticated=True)
self.request.path = "/persons/1/"
self.menu.save_user_state(self.request)
list_dict = [
{
"name": "parent1",
"url": "/user/account/",
"related_urls": ["/persons/", "/groups/"],
}
]
nav = self.menu.generate_menu(list_dict)
self.assertEqual(len(nav), 1)
self.assertEqual(nav[0]["selected"], True)
def test_generate_menu_selected_related_urls_submenu(self):
self.request.user = TestUser(authenticated=True)
self.request.path = "/persons/1/"
self.menu.save_user_state(self.request)
list_dict = [
{
"name": "parent1",
"url": "/user/account/",
"submenu": [
{
"name": "child1",
"url": '/user/account/profile/',
"related_urls": ["/persons/"]
},
{
"name": "child2",
"url": 'named_url',
"related_urls": ["/groups/"]
},
],
}
]
nav = self.menu.generate_menu(list_dict)
self.assertEqual(len(nav), 1)
self.assertEqual(nav[0]["selected"], True)
self.assertEqual(nav[0]["submenu"][0]["selected"], True)
self.assertEqual(nav[0]["submenu"][1]["selected"], False)
\ No newline at end of file
from importlib import import_module from importlib import import_module
import django
from django.apps import apps from django.apps import apps
from django.core.exceptions import ImproperlyConfigured from django.core.exceptions import ImproperlyConfigured
if django.VERSION >= (1, 10): # pragma: no cover
from django.urls import reverse, NoReverseMatch
else:
from django.core.urlresolvers import reverse, NoReverseMatch
def get_callable(func_or_path): def get_callable(func_or_path):
""" """
...@@ -35,3 +40,14 @@ def clean_app_config(app_path): ...@@ -35,3 +40,14 @@ def clean_app_config(app_path):
f"The application {app_path} is not in the configured apps or does" + f"The application {app_path} is not in the configured apps or does" +
"not have the pattern app.apps.AppConfig" "not have the pattern app.apps.AppConfig"
) )
def parse_url(url):
"""
Returns concrete URL for a menu dict URL attribute.
"""
try:
final_url = reverse(**url) if type(url) is dict else reverse(url)
except NoReverseMatch:
final_url = url
return final_url
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment