Repository: django-cms/django-cms

Issue:
example for show_sub_menu template tag does not work
https://django-cms.readthedocs.org/en/latest/advanced/templatetags.html#show-sub-menu

The last example does not work. The string for the template will get converted into an integer and it crashes. Unless i dont get something, you have to provide 2 more attributes: root_level and nephews before the template so you get something like:

``` python
<ul>
    {% show_sub_menu 1 0 100 "myapp/submenu.html" %}
</ul>
```



Discussion:
yep docs are broken it seams.

by the way, because of this, the template tag feels kinda broken. in my usecaes, dont want to tell the template tag the "root_level". the root level might change depending on the page in which the template with the template tag is used. 

this works if i dont specify the custom template and dont give the tag the root_level

how would you fix it?

the problem has something todo with the definition the argument:

``` python
IntegerArgument('root_level', default=None, required=False),
```

None for an Integer as default parameter is wrong. In line 213 of the file (https://github.com/divio/django-cms/blob/develop/menus/templatetags/menu_tags.py#L213) the root_level is checked for None but i can not provide None as a parameter of the tag because None is not a valid Integer :)

If root_level is not an IntegerArgument but an Arguement, would None and an Integer be a valid value?

``` python
<ul>
    {% show_sub_menu 100 None 100 "myapp/submenu.html" %}
</ul>
```

 This would be the result and might be ok ... because we would just provide the default parameters.

Not really keen on changing argument type, but looks like the only choice not to break backward compat.


Resolving patch:
diff --git a/menus/templatetags/menu_tags.py b/menus/templatetags/menu_tags.py
--- a/menus/templatetags/menu_tags.py
+++ b/menus/templatetags/menu_tags.py
@@ -191,12 +191,16 @@ class ShowSubMenu(InclusionTag):
 
     options = Options(
         IntegerArgument('levels', default=100, required=False),
-        IntegerArgument('root_level', default=None, required=False),
+        Argument('root_level', default=None, required=False),
         IntegerArgument('nephews', default=100, required=False),
         Argument('template', default='menu/sub_menu.html', required=False),
     )
 
     def get_context(self, context, levels, root_level, nephews, template):
+        # Django 1.4 doesn't accept 'None' as a tag value and resolve to ''
+        # So we need to force it to None again
+        if not root_level and root_level != 0:
+            root_level = None
         try:
             # If there's an exception (500), default context_processors may not be called.
             request = context['request']


Test patch:
diff --git a/cms/tests/menu.py b/cms/tests/menu.py
--- a/cms/tests/menu.py
+++ b/cms/tests/menu.py
@@ -108,6 +108,14 @@ def test_show_submenu_nephews(self):
         self.assertEqual(len(nodes[1].children), 1)
         self.assertEqual(len(nodes[1].children[0].children), 1)
 
+    def test_show_submenu_template_root_level_none_no_nephew_limit(self):
+        context = self.get_context(path=self.get_page(1).get_absolute_url())
+        tpl = Template("{% load menu_tags %}{% show_sub_menu 100 None 100 %}")
+        tpl.render(context)
+        nodes = context["children"]
+        # default nephew limit, P2 and P9 in the nodes list
+        self.assertEqual(len(nodes), 2)
+
 
 class FixturesMenuTests(MenusFixture, BaseMenuTest):
     """
@@ -312,7 +320,18 @@ def test_show_submenu(self):
         # P2 is selected
         self.assertTrue(nodes[0].children[0].selected)
 
-        
+    def test_show_submenu_template_root_level_none(self):
+        context = self.get_context(path=self.get_page(1).get_absolute_url())
+        tpl = Template("{% load menu_tags %}{% show_sub_menu 100 None 1 %}")
+        tpl.render(context)
+        nodes = context["children"]
+        # First node is P2 (P1 children) thus not selected
+        self.assertFalse(nodes[0].selected)
+        # nephew limit of 1, so only P2 is the nodes list
+        self.assertEqual(len(nodes), 1)
+        # P3 is a child of P2, but not in nodes list
+        self.assertTrue(nodes[0].children)
+
     def test_show_breadcrumb(self):
         context = self.get_context(path=self.get_page(3).get_absolute_url())
         tpl = Template("{% load menu_tags %}{% show_breadcrumb %}")