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:
mobile_main_template.zpt
(guess what for)minimal_main_template.zpt
(for things like Help page popups)
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!