Tip: Printer friendly pages with Page Templates in Zope

March 24, 2008
0 comments Zope

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!

apple.com/store doesn't work in Firefox (on Linux)

March 19, 2008
6 comments Web development

apple.com/store doesn't work in Firefox (on Linux) If you do web design, making your pages work in different browsers can be very frustrating. The most common troublemaker is Internet Explorer and I think everyone who's ever tried hand-coding CSS has experienced. Another thing that makes it hard is simply lack of time to test it in all different browsers and platforms.

But! if it makes you feel any better even Apple is struggling as this screenshot shows.

I've seen Apple.com/store work in Firefox on other computers so clearly it's not a problem on all Firefoxes but you'd think a big site like this must have heard of this and done something about it. If you think that what happens is that the images aren't loaded that not the case. This problem has been around for a while for me now. And no, I don't have Firebug or any other debuggers switched on as I open this site.

Mocking a Python standard library

March 14, 2008
2 comments Zope

Here's one of many things I've learnt today at PyCon. Inspired by code that Grig Gheorghiu showed in his slides on automated testing, you can monkey patch a standard library that your application is using in your unit tests to, in my case, mock a remote service without having to run a server. I've done lots of monkey-patching in Zope but then I've only been monkey patching individual methods or attributes of imported classes. This is very similar to that. Here's what my application does:


from poplib import POP3
class MyZopeApp(...):
   def check4mail(self, hostname, port, user, pwd):
       connection = POP3(hostname, port=port)
       ...download emails and process them...

Adjacent to this I have a unit/integration test that looks like this:


class TestCase(ZopeTestCase):
   def test_check4mail(self):
       # monkey patch!
       # note that this imports a module, not a class
       from Products.IssueTrackerProduct import IssueTracker 
       FakePOP3.files = ('test1.email',)
       IssueTracker.POP3 = FakePOP3

       # now check what happens when check4mail() is run
       result = self.folder.tracker.check4mail()
       assert ...

Truncated! Read the rest by clicking the link below.

See you at PyCon 2008

March 11, 2008
0 comments Python

I'm going to Chicago on Wednesday for the PyCon 2008 conference. I'm going to stay at the Crowne Plaza (or whatever it was called) like many of the other people at the conference.

This is what I look like:

See you at PyCon 2008

If you see this mug, go up to it and say Hi. It speaks British, Swedish and some American and loves food, beer and tea which might be helpful to know if you would feel like to talk more to it. Its interests for this conference are: Grok, Zope, Django, Plone, buildout, automated testing, agile development and Javascript. Its main claim-to-fame is an Open Source bug/issue tracker program called IssueTrackerProduct which it is more than delighted to talk about.

I've never been to Chicago before and I'm really excited about Tuesday night as I've bought tickets to a Chicago Bulls NBA game (basketball). All other nights I'm hoping to socialise, get drunk, get full and get down and dirty nerdy all week. See you there!

File check before delete

March 7, 2008
1 comment Linux

Because I always forget, here's how to check if a file exists before attempting to delete it in bash:


[ -f foobar.html ] &amp;&amp; rm foobar.html

If you don't do it this way and the file doesn't exist you get this:


rm: cannot remove `foobar.html': No such file or directory

"Confessions of a College Callgirl" is the new "My Secret Life As A Prostitute"

March 2, 2008
2 comments Misc. links

Back in 2004 I used to sometimes read a blog called My Secret Life As A Prostitute which was both sexy, sobering and kind of educational. That blog was also a callgirl who wrote about her work-experiences, sex life in general and problems she had with her boyfriend. Sadly that blog disappeared suddenly. Perhaps the girl who wrote it got "discovered". By that I might mean that a colleague of hers at some investment bank found out what she was spending so much time on in her lunch breaks. Jokes aside, it's hard to tell if this is for real or just made up based on someone's fantasy of being an escort girl. Sometimes the blog gets very technical to the point that it's hard to imagine her not being a real call girl.

As I'm skimming through this new blog I find that it's so similar to the one I was skimming back in 2004. She's very blunt and has the same sense of humor and just like the 2004 blog every now and then, as she describes her encounters/jobs she also describes how she herself gets off on it.

Another similarity is that reading this gives the same feeling of shame of reading it. I'm obviously not so ashamed that I can't confess that I'm reading up it does feel a bit intimate and "dirty" at the same time. It's like reading an Bret Easton Ellis book which is sold in respectable normal bookshops but whose content is sometimes worse than porn.

And for people who've seen Flight of the Concordes, check out this post

hostip.info - Look up the location from an IP

March 1, 2008
1 comment Linux

I've never really needed it but I've been looking for a tool that is super easy to use that quickly looks up the location of an IP address. The super easy tool is called hostip.info and this is what happens when you do a lookup on www.peterbe.com's IP at http://api.hostip.info/get_html.php?ip=80.68.212.7 :


Country: UNITED KINGDOM (UK)
City: (Unknown city)

Cool. I'll remember that till next I really need this. I discovered hostip.info by reading this cool blog by Corey Goldberg

CommandLineApp by Doug Hellmann

February 22, 2008
0 comments Python

I just read the feature article "Command line programs are classes, too!" by Doug Hellmann in the January 2008 issue of Python Magazine about his program CommandLineApp and I've tried it out on one of my old Python programs where I do the opt parsing manually with getopt. The results are beautiful and quick. It's sprinkled with Doug specific magic but I quickly got over that when I saw out easy it was to work with. There are still a few questions of things I didn't manage to work out but that will unfortunately have to wait.

If anything, the worst thing about this library is that it's not part of the standard library so either you have to tell people to sudo easy_install CommandLineApp in the instructions or include it yourself in your packages if you prefer to ship things with a kitchen sink included.

If you want to check it out in action, either subscribe to the magazine (and support the effort) or just download csvcat

If Americans knew - An interesting insight into the Israeli Palestine conflict

February 12, 2008
4 comments Politics

If Americans knew - An interesting insight into the Israeli Palestine conflict I'm not a political editor and I can't confirm the validity of these statistics but if they're at least close to true it's a hell of a scary picture of the injustice in the Israeli/Palestine conflict.

Israel receives $6.8 million per day in aid. I doubt that all of that money goes towards building better schools for Israeli families.

Truncated! Read the rest by clicking the link below.

Chinese New Year and the Persecution of Falun Gong in China

February 9, 2008
2 comments Kung Fu

Chinese New Year and the Persecution of Falun Gong in China Today I'm celebrating the Chinese New Year with a big dinner in Chinatown in central London. I love the Chinese people, their food, their culture and am perpetually interested in learning more about them and their ways.

But we mustn't forget that this otherwise great country also has a very very dark side which we must never accept or forget: The Persecution of Falun Gong.

Didn't the nazi persecution of jews teach us anything? Are you aware that Falun Gong practitioners are imprisoned, bullied and tortured? Do you know that this oppression is fully sponsored by the government and not rogue individual groups?

I was made aware of this website (warning: graphical content) and this video just a few days ago. I'm fully aware that China is a big country where many "bad" things can happen due to the sheer numerical chances with such large numbers and such many different internal cultures but that's never an excuse for this barbaric behavior.

Think about it. Remember it.