crbreadcrumb — Generalized breadcrumb rendering

Renderables

The cradmin.crbreadcrumb module provides generalized renderables for breadcrumbs. There renderables can be used to render breadcrumbs anywhere on a page using the cradmin_render_renderable() template tag.

Cascading breadcrumbs in cradmin instances, apps and views

Having renderables for breadcrumbs is good, but it does not help with the challenge of having to create the full breadcrumb path in each view, and having to refactor that everywhere if we move views around. To solve this problem, we have added support for breadcrumbs in:

All of these classes have a get_breadcrumb_item_list_renderable()-method. The method on crinstance.BaseCrAdminInstance creates a breadcrumb item list renderable object (a subclass of django_cradmin.crbreadcrumb.BreadcrumbItemList). The method on crapp.App just call request.cradmin_instance.get_breadcrumb_item_list_renderable() to get the breadcrumb item list from the cradmin instance. And, in the same spirit, the method on viewhelpers.mixins.CommonCradminViewMixin just call request.cradmin_app.get_breadcrumb_item_list_renderable() to get the breadcrumb item list from the cradmin app. Docs for each of these methods here:

As a convenience, crinstance.BaseCrAdminInstance, crapp.App and viewhelpers.mixins.CommonCradminViewMixin also define a add_breadcrumb_list_items()-method which can be used to just add breadcrumb items as long as the cradmin instance/app actually provide a breadcrumb item list rendereable. You normally want to override these methods, and they are documented here:

Note

These methods are named add_breadcrumb_list_items(). This does not mean that you can only add items (it is just the use case in 95% of use cases). Since you have a BreadcrumbItemList, you can add, remove, insert, extend, etc, not just add.

Example

A typical and simple example:

class SiteEditView(viewhelpers.formview.UpdateRoleView):
    def add_breadcrumb_list_items(self, breadcrumb_item_list):
        breadcrumb_item_list.append(label='Edit', active=True)


class SiteOverviewView(viewhelpers.generic.WithinRoleTemplateView):
    # No add_breadcrumb_list_items() method because this is the index view for
    # the app, so the breadcrumb the app adds takes you to this view.
    pass


class SiteDetailsApp(crapp.App):
    appurls = [
        crapp.Url(r'^$', SiteOverviewView.as_view(), name=crapp.INDEXVIEW_NAME),
        crapp.Url(r'^edit$', SiteEditView.as_view(), name='edit'),
    ]

    def add_breadcrumb_list_items(self, breadcrumb_item_list):
        breadcrumb_item_list.append(
           url=self.reverse_appindexurl(),
           label='{} details'.format(
              self.request.cradmin_instance.get_titletext_for_role(self.request.cradmin_role))
        )


class SiteCradminInstance(crinstance.BaseCrAdminInstance):
     rolefrontpage_appname = 'details'
     apps = [
        ('details', SiteDetailsApp)
     ]

     def add_breadcrumb_list_items(self, breadcrumb_item_list):
         if self.get_rolequeryset().count() > 1:
            # Add breadcrumb back to the roleselect view if we have more than one site
            breadcrumb_item_list.append(
                url=self.get_instance_frontpage_url(),
                label='Sites')

Custom breadcrumb item list renderable:

class MyCustomBreadcrumbItemList(crbreadcrumb.WrappedBreadcrumbItemList):
    # We just override the css class in this example, but you can do much more!
    def get_bem_block(self):
        return 'my-custom-breadcrumb-item-list'


class SiteCradminInstance(crinstance.BaseCrAdminInstance):
    # Everything else is just like in SiteCradminInstance above, but
    # we add this property
    breadcrumb_item_list_renderable_class = MyCustomBreadcrumbItemList

Custom breadcrumb item list in just a single view:

# This works for crapp.App too if you want a custom breadcrumb style for all views in an app!

class SiteEditView(viewhelpers.formview.UpdateRoleView):
    def add_breadcrumb_list_items(self, breadcrumb_item_list):
        breadcrumb_item_list.append(label='Edit', active=True)

    def get_breadcrumb_item_list_renderable(self):
        # We get the breadcrumb item list from super() this will include everything from
        # the cradmin instance and app, and the item we added in add_breadcrumb_list_items()
        # above.
        breadcrumb_item_list = super().get_breadcrumb_item_list_renderable()

        if breadcrumb_item_list is None:
            # Handle that breadcrumbs may have been disabled in the cradmin instance or app.
            return None

        # Then we create an instance of MyCustomBreadcrumbItemList with a copy
        # of the items of the items from super().
        return MyCustomBreadcrumbItemList.from_breadcrumb_item_list(breadcrumb_item_list)

Rendering breadcrumbs at a custom location

Lets say your design requires you to render the breadcrumb centered above the title in the page-cover on a certain page. You can achieve this fairly easily.

This can be solved in many different ways, but we will go with a fairly easy solution where we:

  • Use BreadcrumbItemList instead of WrappedBreadcrumbItemList to get a plain <nav class="breadcrumb-item-list"> without any wrapper.
  • Set a custom location for the breadcrumb so it is not rendered at the default location.
  • Render the breadcrumb in the page-cover-content block.

First, we override get_breadcrumb_item_list_renderable on the view:

class SiteEditView(viewhelpers.formview.UpdateRoleView):
    def add_breadcrumb_list_items(self, breadcrumb_item_list):
        breadcrumb_item_list.append(label='Edit', active=True)

    def get_breadcrumb_item_list_renderable(self):
        # We have an example above that explains how just copying items works in detail.
        breadcrumb_item_list = super().get_breadcrumb_item_list_renderable()
        if breadcrumb_item_list is None:
            return None
        breadcrumb_item_list = crbreadcrumb.BreadcrumbItemList.from_breadcrumb_item_list(breadcrumb_item_list)

        # We set a custom location to avoid rendering the breadcrumbs
        # at the default location
        breadcrumb_item_list.set_location('custom')

        return breadcrumb_item_list

Next, we override the template:

{% extends "django_cradmin/viewhelpers/formview/within_role_update_view.django.html" %}
{% load cradmin_tags %}

{% block page-cover-content %}
    {# Render breadcrumbs here instead #}
    <div class="text-center paragraph">
        {% cradmin_render_breadcrumb_item_list %}
    </div>

    {{ block.super }}
{% endblock page-cover-content %}

Note

You can change how the breadcrumbs are rendered for all views in your site by overring the breadcrumb item list renderable on your cradmin instances (typically with a common base class or mixin class), and override the django_cradmin/standalone-base.django.html template.

Disabling breadcrumbs

Disabling breadcrumbs can be done on cradmin instance, app or views. It is the same for all of them, you just override the get_breadcrumb_item_list_renderable() method and return None:

# View
class SiteEditView(viewhelpers.formview.UpdateRoleView):
    def get_breadcrumb_item_list_renderable(self):
        return None

# App
class SiteDetailsApp(crapp.App):
    def get_breadcrumb_item_list_renderable(self):
        return None


# Cradmin instance
class SiteCradminInstance(crinstance.BaseCrAdminInstance):
    def get_breadcrumb_item_list_renderable(self):
        return None

crbreadcrumb module

class BreadcrumbItem(label, url=None, active=False, label_maxlength=None, active_label_maxlength=None, render_link_for_active=False, parent_bem_block=None)

Bases: django_cradmin.renderable.AbstractBemRenderable

Breadcrumb item renderable.

Parameters:
  • label (str) – The text/label.
  • url (str) – The link URL. If this is None or any other boolean false value, we render the item as a <span> instead of as a <a> element.
  • active (bool) – If this is True, we add the --active BEM variant to the element.
  • label_maxlength (int) – The max length of the label before it is shortened using the truncatechars django template filter. You typically do not set this directly, but instead override BreadcrumbItemList.get_default_item_label_maxlength() to get uniformed max lengths for all your breadcrumbs.
  • active_label_maxlength (int) – The max length of the label if active=True before the label is shortened using the truncatechars django template filter. You typically do not set this directly, but instead override BreadcrumbItemList.get_default_active_item_label_maxlength() to get uniformed max lengths for all your breadcrumbs.
  • render_link_for_active (bool) – If this is True, we render as a link (<a>) even if active is True. We do, of course, not render as a link if we do not have an url.
  • parent_bem_block – Provided automatically by BreadcrumbItemList.
get_bem_element()

Get the bem element string.

get_bem_variant_list()

Get a list of BEM variants.

You do not include the block/element, just the part after --.

Should we render the element as a link (<a>)?

get_html_element_attributes()

Get HTML element attributes as a dict.

class BreadcrumbSeparator(parent_bem_block=None)

Bases: django_cradmin.renderable.AbstractBemRenderable

Breadcrumb separator renderable.

get_bem_element()

Get the bem element string.

class BreadcrumbItemList(cradmin_instance)

Bases: django_cradmin.renderable.AbstractBemRenderable

List of breadcrumb items.

We provide a lot of helper methods, but if you need more powerful features, such as removal of breadcrumb items, you can just manipulate the breadcrumb_item_list attribute directly. All the append*, insert*, etc. methods just add items to this list.

breadcrumb_item_list

list – A plain python list of django_cradmin.renderable.AbstractRenderable objects, normally BreadcrumbItem objects.

cradmin_instance

django_cradmin.crinstance.BaseCrAdminInstance – The cradmin instance sent in as an argument to __init__().

Parameters:cradmin_instance (django_cradmin.crinstance.BaseCrAdminInstance) – A cradmin instance.
LOCATION_ABOVE_PAGE_COVER = 'above-page-cover'

Render location – Above page cover.

LOCATION_BELOW_PAGE_COVER = 'below-page-cover'

Render location – Below page cover.

get_extra_css_classes_list()

Get a list of extra css classes.

get_default_location()

The location to render the breadcrumb at by default.

Can be overridden on a per view, per app or per cradmin instance basis using set_location().

Only relevant if using the django_cradmin.templatetags.cradmin_tags.cradmin_render_breadcrumb_item_list() template tag with the location argument. Defaults to LOCATION_BELOW_PAGE_COVER.

get_location()

Get the location to render the breadcrumb item list at.

Do not override this - override get_default_location() instead.

set_location(location)

Set the location to render the breadcrumb item list at.

Can be used in the get_breadcrumb_item_list_renderable() method of cradmin instances, apps or views to override the location to render breadcrumbs at.

Parameters:location (str) – Location.
get_bem_block()

Override this to use a custom BEM block for the breadcrumb.

get_bem_variant_list()

Get a list of BEM variants.

You do not include the block/element, just the part after --.

get_separator_renderable_class()

Get the renderable class for breadcrumb item separators.

Defaults to BreadcrumbSeparator.

make_separator_renderable()

Make a breadcrumb item separator renderable.

get_item_renderable_class()

Get the renderable class for breadcrumb items.

Defaults to BreadcrumbItem.

get_default_item_label_maxlength()

The default max length of the label of items.

If the label is longer than this, the label is truncated using the truncatechars django template filter.

If you return None or another boolean false falue from this method, labels are not truncated.

Returns:The max length of item labels, or None. Defaults to 15.
Return type:int
get_default_active_item_label_maxlength()

The default max length of the label of active items.

If the label is longer than this, the label is truncated using the truncatechars django template filter.

If you return None or another boolean false falue from this method, labels are not truncated.

Returns:The max length of item labels, or None. Defaults to 25.
Return type:int
get_item_renderable_kwargs(**extra_kwargs)

Get kwargs for the get_item_renderable_class().

Make sure you call super to get the required kwargs if you override this method.

Parameters:**extra_kwargs – Extra kwargs.
Returns:kwargs.
Return type:dict
make_item_renderable(**kwargs)

Make an item renderable.

Parameters:**kwargs – Kwargs for the item renderable class. This is forwarded to get_item_renderable_kwargs() to enable default kwargs for all items in the breadcrumb item list.
append(**kwargs)

Uses make_item_renderable() to create a renderable, and appends the created item to the breadcrumb list.

prepend(**kwargs)

Uses make_item_renderable() to create a renderable, and prepends the created item to the breadcrumb list.

insert(index, **kwargs)

Uses make_item_renderable() to create a renderable, and inserts the created item in the breadcrumb list.

insert_item_renderable(index, renderable_object)

Insert a renderable object at a specific index in the breadcrumb list.

Parameters:
prepend_item_renderable(renderable_object)

Prepend a renderable object to the breadcrumb list.

Parameters:renderable_object – The renderable object (a subclass of django_cradmin.renderable.AbstractRenderable)
append_item_renderable(renderable_object)

Append a renderable object to the breadcrumb list.

Parameters:renderable_object – The renderable object (a subclass of django_cradmin.renderable.AbstractRenderable)
extend_with_item_renderables(renerable_iterable)

Just like append() except that it takes an iterable of renderables instead of a single renderable.

iter_breadcrumb_list_renderables()

Iterate through all the breadcrumb items and separators.

Separators is yielded automatically after each item except the last one. Separator renderables can be overridden with make_separator_renderable().

class BreadcrumbItemListWrapper(breadcrumb_item_list)

Bases: django_cradmin.renderable.AbstractBemRenderable

Wraps a BreadcrumbItemList in a box.

get_bem_block()

Get the bem block string.

get_bem_variant_list()

Get a list of BEM variants.

You do not include the block/element, just the part after --.

class WrappedBreadcrumbItemList(cradmin_instance)

Bases: django_cradmin.crbreadcrumb.BreadcrumbItemList

Renders and works just like BreadcrumbItemList except that it is wrapped within a BreadcrumbItemListWrapper.

You can subclass BreadcrumbItemListWrapper and replace the wrapper class by overriding get_wrapper_renderable_class().

Parameters:cradmin_instance (django_cradmin.crinstance.BaseCrAdminInstance) – A cradmin instance.
get_wrapper_renderable_class()

Get the renderable for the wrapper element(s).

Returns:BreadcrumbItemListWrapper or a subclass.
Return type:django_cradmin.crbreadcrumb.BreadcrumbItemListWrapper
get_wrapper_renderable_kwargs()

Get kwargs for the class returned by get_wrapper_renderable_class().

Returns:Kwargs.
Return type:dict
render(request=None, extra_context_data=None)

Render get_template_names with the context returned by get_context_data().

Paramteters:
request (HttpRequest): If this is provided, we forward it to
get_context_data(), and to render_to_string() (which is used to render the template).