views:

111

answers:

2

I'm trying to do some customization of a Trac project management website and have run into an interesting problem. The project has a set of images that are both SVG and PNG. The SVG images have numerous advantages including multiple hyperlinks and a smaller transmitted size against PNG which is bigger and can only link to a single document.

I realize that it is possible to use jQuery to sniff out the user agent after the page has been loaded and replace the PNG with the SVG version of the image, but this results in the PNG being sent to all clients. I also can have Genshi replace the PNG with SVG for all clients and then use jQuery to put the PNG back, but the same problem results. I could use jQuery to insert the appropriate images for all clients, but that just seems silly to require the client to do what the server should.

Is there a way I can get browser information inside of a Genshi template? It's a little more difficult than just calling for environment variables because of the fact that I'm running Trac using WSGI. I've looked through the output of repr(locals()) and didn't see anything that looked like it solved my problem. I'd also like to avoid modifying the Trac source code.

A: 
user_agent = environ.get('HTTP_USER_AGENT', None)

Or if environ is wrapped in some sort of Request object:

user_agent = request.user_agent

btw, You should probably look at HTTP_ACCEPT header instead of HTTP_USER_AGENT to find out what representation should be sent.

J.F. Sebastian
Yup, in a CGI environment or inside of a WSGI app I could do those, but `environ` is empty inside Genshi and I can't figure out where/if the request object is passed to Genshi from Trac/WSGI. Also, HTTP_ACCEPT is probably a no go because some browsers lie and say they can accept SVG but do so poorly -- I'm looking at you Chrome! What gives with the giant white boxes for backgrounds‽
Pridkett
@Pridkett: grep your trac source for the template name and pass required variables there in the rendering code.
J.F. Sebastian
I'm trying to avoid changing the Trac source code. I've gone down that path too many times and don't really want to worry about managing a variety of patches -- even really simple ones.
Pridkett
A: 

Okay, so I did some digging on the issue, not by grepping through the source code, but by writing a custom Genshi handler that spit out the recursive repr() of every element in locals (with help provided by a previous question that addressed how to print out all variables in scope). I had originally missed the req object. It looks like it's as simple as using req.environ['HTTP_USER_AGENT']. The problem was in finding the req object in the first place. Grepping through the source code I still can't find exactly where the templates are instantiated, so this proves to be much easier and better than a patch.

For completeness, here's the bit of Genshi template I used to replace the logo only for newer versions of Gecko based browsers. It's a little hacky and probably suboptimal, but it works and it doesn't send SVG to browsers that lie and say they're "like Gecko" but can't render SVG properly -- yes, I'm looking at you Webkit.

<py:if test="'Gecko/' in req.environ['HTTP_USER_AGENT'] and [int(x.split('/')[1]) for x in req.environ['HTTP_USER_AGENT'].split() if x.startswith('Gecko')][0] &gt; 20080101">
  <div py:match="div[@id='header']">
    <object type="image/svg+xml" id="svgLogo" data="${href.chrome('site/logo.svg')}" style="width=${chrome['logo']['width']}px; height=${chrome['logo']['height']}px;"></object>
  </div>
</py:if>
Pridkett