Templating
WSC's new Version 3 Website generates a page by the layout defined in a Template.
The Template uses a system known as H2O to put the relevant data in the correct place.
Contents
Standard Model Templates
A simple model (a model is a programmatical representation of an object, such as a Person, Film, News Article, Social) will have the following standard templates:
- New
- View
- Search (note that you can browse by using Search without any parameters)
- Edit
Delete is dealt with by a more generic template.
Standard Template Locations
Templates should be in the templates directory, under the model's folder name (e.g. Person) and then in a text file called the standard name (e.g. view). This can then be referred to as Person/view.
Creating a Template
All templates should contain as the top line:
{% extends 'default' %}
And then, depending on the main menu icon the page needs to appear under (this for example is for pages under the schedule icon):
{% block menu %}{% include '/menus/schedule' %}{% endblock %} {% block submenu %}{% include '/submenus/schedule' %}{% endblock %}
"schedule" can be replaced with any of "admin", "crew", "contact" or "society". Remember to replace it in BOTH lines.
The next declaration should set the Page's Title. This is the text you see in the browser's title bar, or in the tab itself in your browser, and will be suffixed with ' - Warwick Student Cinema'.
Here is an example of how to set the page title to the text 'New News Article':
{% block title %}New News Article{% endblock %}
You then need to set the page content. Place content between the 'block content' and 'endblock' tags, for example
{% block content %} < Page Content Goes Here > {% endblock %}
Inserting Content
Content should be located in the content block.
You can write any HTML code and it will be placed automatically on the page between the header and footer and standard formatting (such as font, sizes and colours) will be applied.
Considerations to make when making the content:
- What do you need this page to tell you? A good basis would be whatever the current website provides.
- How are you going to lay it out, to make best use of screen space (i.e. with columns?)
- New and Edit pages should, normally, look exactly like the View page, but with form input fields instead.
- Edit pages should include the current text in the field (e.g. use the value property of most form fields, or the selected property for radios/checkboxes/selects)
When you want to put a certain property of the model (e.g. for the Person model, the person's University Number), you use '{{', a space, the model name in lower case (e.g. person), a full stop, the property (e.g. uni_number), another space and then '}}'. For example;
{{ person.uni_number }}
Properties are named the same as in the database. In the case of creating templates for a programmer for a model which has not been written, use your best guess as to a sensible property name. Replace spaces with underscores and always use lower case.
HTML Standards
We are using XHTML. This means elements must either open (e.g. ) and then close () or be self closing (e.g. <img .... />). "More on Basic XHTML"
Please follow "K&R Indenting Standards" - basically, indent by an extra tab every time you open a new block and indent by one less when you close a block. The exact specifics of K&R do not apply in the templating engine.
If you open an element inside a certain block (e.g. <div><table>), you MUST close it before you can close the outer block (e.g. </table> MUST occur before </div> can).
Include any CSS you wish to use in the style tag, we will move it later to the main stylesheet.
Please don't create images for pages, we'll do these later, and its awkward and difficult to make uniform. Some templates will need image holders for their model's content - that's fine (e.g. Photo for Person, Graphic for Film), and don't forget any heights/widths you want to specify and an alt tag!
Tables are strictly for tabular data. If you are trying to position content, you are looking for <div> and CSS.
Generic Properties Available to All Templates
The 'user' model is available to all templates loaded with the current web user's data. This means you can use, as a few examples:
- user.person.nickname to get the current logged in user's nickname
- user.person.firstname to get the current logged in user's firstname
- now gives the current server timestamp.
Conditional Segments
You can make certain areas of your template appear only if certain conditions are met, using an if statement.
These take the form:
{% if expression %} ... {% endif %}
The expression must evaluate as true. You may also use {% else %}.
An example of an if statement:
{% if group.inherited == true %} inherited {% endif %}
Note that expression comparison operators are: == != < >.
Repeated Elements
If you have a structure you need to repeat, say for each result, then you use a for loop. These take the form:
{% for object in model.objects %} ... {% endfor %}
The loop will take all of the objects in model.objects and give them to you, one at a time, called object.
For example;
{% for contact in person.contacts %}
{{ contact.name }} {{ contact.value }} {% endfor %}
Dates and Times
Please parse these through relative_datetime - it changes a timestamp (e.g. 102402405) to '4 hours ago' or '3 days ago at 4:37 PM' or '24th Jan at 8:02 PM' etc. This is done with a pipe and the text 'relativetime'.
For example;
{{ person.membershipExpires | relativetime }}
Example
Generates the Person/view page.
{% extends '../default' %} {% block title %}{{ person.firstname }} {{ person.surname }} ({{person.uni_number}}){% endblock %} {% block content %} <img src="{{ person.image }}" style="width:350px;float:left;" /> <h1>{{ person.firstname }} {{ person.surname }} ({{ person.uni_number }})</h1> {% if person.nickname %} <h3>a.k.a. ({{ person.nickname }})</h3>{% endif %} <h3>{{ person.primary_role }}</h3> <div style="width:100%"> <div style="width:60%;float:left;"> <h3>Contact Details</h3> <table> {% for contactDetail in person.contacts %} <tr> <td>{{ contactDetail.name }}</td> <td>{{ contactDetail.value }}</td> </tr> {% endfor %} </table> <h3>Memberships</h3> {% for group in person.groups %} {% if group.inherited == false %} {{ group.name }} {% if group.expires %} <small> until {{ group.expires | relative_datetime }}</small> {% endif %} <br /> {% endif %} {% endfor %} <h3>Inherited Memberships</h3> <i>These memberships have been added automatically from {{ person.firstname }}'s Primary Roles:</i><br> {% for group in person.groups %} {% if group.inherited == true %} {{ group.name }} {% if group.expires %} <small> until {{ group.expires | relative_datetime }}</small> {% endif %} <br /> {% endif %} {% endfor %} </div> <div style="float:right;width:40%;"> <h3>WSC Membership</h3> <ul> {% if person.membershipExpires < now %} <li>Membership Expired {{ person.membershipExpires | relative_datetime }}</li> {% endif %} {% if person.membershipExpires > now %} <li>Current Member until {{ person.membershipExpires | relative_datetime }}</li> {% endif %} {% if person.membershipExpires == 0 %} <li>Never a Member of Warwick Student Cinema</li> {% endif %} </ul> <h3>Show History</h3> <ul> <li>Number of Shows: {{ person.noShowsWorked }} {% if person.noShowsWorked > 0 %}- <a href=".">View Full History</a>{% endif %}</li> <li>Last Show: <i>{{ person.lastShow.name }}</i> as {{ person.lastShow.role }}</li> </ul> <h3>Comments</h3> {% for comment in person.comments %} {{ comment.content }}<br /> <small>{{ comment.author }} on {{ comment.datetime | relative_datetime }}</small><br /> <br /> {% endfor %} </div> </div> {% endblock %}
Further Reference
Do speak to Edward or Matt in the IT Team in particular.
Also, if you need to do something complicated, H2O's In Built Tags and H2O's In Built Filters may save you some effort.