3.5 Albatross Macros

In the previous section we demonstrated a program which can be used to display pages from a collection of template files. You might recall that the HTML in the template files was very repetitive. In this section you will see how Albatross macros can be used to introduce a common look to all HTML pages.

If we look at the main.html template file again you will notice that there really is very little content which is unique to this page.

<html>
 <head>
  <title>Simple Content Management - main page.</title>
 </head>
 <body>
  <h1>Simple Content Management - main page</h1>
  <hr noshade>
  This is the main page.
 </body>
</html>

Using Albatross macros we can place all of the boilerplate into a macro. Once defined, the macro can be reused in all template files.

The sample program from this section is supplied in the samples/templates/content2 directory and can be installed in your web server cgi-bin directory by running the following commands.

cd samples/templates/content2
python install.py

First consider the macro in the macros.html template file.

<al-macro name="doc">
<html>
 <head>
  <title>Simple Content Management - <al-usearg name="title"></title>
 </head>
 <body>
  <h1>Simple Content Management - <al-usearg name="title"></h1>
  <hr noshade>
  <al-usearg>
 </body>
</html>
</al-macro>

Now we can change main.html to use the macro.

<al-expand name="doc">
  <al-setarg name="title">main page</al-setarg>
  This is the main page.
</al-expand>

Likewise, the other.html file.

<al-expand name="doc">
  <al-setarg name="title">other page</al-setarg>
  This is the other page.
</al-expand>

And finally the error page oops1.html.

<al-expand name="doc">
  <al-setarg name="title">error page</al-setarg>
  <al-if expr="page == 'oops.html'">
   You actually requested the error page!
  <al-else>
   Sorry, the page <font color="red"><al-value expr="page"></font>
   does not exist.
  </al-if>
</al-expand>

We also have to modify the application to load the macro definition before loading the requested pages.

#!/usr/bin/python
import os
from albatross import SimpleContext, TemplateLoadError

script_name = os.environ['SCRIPT_NAME']
request_uri = os.environ['REQUEST_URI']
page = request_uri[len(script_name) + 1:]
if not page or os.path.dirname(page):
    page = 'main.html'

ctx = SimpleContext('templ')
ctx.load_template('macros.html').to_html(ctx)
ctx.locals.page = page
try:
    templ = ctx.load_template(page)
except TemplateLoadError:
    templ = ctx.load_template('oops.html')

templ.to_html(ctx)

print 'Content-Type: text/html'
print
ctx.flush_content()

Test the program by trying a few requests with your browser:

http://www.object-craft.com.au/cgi-bin/alsamp/content2/content.py
http://www.object-craft.com.au/cgi-bin/alsamp/content2/content.py/main.html
http://www.object-craft.com.au/cgi-bin/alsamp/content2/content.py/other.html
http://www.object-craft.com.au/cgi-bin/alsamp/content2/content.py/error.html
http://www.object-craft.com.au/cgi-bin/alsamp/content2/content.py/oops.html

The only new line in this program is the following:

ctx.load_template('macros.html').to_html(ctx)

This loads the file which contains the macro definition and then executes it. Executing the macro definition registers the macro with the execution context, it does not produce any output. This means that once defined the macro is available to all templates interpreted by the execution context. The template is not needed once the macro has been registered so we can discard the template file.

When you use Albatross application objects the macro definition is registered in the application object so can be defined once and then used with all execution contexts.

There is one small problem with the program. What happens if the browser requests macros.html? Suffice to say, you do not get much useful output. The way to handle this problem is to modify the program to treat requests for macros.html as an error.

Let's revisit the macro definition in macros.html and see how it works. Albatross macros use four tags; <al-macro>, <al-usearg>, <al-expand>, and <al-setarg>.

<al-macro name="doc">
<html>
 <head>
  <title>Simple Content Management - <al-usearg name="title"></title>
 </head>
 <body>
  <h1>Simple Content Management - <al-usearg name="title"></h1>
  <hr noshade>
  <al-usearg>
 </body>
</html>
</al-macro>

The <al-macro> tag is used to define a named macro. The name attribute uniquely identifies the macro within the execution context. In our template file we have defined a macro called "doc". All content enclosed in the <al-macro> tag will be substituted when the macro is expanded via the <al-expand> tag.

In all but the most simple macros you will want to pass some arguments to the macro. The place where the arguments will be expanded is controlled via the <al-usearg> tag in the macro definition. All macros accept an ``unnamed'' argument which captures all of the content within the <al-expand> tag not enclosed by <al-setarg> tags. The unnamed argument is retrieved within the macro definition by using <al-usearg> without specifying a name attribute.

In our example we used a fairly complex macro. If you are still a bit confused the following sections should hopefully clear up that confusion.



Subsections