From c37903fe81a99f3840503e51fff6029012ce1c2a Mon Sep 17 00:00:00 2001 From: Aron Carroll Date: Wed, 1 Aug 2012 15:27:56 +0100 Subject: [PATCH] [#2375] Update the templating documentation --- doc/templating.rst | 446 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 407 insertions(+), 39 deletions(-) diff --git a/doc/templating.rst b/doc/templating.rst index 6569a5478be..b8f3e89a778 100644 --- a/doc/templating.rst +++ b/doc/templating.rst @@ -1,75 +1,443 @@ -================ Jinja Templating ================ -The base theme of CKAN now uses `Jinja ` as it's -templating engine. Old Genshi templates are still supported but we advise -that you start to move away from using them. +We have recently moved over to using Jinja from Genshi for the default +templating engine within CKAN. This was done to provide a more flexible, +extensible and most importantly easy to understand templating language. + +Some useful links to get you started. + +- `Jinja Homepage `_ +- `Jinja Developer Documentation `_ +- `Jinja Template + Documentation `_ + +Legacy Templates +---------------- + +Existing Genshi templates have been moved to the *templates\_legacy* +directory and will continue to be served if no file with the same name +is located in *templates*. This should ensure backward compatibility +until instances are able to upgrade to the new system. + +The lookup path for templates is as follows. Give the template path +"user/index.html": + +1. Look in the template directory of each loaded extension. +2. Look in the template\_legacy directory for each extension. +3. Look in the main ckan template directory. +4. Look in the template\_legacy directory. + +CKAN will automatically determine the template engine to use. + +File Structure +-------------- + +The file structure for the CKAN templates is pretty much the same as +before with a directory per controller and individual files per action. + +With Jinja we also have the ability to use snippets which are small +fragments of HTML code that can be pulled in to any template. These are +kept in a snippets directory within the same folder as the actions that +are using them. More generic snippets are added to templates/snippets. + +:: + + templates/ + base.html # A base template with just core HTML structure + page.html # A base template with default page layout + header.html # The site header. + footer.html # The site footer. + snippets/ # A folder of generic sitewide snippets + home/ + index.html # Template for the index action of the home controller + snippets/ # Snippets for the home controller + user/ + ... + templates_legacy/ + # All ckan templates Using the templating system --------------------------- Jinja makes heavy use of template inheritance to build pages. A template -for an action will tend to inherit from *page.html*:: +for an action will tend to inherit from *page.html*: + +:: + + {% extends "page.html" %} -{% extends "page.html" %} +Each parent defines a number of blocks that can be overridden to add +content to the page. *page.html* defines majority of the markup for a +standard page. Generally only ``{% block primary_content %}`` needs to +be extended: -Each parent defines a number of blocks that can be overridden to add content -to the page. *page.html* defines majority of the markup for a standard -page. Generally only ``{% block primary_content %}`` needs to be extended:: +:: -{% extends "page.html" %} + {% extends "page.html" %} -{% block page_content.html %} -

My page title

-

This content will be added to the page

-{% endblock %} + {% block page_content.html %} +

My page title

+

This content will be added to the page

+ {% endblock %} -Most template pages will define enough blocks so that the extending page can -customise as little or as much as required. +Most template pages will define enough blocks so that the extending page +can customise as little or as much as required. + +Internationalisation +-------------------- + +Jinja provides a couple of helpers for +`internationalisation `_. +The most common is to use the ``_()`` function: + +:: + + {% block page_content.html %} +

{{ _('My page title') }}

+

{{ _('This content will be added to the page') }}

+ {% endblock %} + +Variables can be provided using the "format" function: + +:: + + {% block page_content.html %} +

{{ _('Welcome to CKAN {name}').format(name=username) }}

+ {% endblock %} + +For longer multiline blocks the ``{% trans %}`` block can be used. + +:: + + {% block page_content.html %} +

+ {% trans name=username %} + Welcome to CKAN {{ name }} + {% endtrans %} +

+ {% endblock %} Conventions ----------- -There are a few common conventions that have evolved from using the language. +There are a few common conventions that have evolved from using the +language. Includes ~~~~~~~~ -Snippets of text that are included using ``{% include %}`` should be kept in -a directory called *partials*. This should be kept in the same directory -as the code that uses it. +Snippets of text that are included using ``{% include %}`` should be +kept in a directory called *partials*. This should be kept in the same +directory as the code that uses it. Snippets ~~~~~~~~ -Snippets are essentially middle ground between includes and macros in that -they are includes that allow a specific context to be provided (includes just -receive the parent context). +Snippets are essentially middle ground between includes and macros in +that they are includes that allow a specific context to be provided +(includes just receive the parent context). -Ideally we should be able to remove one of these from the final release of the -new theme. +Ideally we should be able to remove one of these from the final release +of the new theme. Macros ~~~~~~ -Macros should be used very sparingly to create custom generators for very -generic snippets of code. For example macros/form.html has macros for creating -common form fields. +Macros should be used very sparingly to create custom generators for +very generic snippets of code. For example macros/form.html has macros +for creating common form fields. + +They should generally be avoided as they are hard to extend and +customise. + +CKAN Extensions +--------------- + +Currently extensions cannot automatically insert content into the CKAN +website instead they require a new "theme" extension to be created +specifically for the instance. This has been done to intentionally keep +everything very declarative and to allow the most flexibility in the +simplest way. + +Please see the `Extension Templating <./extension-templating.rst>`_ +document for more information. + +Custom Control Structures +------------------------- + +We've provided a few additional control structures to make working with +the templates easier. Other helpers can still be used using the ``h`` +object as before. + +ckan\_extends +~~~~~~~~~~~~~ + +:: + + {% ckan_extends [template_name] %} + +This works just like ``{% extend %}`` but should be used in extensions +to pull in the template from CKAN core for customisation. + +For example if you wish to remove the breadcrumb from the user profile +page in your own site. You would locate the template you wish to +override. + +:: + + ckan/templates/user/read.html + +And create a new one in your theme extension. + +:: + + ckanext-mytheme/ckanext/mytheme/templates/user/read.html + +In this new file you would pull in the core template using +``{% ckan_extends %}``: + +:: + + {% ckan_extends "user/read.html" %} + +This will now render the current user/read page but we can override any +portion that we wish to change. In this case the ``breadcrumb`` block. + +:: + + {% ckan_extends "user/read.html" %} + + {# Remove the breadcrumb #} + {% block breadcrumb %}{% endblock %} + +snippet +~~~~~~~ + +:: + + {% snippet [filepath], [arg1=arg1], [arg2=arg2]... %} + +Snippets work very much like Jinja's ``{% include %}`` except that that +do not inherit the parent templates context. This means that all +variables must be explicitly passed in to the snippet. This makes +debugging much easier. + +:: + + {% snippet "package/snippets/package_form.html", data=data, errors=errors %} + +url\_for +~~~~~~~~ + +:: + + {% url_for [arg1=arg1], [arg2=arg2]... %} + +Works exactly the same as ``h.url_for()``: + +:: + + Home + +link\_for +~~~~~~~~~ + +:: + + {% link_for text, [arg1=arg1], [arg2=arg2]... %} + +Works exactly the same as ``h.link_for()``: + +:: + +
  • {% link_for _("Home"), controller="home", action="index" %}
  • + +url\_for\_static +~~~~~~~~~~~~~~~~ + +:: + + {% url_for_static path %} + +Works exactly the same as ``h.link_for()``: + +:: + + + +Form Macros +----------- + +For working with forms we have provided some simple macros for +generating common fields. These will be suitable for most forms but +anything more complicated will require the markup to be written by hand. + +The macros can be imported into the page using the ``{% import %}`` +command. + +:: + + {% import 'macros/form.html' as form %} + +The following fields are provided: + +form.input() +~~~~~~~~~~~~ + +Creates all the markup required for an input element. Handles matching +labels to inputs, error messages and other useful elements. + +:: + + name - The name of the form parameter. + id - The id to use on the input and label. Convention is to prefix with 'field-'. + label - The human readable label. + value - The value of the input. + placeholder - Some placeholder text. + type - The type of input eg. email, url, date (default: text). + error - A list of error strings for the field or just true to highlight the field. + classes - An array of classes to apply to the control-group. + +Examples: + +:: + + {% import 'macros/form.html' as form %} + {{ form.input('title', label=_('Title'), value=data.title, error=errors.title) }} + +form.checkbox() +~~~~~~~~~~~~~~~ + +Builds a single checkbox input. + +:: + + name - The name of the form parameter. + id - The id to use on the input and label. Convention is to prefix with 'field-'. + label - The human readable label. + value - The value of the input. + checked - If true the checkbox will be checked + error - An error string for the field or just true to highlight the field. + classes - An array of classes to apply to the control-group. + +Example: + +:: + + {% import 'macros/form.html' as form %} + {{ form.checkbox('remember', checked=true) }} + +form.select() +~~~~~~~~~~~~~ + +Creates all the markup required for an select element. Handles matching +labels to inputs and error messages. + +A field should be a dict with a "value" key and an optional "text" key +which will be displayed to the user. +``{"value": "my-option", "text": "My Option"}``. We use a dict to easily +allow extension in future should extra options be required. + +:: + + name - The name of the form parameter. + id - The id to use on the input and label. Convention is to prefix with 'field-'. + label - The human readable label. + options - A list/tuple of fields to be used as . + selected - The value of the selected