Per Erik Strandberg /cv /kurser /blog

Summary

This tutorial is my attempt to modify the edit mode of my content types in Plone Cms. I do this by modifying the macro of the widget of the field of the archetypes content type.

Short Background

There are many way of doing this, here I only touch upon the Plone Custom Widget Macro Thingie's.

More info on this and related areas are found in

You can download this tutorial in two version:

Introducing the content type we work with

It has a very simple schema - we want to be able to select one of a number of colors or write in a separate field the name of some exotic color:

colors = ['red', 'green', 'blue', 'cyan', 'magenta', 'yellow', 'black']
schema = BaseSchema.copy() + Schema((
    StringField('FavColor',
        vocabulary = colors,
        default = colors[2],
        widget = SelectionWidget(format = 'radio', ),
        ),
    StringField('OtherColor', ),
    ))

Creating content of this type will look something like this:
http://www.pererikstrandberg.se/blog/plone/specialselection1.png

Viewing it is really not very fancy either:
http://www.pererikstrandberg.se/blog/plone/specialselection2.png

How to modify the Widget Macro Thingie

Before we can modify it: some copy-paste-programming

Modifying the Widget Macro Thingie is not as hard as you first might think - but on the other hand it is not very intuitive either (like everything else in the Plone world).

  1. Register a skins-folder like we do in Plone Archetypes View Template Modifications
  2. Copy Paste some of the built-in macros for the widget you want. In this case we copy the file Archetypes/skins/archetypes/widgets/selection.pt (might be located in your products folder) into products/specialselection/skins/specialselection/special.pt
  3. Tell the field in the schema that you use a particular widget and tell that widget that you want to use a particular macro (see schema below).
  4. Modify the macros in the widget page template file.

Out previously very simple schema is still pretty simple:

colors = ['red', 'green', 'blue',
          'cyan', 'magenta', 'yellow', 'black',
          'Something Completely Different']

schema = BaseSchema.copy() + Schema((
    StringField('FavColor',
        vocabulary = colors,
        default = colors[2],
        widget = SelectionWidget(
            format = 'radio',
            macro = 'special',
            ),
        ),
    StringField('OtherColor',
        widget = StringWidget(
            macro = 'magic',
            ),
        ),
    ))

As I hope you have figured out by now I have also copied the string.pt-file as described in the steps above - that one I copied into magic.

copy-paste-modify-programming closes the circle

As you can see in skins/specialselection/special.pt this is only metal/tal logic to build part of a form. I did some minor changes - including removing the extremely annoying br-tag.

I also wanted to decrease the importance of the OtherColor-field by inserting some pretty ugly logic that lets the viewer know if it is in use or not.

Modifying my content type now looks like this:
http://www.pererikstrandberg.se/blog/plone/specialselection3.png

And looking at it something like this:
http://www.pererikstrandberg.se/blog/plone/specialselection4.png

Or like this if the last radio button is pushed:
http://www.pererikstrandberg.se/blog/plone/specialselection6.png

Making your own widget class

My colleague (Raphael Ritz) hinted me that there is already a widget very similar to what I wanted in the ATExtensions bundle that he wrote some time ago (get it from plone.org: [5]).

It did not exactly do what I wanted but I took it as a starting point to learning how you make your own widget class.

My specialselection package now contains these files:

./README.txt
./__init__.py
./combo.py
./config.py
./specialselection.py
./Extensions/Install.py
./skins/specialselection/combo_widget.pt

Where the new and fancy stuff is in the combo.py-file and the pt-file.

The principal contents of the combo.py is:

from [...] import [...]

class ComboWidget(SelectionWidget):
    [...]

    def process_form( [...] ):
        [...]
        value = form.get( [...] )
        [...]
        return value, {}

InitializeClass(ComboWidget)

registerWidget(ComboWidget, [...] )

As you can see there is a class inheriting from the selection widget class that overrides the method process_form. This file also registers a widget so there is no need for XML/ZCML, nice.

I have modified the page template of the widget slightly and removed everything that is not related to the radio buttons (my plan is to make a more generic path and perhaps check it into the collective once Raphael has looked at it).

Creating the content type now looks like this:
http://www.pererikstrandberg.se/blog/plone/specialselection7.png

You can download this version here: [6]

Contributing to the Free Software Community

When writing this this tutorial Raphael and I agreed that I should send a patch to the combo-widget class. I tried to upgrade the class even more to get it even better and then I sent him a patch - hopefully that will bring the behavior I missed into the official ATExtensions product. That way I help someone else get better software and then they might help me get better software - ah software communism at its best [:)]-|--<


This page belongs in Plone Cms.
This page belongs in Kategori Programmering.