API Documentation

Element creation

In order to instruct the render engine how to render various components, we create elements and tie various resources to these elements via includes. The central component to this process is the Element class.

class render_engine.elemtools.Element(layout, config, parent=None, uuid=None)

The main base class that all render engine elements inherit from. A typical element may be defined like so:

from ...elemtools import Element, js, css

class Accordion(Element):
  includes = [
    css('jquery-ui'), js.inline('accordion')
  ]

Some elements require fetching additional information from either the the database or some other source. The staff listing element would be a good example of this. In such scenarios, the Element.before_render method can be used to augment the Element.data dictionary like so:

from ...elemtools import Element
from models import Staff

class StaffListing(Element):
  def before_render(self):
    # Fetch the staff id's from the element's config
    ids = self.config.get('staffIds', [])

    # Load the staff records from the database and place them in a place
    # that the element's template file can read them from
    self.data['staff_members'] = Staff.query.filter(
      Staff.id.in_(ids)
    )

To complete our staff listing example, the template may look something like:

<div {{ element|get_selectors }}>
  <div id="staff-listing-{{ element.uuid }}">
    {% for i in staff_members %}
      <div class="staff-listing-member">
        <div class="staff-listing-member-name">
          {{ i.first_name }} {{ i.last_name }}
        </div>
      </div>
    {% endfor %}
  </div>
</div>
layout

The Layout object that the element belongs to.

config

The element’s config dictionary (this is built by the layoutbuilder).

parent

If the element is a child of another element, the reference to the parent is stored here.

uuid

A uuid.uuid4 object used to uniquely identify one element from another at render time.

data

A dictionary to be passed off to the template engine (Jinja2) at render time.

includes

A list of non-standard included assets that the element needs to render correctly. This list should always include objects generated by functions js, css, and friends. For example:

includes = [
  js('angular'), css('jquery-ui')
]
dynamic

A simple boolean value that tells the render engine whether this element may contain dynamic content or not.

children

The element’s child elements, if any.

before_render()

A hook that can be implemented for modifying the element’s data dictionary attribute, which may be then used by the template, etc. This is the primary method by which an element can request additional information from the database.

iter_all_children(bypass_disabled=False)

Returns an iterator that iterates over all of the element’s children. This is a recursive function: it will return grand children, great grandchildren, etc.

module_name

The module name that the element is defined in.

path

The path to the element.

render()

Renders the element’s template. Keyword arguments will be passed through to the template engine.

render_children()

A helper method that renders the element’s immediate children.

template_file

The path to the element’s template file.

Including resources

Each Element has an includes list which is used to instruct the render engine how to fetch additional resources needed for rendering (e.g. CSS files and JavaScript files that aren’t part of the global site resources).

render_engine.elemtools.js(name, footer=False)

Specifies a JavaScript file as a dependency (include) for an element. See Element for examples on usage.

Parameters:
  • name (str) – The name of the JavaScript resource. This should be a name defined in the application’s include_registry.
  • footer (bool) – Whether or not the resource should be included in the footer of the page.
inline(name, footer=False)

This is a lot like js, except it pulls the resource into the body of the rendered template, wrapped in <script></script>. For convenience, this function is aliased to js.inline. E.g.:

from ...elemtools import Element, js

class SomeThing(Element):
  includes = [
    js.inline('durp')
  ]

It should be noted that this function looks for a resource of extension .js (make sure you don’t add that to the name parameter). It looks for this file in the parent element’s package directory. So, for example, let’s say the above example lives at src/render_engine/elements/something/__init__.py, the js.inline('durp') call will expect to find the JavaScript file located at src/render_engine/elements/something/durp.js.

Parameters:
  • name (str) – The name of the resource.
  • footer (bool) – Whether or not this resource should be inserted in the footer. Default is false, which will put it in the template’s <head></head> element.
render_engine.elemtools.css(name, footer=False, media='all')

Specifies a CSS file as a dependency (include) for an element. See Element for examples on usage.

inline(name, footer=False, media='all')

This is the CSS equivalent of js.inline.

Registry components

These are classes that are instantiated by the render engine (once each). You can find these instantiated at render_engine.elemtools.element_registry and render_engine.elemtools.include_registry.

class render_engine.elemtools.Registry
register(key, value)

Add an item to the registry

Parameters:
  • key – The key to set the object to.
  • value – The object to save in the registry.
class render_engine.elemtools.ElementRegistry
create_element_from_config(layout, config, parent=None)

Instantiates an Element object based on the config passed to it.

Parameters:
Returns:

A new element.

Return type:

render_engine.elemtools.Element

render_engine.elemtools.element_registry

An instance of ElementRegistry. This is where you should register all of your element definitions.

render_engine.elemtools.include_registry

An instance of Registry. This is where you should register all of your include resources.

Bringing everything together

All of the necessary components for a layout are brought together into one place via Layout. Generally, these objects are instantiated for you via the models.Menu.layout property.

class render_engine.elemtools.Layout(element_registry, include_registry, config=None, elements=None, pre_main_elements=None, post_main_elements=None, template_variables=None)

The central object that stores all of the information about a given layout.

get_all_includes()

Gets all of the includes arrays from all elements in the layout, combines them together into a single array, removes duplicates, and finally sorts them.

get_dynamic_elements()

Returns all elements which have been flagged as having dynamic content.

iter_all_elements(bypass_disabled=False)

Returns an iterator of all elements in the layout. By “all elements”, I mean literally all of them: this is a recursive function that pulls in all of the element’s children, etc. as well.

render()

Renders and returns the main content area of the layout.

render_post_main()

Renders and returns the “post main” content area of the layout.

render_pre_main()

Renders and returns the “pre main” content area of the layout.

Utilities

There are a number of utility functions, decorators, etc. that I have created to help with this whole thing. They’re listed below. :)

util.authenticate(fn)

A simple decorator that checks whether or not the user is logged in or not. If the user isn’t logged in, a 401 is sent. Note that this is intended to be used with the API and not the render engine portion of the app.

For example:

class SomeResource(Resource):
  @authenticate
  def get(self):
    return jsonify({
      'stuff': 'cool'
    })
class util.creds(*allowed_creds)

Checks that the user is logged in and has the credentials specified. This, like the authenticate decorator, is intended to be used with the API portion of the app. (A JSON 401 will be sent if the request fails.)

For example:

class SomeOtherResource(Resource):
  @creds('admin', 'dev')
  def get(self):
    return jsonify({
      'stuff': 'whatever'
    })
render_engine.elemtools.augment_query(query, config)

Creates a new query based, augmented with configuration data as provided by the output of the resource-list directive. Basically, it takes a query and applies order by, limit, etc. to that query, as specified by the user-configured resource-list element.

For example, consider the following JSON configuration:

{
  "query": {
    "dynamic": true,
    "filters": {
      "date": false,
      "ids": [],
      "ministryIds": [3, 4]
    },
    "limit": 10,
    "orderBy": "id"
  }
}

It’s a rather tedious endeavor to apply all of the necessary filtering, ordering, limiting, etc. to the above JSON, so this function does most of it for you. We could, for instance, create a query on the staff table, then pass that query and the “query” property of the JSON configuration above to augment_query like so:

from models import Staff

# We only want staff that are enabled
original_query = Staff.query.filter_by(enabled='yes')

# Now we can create an augmented version of the query like so:
augmented_query = augment_query(original_query, config['query'])

# Fetch all results
results = augmented_query.all()

Note that augment_query does not do any date filtering. If such filtering is required, it needs to be applied to the query that is passed to augment_query.

Also, augment_query does NOT modify the query passed to it, but rather creates a new query based on that original query. (This is typical of all SQL Alchemy query building.)

Template engine filters

I’ve created a number of (I think) useful template filters so that we can reduce some of the more obnoxious templating tasks, such as resolving links to menu records, HTML element id and class auto population stuff, etc.

render_engine.filters.get_selectors(element, *additional_classes)

Based upon the element’s config parameters (as specified by the layout builder), outputs id and class attributes for use in HTML tag definitions.

For example, consider the following element config JSON:

{
  "type": "text-block",
  "text": "This is so cool!",
  "dom": {
    "identifier": "some-text-block",
    "classes": "custom-textblock my-textblock"
  }
}

And now consider the following template for the “text-block” type:

<div {{ element|get_selectors }}>
  ...
</div>

This will output the following DOM:

<div id="some-text-block" class="text-block custom-textblock my-textblock">
  ...
</div>

You’ll notice that the filter also adds the “type” of the element as a class.

Accepts link configuration generated by the layoutbuilder’s dynamic-link directive and yields a URL.

render_engine.filters.classify(obj)

A simple helper for applying classes conditionally to a DOM element.

For example:

<div class="{{ {'things': True, 'stuff': False, 'whatever': True}|classify }} ">
  ...
</div>

... will return:

<div class="things whatever">
  ...
</div>

Given a Category model object, outputs a corresponding relative URL.

ORM Models

Some of the models have some additional, non-standard behavior. My attempt is to document that behavior here. All of the normal stuff (e.g. column definitions) will be ommitted. Furthermore, ORM classes that don’t have any oddities will be also be ommitted.

class models.Menu(**kwargs)
layout

Returns a render_engine.elemtools.Layout object based on the menu’s layout_config data (JSON).