svenwltr
svenwltr

Reputation: 18442

Django CMS - navigation order

I want to integrate an app to Django CMS. Therefor I followed the documentation of Django CMS.

For example: I use the following code (from doc) in menu.py of my app.

from menus.base import Menu, NavigationNode
from menus.menu_pool import menu_pool
from django.utils.translation import ugettext_lazy as _

class TestMenu(Menu):

    def get_nodes(self, request):
        nodes = []
        n = NavigationNode(_('sample root page'), "/", 1)
        n2 = NavigationNode(_('sample settings page'), "/bye/", 2)
        n3 = NavigationNode(_('sample account page'), "/hello/", 3)
        n4 = NavigationNode(_('sample my profile page'), "/hello/world/", 4, 3)
        nodes.append(n)
        nodes.append(n2)
        nodes.append(n3)
        nodes.append(n4)
        return nodes

menu_pool.register_menu(TestMenu)

My problem is the order of the nodes. With this code my menu will be appended on the menu of my cms pages, but I need a different order.

Is there some way to define on which position my app menu appears?

Upvotes: 4

Views: 1588

Answers (2)

Jacques de Hooge
Jacques de Hooge

Reputation: 6990

Thanks for helping me out, Sven!! I wasn't aware of the existence of modifiers...

Below is a refinement of your code. It will insert app nodes at arbitrary locations. Each app node has a targetIndex attribute, giving it's zero-based place number on the menu. Sorry for the camel-case, but I use a mix of programming languages and one style to fit them all. In the example, app nodes are inserted at even place numbers, 'follow' is the name of my app.

    from menus.base import Menu, NavigationNode, Modifier
    from menus.menu_pool import menu_pool

    class FollowMenu (Menu):
        def get_nodes (self, request):
            nodes = []
            for i in range (5):
                nodes.append (NavigationNode (('Test' + str (i)), '/', i,  attr={'targetIndex': 2 * i}))
            return nodes

    menu_pool.register_menu (FollowMenu)

    class FollowModifier (Modifier):
        def modify (self, request, nodes, namespace, root_id, post_cut, breadcrumb):
            if not post_cut:
                return nodes

            appNodes = [node for node in nodes if 'targetIndex' in node.attr]
            cmsNodes = [node for node in nodes if not 'targetIndex' in node.attr]

            resultNodes = []

            appNodeIndex = 0
            cmsNodeIndex = 0
            for resultNodeIndex in range (len (nodes)):
                if appNodeIndex < len (appNodes) and appNodes [appNodeIndex] .attr ['targetIndex'] == resultNodeIndex:
                    resultNodes.append (appNodes [appNodeIndex])
                    appNodeIndex += 1
                elif cmsNodeIndex < len (cmsNodes):
                    resultNodes.append (cmsNodes [cmsNodeIndex])
                    cmsNodeIndex += 1
                else:
                    raise Exception ('Error merging app menu and cms menu items')

            return resultNodes

    menu_pool.register_modifier (FollowModifier)

Upvotes: 0

svenwltr
svenwltr

Reputation: 18442

Here is my workaround, so far. (I still would prefer a more clean way.)

I added a CMS page named --appname-- and this is my menu.py:

from menus.base import Menu, NavigationNode
from menus.base import Modifier
from menus.menu_pool import menu_pool

my_items = ["a", "b", "c"]

class ImmoMenu(Menu):

    def get_nodes(self, request):
        nodes = []

        i = 0

        for name in my_items:
            i += 1
            n = NavigationNode(name, "/", i, attr={'appname': True})
            nodes.append(n)

        return nodes

menu_pool.register_menu(ImmoMenu)


class ImmoModifier(Modifier):

    def modify(self, request, nodes, namespace, root_id, post_cut, breadcrumb):
        if post_cut is not True:
            return nodes

        split_passed = False

        nodes_before = []
        nodes_after = []
        nodes_immo = []

        for node in nodes:
            if node.title == "--appname--":
                split_passed = True
                continue

            if 'appname' in node.attr:
                nodes_immo.append(node)

            elif split_passed:
                nodes_after.append(node)

            else:
                nodes_before.append(node)

        return nodes_before + nodes_immo + nodes_after

menu_pool.register_modifier(ImmoModifier)

Upvotes: 3

Related Questions