Wednesday, July 7, 2010

Adding CSS that uses settings from content

Use case



A client wants to display a section of their site in a slightly different style. This different style currently consists of adding a background image, which should be changed by content editors who have no technical knowledge of CSS, and who we don't want to bother with things like the ZMI.

Approach



The object at the top of the section is a custom content type. We can add a background_image attribute to that, so content editors can change it. But can we get that into a CSS file?

Attempt 1: a skin template CSS file



First off, i tried to add a skin template to generate the CSS. This worked beautifully when calling section_object/my_skin_template.css. Unfortunately, CSS that is included by Plone's portal_css tool has the portal root as context, so my lookup of the background_image attribute never found anything.

Solution: A CSS viewlet



Adding a viewlet to the plone.htmlhead.links viewlet manager solved my problem.

browser/viewlets.zcml:

<browser:viewlet
name="myproduct.sectioncss"
manager="plone.app.layout.viewlets.interfaces.IHtmlHeadLinks"
class=".viewlets.SectionCSS"
layer=".interfaces.IMyProduct"
permission="zope2.View"
/>


This will render the viewlet in the <head> tag, so we can generate an internal style sheet here.

browser/viewlets.py:

class SectionCSS(ViewletBase):

def getBackgroundImageUrl(self):
return_value = None
try:
bg_image = self.context.getBackground_image()
return_value = bg_image.absolute_url()
except:
pass
return return_value

def render(self):
return_string = ''
image_url = self.getBackgroundImageUrl()
if image_url:
return_string = "<style type='text/css'>body { background-image: url('%s'); } </style>" % image_url
return return_string




What's next



There's much room for improvement here: The try/except will have to go, for example. I'm also curious what other people have done to solve this problem.

Saturday, July 3, 2010

iPython in Plone 4

[edit (2010-07-30): add link to full iPython extension script which doesn't require login]

The Plone 3 Products Development Cookbook shows a way to make your Plone 3 buildout create a Zope-aware iPython script. With a slight modification, the script can be used for Plone 4 as well.

buildout.cfg:
parts +=
    ipzope

[ipzope]
# an IPython Shell for interactive use with zope running.
# You also need to put
# https://svn.plone.org/svn/collective/dotipython/branches/plone4/
# ipy_profile_zope.py
# in your $HOME/.ipython directory for the following to work.
# You may have to remove an existing ipy_profile_zope.py: if you 
# get errors when running ./bin/ipzope, check the stack trace for that 
# filename to make sure the correct version is used. 
recipe = zc.recipe.egg
eggs =
    ipython
    ${instance:eggs}
initialization =
    import sys, os
    os.environ["INSTANCE_HOME"] = "${instance:location}"
    sys.argv[1:1] = "-p zope".split()
scripts = ipython=ipzope


The modification makes the script check if a SOFTWARE_HOME environment variable existst. If not, it assumes we have an egg-based Zope (2.12 or higher). The full script is available from SVN.

The script still works with older Zope versions (Plone 3), so i think the branch can be merged. Note that in a Plone 3 buildout, you'd also have to define extra-paths = ${zope2:location}/lib/python in the [ipzope] part.

Thursday, July 1, 2010

Find my commits SVN script

This script finds all log messages for commits that you've done in (or below) the current SVN-controlled directory.

#!/bin/bash
#
# svn_my_commits_here.sh
#
# Find all my commits _ever_ in this level of the repository (and below).

repo_url=`svn info | sed -n 's/^URL: *//p'`
# Multiple usernames can be given, separated by \|
username='joesmith\|jsmith'

for revision in `svn log -q $repo_url | sed -n "s/r\([0-9]*\) | \($username\) |.*/\1/p"`
do
svn log -vr $revision $repo_url
done