Repository: django-cms/django-cms

Issue:
Allow menu to be edited using
It would be nice to have something like:

{% edit_model_block menu %}
{% show_menu 1 5 0 1 "includes/menu/navigation.html" %}
{% endedit_model_block %}



Discussion:
Could you clarify the intent of this syntax? What would you like to edit?

So I'd basically create a div around the from the menu generated code so I can double click to edit it. It should than show the pagetree.

I see, it's doable with little effort, but I'd propose a slightly different syntax::

```
{% render_model_block request.current_page 'menu' %}
    {% show_menu 1 5 0 1 "includes/menu/navigation.html" %}
{% endrender_model_block %}
```

We should make the users aware of some issues, though:
- Menu is made of different items (not only pages in the pagetree); while this should be clear for all CMS users, still it might confuse some who edit it via the frontend editor; a proper documentation of this it's all we can do;
- Depending on the menu layout the menu item clickable area might shadow the plugin-editing one; we might add documentation for this so the developer will take this into account when using this templatetag
- As some plugins to edit menu configuration exists, again these trigger event conflict with this feature; we should document this too


Resolving patch:
diff --git a/cms/templatetags/cms_tags.py b/cms/templatetags/cms_tags.py
--- a/cms/templatetags/cms_tags.py
+++ b/cms/templatetags/cms_tags.py
@@ -646,7 +646,10 @@ def _get_editable_context(self, context, instance, language, edit_fields,
         request = context['request']
         with force_language(request.toolbar.toolbar_language):
             extra_context = {}
-            if editmode:
+            if edit_fields == 'changelist':
+                instance.get_plugin_name = u"%s %s list" % (smart_text(_('Edit')), smart_text(instance._meta.verbose_name))
+                extra_context['attribute_name'] = 'changelist'
+            elif editmode:
                 instance.get_plugin_name = u"%s %s" % (smart_text(_('Edit')), smart_text(instance._meta.verbose_name))
             else:
                 instance.get_plugin_name = u"%s %s" % (smart_text(_('Add')), smart_text(instance._meta.verbose_name))
@@ -678,7 +681,10 @@ def _get_editable_context(self, context, instance, language, edit_fields,
                     if not view_url:
                         view_url = 'admin:%s_%s_edit_field' % (
                             instance._meta.app_label, instance._meta.module_name)
-                    url_base = reverse(view_url, args=(instance.pk, language))
+                    if view_url.endswith('_changelist'):
+                        url_base = reverse(view_url)
+                    else:
+                        url_base = reverse(view_url, args=(instance.pk, language))
                     querystring['edit_fields'] = ",".join(context['edit_fields'])
             if editmode:
                 extra_context['edit_url'] = "%s?%s" % (url_base, urlencode(querystring))
@@ -767,13 +773,15 @@ def _get_empty_context(self, context, instance, edit_fields, language,
         # attribute
         if not instance and editmode:
             return context
+        extra_context = copy(context)
         # ugly-ish
         if instance and isinstance(instance, Page):
             if not edit_fields:
                 edit_fields = 'title,page_title,menu_title'
             view_url = 'admin:cms_page_edit_title_fields'
+        if edit_fields == 'changelist':
+            view_url = 'admin:cms_page_changelist'
         querystring = {'language': language}
-        extra_context = copy(context)
         if edit_fields:
             extra_context['edit_fields'] = edit_fields.strip().split(",")
         # If the toolbar is not enabled the following part is just skipped: it
@@ -791,7 +799,7 @@ def _get_empty_context(self, context, instance, edit_fields, language,
         return extra_context
 
     def get_context(self, context, instance, attribute, edit_fields,
-                          language, filters, view_url, view_method, varname):
+                    language, filters, view_url, view_method, varname):
         """
         Uses _get_data_context to render the requested attributes
         """


Test patch:
diff --git a/cms/test_utils/project/templates/sidebar_submenu.html b/cms/test_utils/project/templates/sidebar_submenu.html
--- a/cms/test_utils/project/templates/sidebar_submenu.html
+++ b/cms/test_utils/project/templates/sidebar_submenu.html
@@ -1,3 +1,5 @@
 {% load i18n cms_tags menu_tags %}
-
-{% show_menu 1 100 0 1 "sidebar_submenu_root.html" %}
\ No newline at end of file
+{% render_model_block request.current_page "changelist" %}
+        <h3>Menu</h3>
+        {% show_menu 1 100 0 1 "sidebar_submenu_root.html" %}
+{% endrender_model_block %}
\ No newline at end of file
diff --git a/cms/tests/toolbar.py b/cms/tests/toolbar.py
--- a/cms/tests/toolbar.py
+++ b/cms/tests/toolbar.py
@@ -513,6 +513,21 @@ def test_block_tag(self):
         self.assertContains(response, '<span class="date">%s</span>' % (ex1.date_field.strftime("%Y")))
         self.assertContains(response, '<a href="%s">successful if</a></div>' % (reverse('detail', args=(ex1.pk,))))
 
+        # Changelist check
+        template_text = '''{% extends "base.html" %}
+{% load cms_tags %}{% load url from future %}
+
+{% block content %}
+{% render_model_block instance 'changelist' %}
+    {{ instance }}
+{% endrender_model_block %}
+{% endblock content %}
+'''
+        request = self.get_page_request(page, user, edit=True)
+        response = detail_view(request, ex1.pk, template_string=template_text)
+        # Assertions on the content of the block tag
+        self.assertContains(response, '<div class="cms_plugin cms_plugin-%s-%s-changelist-%s">' % ('placeholderapp', 'example1', ex1.pk))
+
     def test_invalid_attribute(self):
         user = self.get_staff()
         page = create_page('Test', 'col_two.html', 'en', published=True)
@@ -798,6 +813,7 @@ def test_edit_page(self):
         self.assertContains(response, '<div class="cms_plugin cms_plugin-cms-page-get_page_title-%s">%s</div>' % (page.pk, page.get_page_title(language)))
         self.assertContains(response, '<div class="cms_plugin cms_plugin-cms-page-get_menu_title-%s">%s</div>' % (page.pk, page.get_menu_title(language)))
         self.assertContains(response, '<div class="cms_plugin cms_plugin-cms-page-get_title-%s">%s</div>' % (page.pk, page.get_title(language)))
+        self.assertContains(response, '<div class="cms_plugin cms_plugin-cms-page-changelist-%s"><h3>Menu</h3></div>' % page.pk)
 
 
 class ToolbarAPITests(TestCase):