Skip to content

Instantly share code, notes, and snippets.

@fulv
Last active November 25, 2017 17:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fulv/bde72273fe1513ee19f386fa2450b3ef to your computer and use it in GitHub Desktop.
Save fulv/bde72273fe1513ee19f386fa2450b3ef to your computer and use it in GitHub Desktop.
Writing LibreOffice templates

Principles

The office document template is a LibreOffice document written normally, except for the significant fact ;-) that it will contain computer code, allowing to display data from the context, to have conditions, to run loops, to incorporate sub-templates, etc.

When generating the document in a given context, the computer code present in the template is "interpreted" and replaced by data to produce the final document.

The computer syntax used is that of the appy framework library, whose "pod" module manages the generation of the document. The "gen" module of that library is not used.

It is possible to insert the computer code in several ways, all explained below. The presence of this computer code does not prevent formatting.

The easiest way to edit a template saved in Plone is to use the "external editor" feature to edit the document and, after each save, directly test the build.

Input Field

The first way to perform the data merge (inserting context data into the document) is to use an input field. To insert a field, in LibreOffice, you must position your cursor at the desired place and go through the "Insert" menu, then "Field" and finally "More fields ..." (or CTRL + F2).

The following window appears:

Insert -> Field -> More Fields

After selecting the "Functions" tab and the "Input field" type, click (once) on "Insert". An additional window is displayed, allowing to enter the computer code in the field.

Input Field

You must type the statement in the second field: in this example "context.title" which will retrieve the "title" attribute of the context. After clicking "OK", the field is inserted into the document. Then, close the "Fields" window to return to the document (by clicking on the "Close" button, or the "x" button, or with the "Esc" key).

Inserted field

To edit an input field, click on it once, which places the mouse cursor at the end of the statement.

Conditional Text field

This field has a purpose identical to the input field but adds a notion of condition. If the condition is true at the time of document generation, the field is rendered. If the condition is false, the field is not rendered and is left in the document, for the purpose of being rendered later! This is the case, for example, of a mail merge field that must be rendered only after the mail merge action.

To insert a Conditional Text field, in LibreOffice, you must position your cursor in the desired position and go through the "Insert" menu, then "Field" and finally "More fields ..." (or Ctrl + F2).

After having selected the "Functions" tab and the "Conditional Text" type, fill in the fields:

  • "Condition": this is the condition that will be tested to see if the field should be rendered or not.
  • "Then": this is the instruction of the field. Beware: these two fields must be defined as text, i.e. surrounded by single or double quote.

Conditional text

Finally, click (only once) on "Insert" to insert this field. It is then necessary to close the "Fields" window to return to the document (by clicking "Close", or "x" or with the "Esc" key).

AT first glance, the Conditional Text field looks like the Input field, but if you hover the mouse cursor on it for 2 seconds, the condition appears on a black background.

Condition

It is also possible to more easily distinguish the 2 types of fields via the following method. Via the "View" menu, click on "Field Names" or use the shortcut "Ctrl + F9".

Field Names

The input field does not display any particular information while the Conditional Text field contains the type as well as the condition in addition to the field code.

To modify a conditional text field, double click it. This will open a window almost identical to the insertion which allows to modify the values.

Edit conditional field

Comments

A comment allows to introduce code to carry out more complex operations than to integrate a simple value in the document. It will allow the following things:

  • integrate document parts via sub templates.
  • evaluate conditions for the rendering of a section, paragraph, title, table, table row, or table cell.
  • run loops to repeat the rendering of the same types of elements mentioned above.
  • define variables to simplify the computer code.

To insert a comment in LibreOffice you must position your cursor at the desired place and use the "Insert" menu, then "Comment" (or Ctrl + Alt + c).

The comment is displayed in the right column and it allows you to enter the desired code.

Comment

In our example, the code renders the corresponding paragraph if the toto variable is set.

To edit a comment, simply position the cursor inside it.

When generating from this template on the context of the homepage of a standard site and with the variable "toto", we obtain the following result:

toto

With the same template but without the variable "toto", we obtain the result:

without toto

We can see that the paragraph related to the comment is missing and that the Conditional Text field has not been rendered.

Rendering Context

At rendering time, a set of data corresponding to the context is available in the template. This dataset may vary by application.

By default, the following data is available:

  • context: this is an object "representing" the content item of the site on which the template is generated and allowing to call most of its attributes (title, description, etc.).
  • view: this is an object (helper view) with a set of methods (functions) that can be called.

The data defined in the "Context Variables" field of the template is also added to the available set. So if the field sets a variable named toto to the value "1", it will be available directly under its name as well as as a member of the "context" or "view" objects.

In the case of a mail merge template, it is necessary to use the variable mailed_data to contain each element of the mailing list returned by the method of the helper view mailing_list. This variable can contain anything you want (objects, dictionaries).

In the case of a collection template, the template is rendered according to the content items selected by it. The dataset contains two more variables:

  • brains: this is the list of the selected content items (in the form of catalog items)
  • uids: this is the list of the selected content items (as unique identifiers)

Helper View

A default view providing standard methods is always available. However, each application extends the basic methods with methods more specific to the application and the bound context.

The base view has the following attributes:

  • real_context: this is the content item of the site on which the template is rendered.
  • portal: this is the "plone site" object.

The base view offers the following methods:

  • get_value: returns the value stored in the field corresponding to the name passed as parameter.
  • display: renders a field (whose name is passed as a parameter), in a "smarter" way than with "get_value".
  • display_date: returns a field or date passed as parameter.
  • display_list: renderss a list field as a single string.
  • display_voc: renders a dictionary field as a single string.
  • display_text_as_html: returns the conversion of a text field to html.
  • display_html_as_text: returns the conversion of an html (rich text) field to a plain text field.
  • display_widget: renders a field in html format, as rendered in the browser.
  • translate: returnss the translation of a character string in another language.
  • get_state: return the state of the context.
  • context_var: tests whether a variable exists in the available data set of the document and returns its value if any.
  • getDGHV: returns the helper view of another context passed as parameter.
  • mailing_list: returns the list of mail merge items (for example mail recipients)

appy.pod Syntax

This is the particular syntax recognized by the appy.pod module that transforms the computer code of the template into LibreOffice content.

Let's first define some elements

<python_expression>: This is a standard python expression that returns a value. It can use the variables present in the generation context.

<document_part> : This is an element representing part of the document. The possible values are:

  • text: for a paragraph
  • title: for a title
  • section: for a section
  • table: for a table
  • row: for a table row
  • cell: for a table cell

<label> : This is a label that can be specified at the beginning of an appy expression. It ends with :. The label can be alpha-numeric and also contain the character _.

Expressions recognized by appy

In a field, you just have to enter a python expression, as defined above.

Comments accept a more particular syntax for performing operations that can be a bit more complex.

Text enclosed in square brackets is optional in expression syntax.

[label:] do <document_part> if <python_expression>
Includes the referenced document part if the condition is met

do <document_part> else [<label>]
Includes the referenced document part if the last condition used in a previous comment is not met. In order to clearly link the "else" command with the corresponding "if", it is recommended to use a label on the "if" and to refer to it after "else". For example: titi: do text if titi=='gentil' followed by do text else titi

do <document_part> with <python_expression>
Defines variables in the python expression, separated by ; if there are several. Variables can be separated by spaces. No ; at the end! Example: do text with titi='nice'; grosminet='bad' .

do <document_part> for <variable_name>[, <variable_name>] in <python_expression>
Repeats the referenced document part for each value in the list returned by the python expression. At each iteration, the value is stored in the specified variable name.

do <document_part>
from <python_expression>
Replaces the document part with the value returned by the python expression, which must be "xml" code compatible with the LibreOffice format. The keyword from must be put on a new line! The python expression will usually use an appy.pod function (see below).

do <document_part> meta-if <python_expression>
This is the equivalent of the Conditional Text field but for a comment. If the condition is met the comment is interpreted and replaced. If the condition is not fulfilled, the comment is left as it is in the document and will require a second "pass" to replace it, ie a new rendering by taking the first generated document as a template.

Combination of expressions

It is possible to combine appy expressions.
Expressions must be interpreted one after the other (from top to bottom).
It is necessary to separate them by a line break.

For example, the following code is used to loop through a list of people in a group list, provided that the names of people start with P or R.

do text with groups = view.getGroups()
for group in groups
with persons = group.persons
for p in persons
if p.name.startswith('P') or p.name.startswith('R')

Features offered by appy.pod

xhtml: This function transforms xhtml (a rich text field) to LibreOffice xml. It is therefore to be used with the expression do ... from xhtml (...)

document: This function allows you to include another LibreOffice document or an image. It can therefore be used to integrate a sub-template . It is to be used with the expression do ... from document (...)

pod: This function allows you to include the rendering of another template. It can therefore be used to integrate a sub-template. It is to be used with the expression do ... from pod (...)

Syntax Errors

A comment containing a part of referenced document must obviously be in this type of element. For example, putting a comment with the document part table outside of a table will cause an error!

It is necessary to use true quote ' or double quote " characters inside field or comment strings. Make sure that LibreOffice does not replace them with "fancier" quote characters. If this is the case, you must either prevent this replacement globally in the configuration, or do a Ctrl + z just after typing the character.

The python and appy.pod expressions are case-sensitive. Make sure that LibreOffice does not capitalize them at the beginning of the sentence for example. If this is the case, you must do a Ctrl + z just after typing the character.

When inserting fields, it may happen to click several times on the "Insert" button which can insert an empty field. In this case, the rendering crashes. In this case it is helpful to double click on the first field (once for an input field and once for a Conditional Text field) and to use the arrows on the bottom left to move from one field to the other to check if they are all filled. In case of an empty field, it is necessary to leave the window "Fields" and to erase it in the document.

If an error occurs while interpreting a comment, the error is displayed in a comment in the generated document.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment