Tip: Printer friendly pages with Page Templates in Zope

24 March 2008   0 comments   Zope

Powered by Fusion×

Since I've seen so many poor solutions to this problem I thought I'd share mine. Here's how I make printer friendly pages.

1. Add a method in your base class that looks like this:

 def getMainTemplate(self):
      """ return the suitable METAL header object """
      # assuming zpt/main_template.zpt
      template_obj = self.main_template

      # assuming the "first" line of main_template.zpt to
      # look like this:
      # <metal:block metal:define-macro="master">
      return template_obj.macros['master']

2. Change all your Page Templates to refer to a method rather than a macro directly so that pages like index_html.zpt start like this:

<html metal:use-macro="here/getMainTemplate">

I've seen the hard coded way too many times where people do something like this <html metal:use-macro="here/main_template/macros/master"> which gives you no flexibility.

3. Now make a copy of main_template.zpt called print_main_template.zpt and the most important change is to make print.css load by default. Here's what it should look like this somewhere inside the <head> tag:

<link rel="stylesheet" type="text/css" href="/screen.css" media="screen" />
<link rel="stylesheet" type="text/css" href="/print.css" />

Note how the print.css link tag is now not conditional. Before in main_template.zpt it should have looked like this:

<link rel="stylesheet" type="text/css" href="/print.css" media="print" /> 
<link rel="stylesheet" type="text/css" href="/screen.css" media="screen" />

And note how the order is stacked just to be extra safe to weird browsers that don't understand the media condition.

As a last optional feature you should add is to add these lines at the bottom of the template 'print_main_template.zpt':

<script type="text/javascript">
window.print();
</script>
</body>
</html>

Another tip is to add something like this to the footer because it becomes useful when you look at a printed copy:

<div id="footer">
   Printed from <span tal:replace="here/absolute_url"></span> on 
   <span tal:replace="python:here.ZopeTime().strftime('%Y/%m/%d')"></span>

4. Now rewrite the method getMainTemplate() to become usefully intelligent:

  def getMainTemplate(self):
      """ return the suitable METAL header object """
      if self.REQUEST.get('print-version'):
          # assuming zpt/print_main_template.zpt
          template_obj = self.print_main_template
      else:
          # assuming zpt/main_template.zpt
          template_obj = self.main_template

      # assuming the "first" line of main_template.zpt to
      # look like this:
      # <metal:block metal:define-macro="master">
      return template_obj.macros['master']

5. Prepare the interface now for the printer friendly page. This can be done in two different ways. One way is to put a link in the footer or byline like this:

<a href="?print-version=1">Print this page</a>

Or if you want to force a particular page to always be printer friendly, for example print_invoice.zpt then write it like this:

<tal:item define="dummy python:request.set('print-version',1)"
          replace="nothing" 
 /><html metal:use-macro="here/getMainTemplate">

As a final point; how you solve your web design with screen.css and print.css varies. One way is to define multiple css files each suitable for individual things like this example shows:

<link rel="stylesheet" type="text/css" href="/typography.css" /> 
<link rel="stylesheet" type="text/css" href="/print.css" media="print" /> 
<link rel="stylesheet" type="text/css" href="/screen.css" media="screen" />

An alternative solution is to don't expect print.css to stand on its own two legs but only be a supplement of the general css file. When doing this you're probably just going to want to override some things and hide some other things like this example from a 'print.css':

body {
   width:100% !important
}

form#login, #navigation, .also-online {
  display:none
}

To conclude

This gives you a robust framework for enabling printer friendly pages that are quite different from the main template and doing it like this means that you don't have add conditional hacks to your main template that displays certain things if in printer friendly mode or not.

Most importantly, this gives you the framework for adding other versions of main template. For example these:

A healthy and fair use of METAL macros is also key to asserting that you don't have to repeat yourself too much in the copies of main_template.pt.

Good luck!

Comments

Thank you for posting a comment

Your email will never ever be published


Related posts

Previous:
apple.com/store doesn't work in Firefox (on Linux) 19 March 2008
Next:
How to uninstall nginx with apt 28 March 2008
Related:
Orphaned Land - Jewish Muslim Metal 08 December 2009
Kalle Kappner - Opeth and Pain of Salvation piano tribute 19 August 2008
Interview with Varg Vikernes 01 July 2008
Printer usability problem 24 August 2007
CSS selector bug in IE? 05 December 2006
More crappy album covers 06 August 2006
Don't put title in a <link> tag 07 January 2006
TAL here hack in Plone 28 April 2005
Find print statements in Python code 12 April 2005
DOCTYPE in PageTemplates with METAL 09 February 2004