Friday 23 January 2015

Linking to static pages from the Navbar correctly in CKAN

I ran into some issues trying to link to a static page in CKAN from the NavBar. I figured out a solution through lots of hacking and browsing through existing codebases. Here's a write up of the problem and solution.

Creating a New Static Page

In CKAN, you may want to add a new static page. The docs give a bit of help on how to add static files but not new pages.
It's easy enough by putting a page in your extensions templates folder, updating your config to load that templates folder, and linking to your page from the header.html file amidst the other navbar items. For example:

In plugin.py
 def update_config()
        here = os.path.dirname(__file__)
        rootdir = os.path.dirname(os.path.dirname(here))
        template_dir = os.path.join(rootdir, 'ckanext',
                                    '<ext_name>', 'templates')
        config['extra_template_paths'] = ','.join([template_dir,
                config.get('extra_template_paths', '')])

Where your file 'my_new_page.html' is your new static file in ckanext/<ext_name>/templates/

Copy templates/header.html from the CKAN source directory to the extensions templates directory e.g. ckanext/<ext_name>/templates/header.html
Then add a list item and href to your new page inside the block header_site_navigation as such:

<li><a href="/my_new_page.html"></a></li>

Et voila!

Making the Link Smarter

If you want to make it like the other Navbar links that become highlighted when the user is currently on that page it gets a little tricky (but can be done). In the templates/header.html you will have added a list item to; you will have seen this helper method: build_nav_main. Like so:
 {{ h.build_nav_main(
                ('search', _('Datasets'))) }}

You can use this method to construct your link which will become highlighted when the page is active. The right parameter is the text that will displayed in the link, this can be anything. The left link is CKANs internal alias for the page. It stores this internal alias alongside the URL path and uses this key/value to to construct the link and ascertain whether you're on the page.

To create this you will need to make use of controllers and implement the IRoutes interface.

The IRoutes interface has the function before_map() which adds custom routes.
The first parameters is your internal alias.
The second is the relative URL path
The third and fourth must specify a controller and an action on the controller.
The 3rd and 4th parameter cannot be replaced with an absolute URL - it must be controller and action.
Include this into your plugin.py

    plugins.implements(plugins.IRoutes, inherit=True)
    def before_map(self, map):
        map.connect('my_page', '/my_page', controller='ckanext.myextension.controller:SpecialRouteController', action='my_page')
        return map

This will add a route aliased as 'my_page' which on the URL /my_page calls an action on the SpecialRouteController.

Create a controller.py in the same directory as your plugin.py.    
In your controller.py you need to add something like this:

import ckan.lib.base as base
from ckan.controllers.home import HomeController
class SpecialRouteController(HomeController):
    def my_page(self):
        return base.render('/my_new_page.html')
Then go back to your header.html file and add something like this:
 {{ h.build_nav_main(
                ('my_page', _('Datasets'))) }}

Now when the build_nav_main constructs the link, it will lookup my_page in the routes, call the my_page action on the SpecialRoutesController and render your static file in the templates directory.


No comments:

Post a Comment