mnav Module

mnav.py This module contains classes that handle the site navigational hierarchy and pages.

Every page on the site should map to a NavNode object. The hierarchical structure of the site can be specified with regard to NavNodes. NavNodes are used:

  • To store page titles.
  • To generate site menus (top navigation menu, sidebar menu, etc.)
  • To generate breadcrumbs.
  • To assist in dynamic url generation.

NavNodes can contain arbitrary dictionary information to be used as hints to site menus, sidebars, sitemaps, and navigation bars, etc.

An unresolved question is whether navnodes should be an independent thing from Routes, or should a Route be a NavNode?

It might seem that all information in a NavNode would be properly stored in a Route entry, and indeed much of the time this would make sense.

But perhaps the way to think of the difference is that the job of the NavNodes hierarchy is to store information about the outward visual organization and appearance of site menus and navigation bars, wheras routes are about the internal controllers that respond to user requests.

Some examples of where Routes and NavNodes diverge:
  • Every page shown to the user should be marked as belonging to a specific NavNode, but a given route might have options that generate one of multiple NavNode locations.
  • Multiple routes might send the user to the same NavNode destination page.

We have a few functions for producing json data to use in an html menu/navbar/sidebar creation.

These return a json datastructure (hierarchical list) that should contain all of the hierarchy of data needed by a javascript/template function, to render a site menu. This data includes node properties

  • label_long = text label (shown when there is room)
  • label_short = text label (when space is tight)
  • label_hint = text label (can be very long text, to be shown on hover)
  • flag_onpath = true if this node is on the current navigational path to our location
  • flag_currentloc = true if this is the current leaf destination of the current page
  • urllink = url link for this item
  • flag_visible = whether this item is visible (note that when making the json navdata, we will NOT generate navnodes for items clearly not visible); but this flag might still be used for ajax functions
  • flag_enabled = whether this item should be shown as disabled
  • children = hierarchical list of children nodes

Note that eventually we may want any property here to be able to be specified as an ajax function; this allows us to do lazy evaluation of dynamic stuff

ATTN: There are some aspects of the current implementation that are unpleasant: As it stands now, the site has a NavNodeManager which is a collection of NavNodes. NavNodes themselves contain properties which may involve lambdas and aliases that resolve differently for each request (such as showing user name on logout menu item). So when we build a menu for a user’s request, we will dynamically resolve some of these NavNode properties, and cache this information local to the request. This is a bit messy as we would really like to carry around such information annotated onto the NavNodes themselves, but that isn’t feasible since they are shared among requests. It’s also an issue because we may have several functions invoked from the view templates that make use of the same NavNodes (for example breadcrumbs and menus) and we would prefer not to have to resolve properties twice on the same request. Solving this means caching results of resolving properties and storing local to the response object.

For now I have implemented a messy caching system that caches resolved navnode properties in the response context object (which also holds information about the current navnode pageid, etc). This isn’t such a bad solution in theory, as it makes it possible for us to both add a per-request annotated properties to nodes (like indicating which nodes are on the active path), as well as letting us cache node dynamic values (like dynamic titles and visibility computations) so that we only have to do it once even if using multiple menus (breadcrumbs, etc.).

However, it uses a very inefficient looking deep dictionary lookup like (context[‘nodes’][‘nodeid’][‘propertyname’]) and i worry about the cost of this, as well as the polution to responsecontext. A reasonable solution might be to use a special data structure for cached note properties, and perhaps assign navnodes a unique numeric counter id at startup, and index by that.

Another thing we do is allow nodes to specify a list of parents and/or children by nodename. This lets one create a hierarchy dynamically and add to it from wherever you want.

Controllers should set the current page id and other context available to navigation nodes using the reponse.add_rendercontext() function, e.g. response.add_rendercontext(‘contact’, {‘isloggedin’:True, ‘username’:’mouser’} )

ATTN: 1/28/14 The last time i looked at this code i got confused by the use of responsecontext. responsecontext is a dict that serves two purposes – first it is available for use by lambda functions which can look at request/response/user second, it can be written to under key ‘navnodecache’ which is itself a MThinDict, in order to cache the results of values (lambda functions) for nodes so that we don’t have to recompute them multiple times while traversing tree. Note that this cache starts off blank on each request.

Bases: object

The NavLink class is a small helper class that is used to refer to a NavNode by id, with its own propertiess. It is used when we need to specify children NavNodes and we need to provide additional information. ATTN: TODO - this is not integrated into above functions of manager yet.

dumps(indent=0)[source]

Return a string (with newlines and indents) that displays some debugging useful information about the object.

class mewlo.mpacks.core.navnode.mnav.NavNode(id, properties={})[source]

Bases: object

The NavNode class represents a page on the site.

dumps(indent=0)[source]

Return a string (with newlines and indents) that displays some debugging useful information about the object.

find_rootparent(rootnode=None)[source]

Find the root parent of this node.

get_flag_linkurl(responsecontext)[source]
get_isvisible(responsecontext, visiblefieldlist=['visible'])[source]

Return value for menu/navbar creation.

get_label(labelproplist, responsecontext)[source]

Return value for menu/navbar creation.

get_menu_hint(responsecontext)[source]

Return value for menu/navbar creation.

get_menu_url(responsecontext)[source]

Return value for menu/navbar creation.

get_pagetitle(responsecontext)[source]

Return value for menu/navbar creation.

get_property(propname, defaultval, flag_resolve, responsecontext)[source]
get_propertyl(propnames, defaultval, flag_resolve, responsecontext)[source]
get_response_property(propertyname, responsecontext, defaultval)[source]

Get a ‘cached’ value in response context for this node.

isactive(responsecontext)[source]
lookup_store_route()[source]

Try to lookup or infer route reference.

nodelist_tostring(nodelist)[source]
relative_url(url)[source]

Ask site to construct proper relative url on the site by adding site prefix.

resetbuild(mewlosite)[source]
set_response_property(propertyname, value, responsecontext)[source]

Set a ‘cached’ value in response context for this node.

class mewlo.mpacks.core.navnode.mnav.NavNodeManager(mewlosite, debugmode)[source]

Bases: mewlo.mpacks.core.manager.manager.MewloManager

The NavNodeManager class manages a collection of NavNodes. The most common usage would be that each site has a NavNodeManager to represent the site hierarchy

add_nodes(nodestoadd)[source]

Add one or more nodes to our node list.

buildstructure()[source]

Walk all nodes and build link structure using children and parents.

calcnav_currentpage_title(responsecontext)[source]

Return title of current page from current navnode

convert_nodeidlist_to_nodelist(nodeidlist)[source]

Convert a list of id strings to a list of node references.

description = 'Manages the navnode structures that build site maps and menus and breadcrumbs'
dumps(indent=0)[source]

Return a string (with newlines and indents) that displays some debugging useful information about the object.

find_current_and_root(rootnode, responsecontext)[source]

Given response and a possible explicit rootnode, find current node and rootnode to use.

find_pathto_rootparent(curnode, rootnode, flag_wantspecials)[source]

Find the path of nodes that go from rootnode to eventual childnode.

lookupnode(nodeid)[source]

Lookup node by string or reference.

makenav_activerowlist(responsecontext, rootnode=None)[source]

This makenav_ function returns a list of rows, where each row is a list of nodes. We might use this for a top navigation bar menu. It starts with the children of the root node, and includes subsequent sub-rows corresponding to the path from the root to the current node. So that the last row in the list is the row of siblings to the current node. On each row there should be one (and only one) active node).

makenav_activerowlist_onerow(parentnode, activechildnode, responsecontext)[source]

Make a list (row) of nodes, using children of parent node, and marking the activechildnode as active.

makenav_breadcrumb_list(responsecontext, rootnode=None)[source]

This makenav_ function returns a breadcrumb list of nodes

makenav_node_to_breadcrumb_html(nodelist, responsecontext)[source]

Take a list of built node rows and return html for them.

makenav_node_to_html(node, labelproplist, responsecontext, visiblefieldlist=['visible'])[source]

Return html for this node item.

makenav_noderow_to_html(row, responsecontext)[source]

Build html from a noderow.

makenav_rowlist_to_html(rowlist, responsecontext)[source]

Take a list of built node rows and return html for them.

sort_nodelist_byproperty(nodelist, responsecontext, flag_isalpha, propnames, defaultval)[source]

Given a nodelist, return sorted version, sorted by node numeric propertyname (with a default value if missing).

startup_prep(stageid, eventlist)[source]

This is invoked by site strtup, for each stage specified in startup_stages_needed() above.

typestr = 'core'

Table Of Contents

This Page