In a previous post I reviewed five Alfresco plugins that provide custom picklist fields. The plugins differ in the way they store the list of values, but almost all of them share the fact that the field is displayed as a picklist and that the list of values can be controlled by an admin user at runtime.
In this post I’m going to show how these plugins work behind the scenes. Not surprisingly, they’re all similar and they all follow Alfresco’s guidelines for custom fields. So chances are that they’ll be useful examples in case you need to develop a custom picklist field yourself.
A reminder of what a picklist is
My previous post discussed this in details but, in a nutshell, a picklist is a part of a form that allows the user to select a value from a number of allowed options:
This post explains how the picklist is implemented in the five Alfresco plugins.
High level view
So here is a high-level picture of how these plugins work (bear with me for the simplifications):
There are three main containers: Web browser, Share and Repo. The various components of the diagram “live” inside one of the containers and interact with each other.
In 10 steps, this is what happens:
- In the web browser, a page needs to display a form for a certain content. A request is sent to the form service.
- The form service (discussed in a later section) needs to find out how to render a form for the given content. For starters, it asks the repo to provide the content’s type metadata.
- The form service looks at its form definitions and finds the one that can handle the given content type.
- The form service scans the form definition field by field. A certain field requires to be rendered as a custom picklist. It does so by pointing to a custom field “control”, basically a Freemarker template.
- The form service returns the requested html form to the browser.
- Part of the form is rendered by the custom control as an html picklist. At this point the picklist has no values/options.
- The YUI component/code runs an AJAX query to retrieve the picklist values. The request is sent to Alfresco’s repo, with Share working as a proxy.
- The custom webscript on the repository queries the picklist value store. This is where the five plugins differ the most. Two use data-lists, one uses entries in the data dictionary, another one queries users, yet another one consults the content model’s constraints. The implementations can be many.
Since the form service plays and important part in this process, in the next sections we’ll see in general what the form service is and specifically how it is used by picklist plugins.
The form service and its form controls
Alfresco has a build-it form service that is responsible for rendering forms for a variety of content types. The form service is fundamentally a Share presentation component, although internally it relies on the content metadata provided by Alfresco’s repo.
Forms are defined via xml. The definition of forms for the basic content types (cm:content, cm:folder, etc) can be found in share/WEB-INF/classes/alfresco/share-form-config.xml, but other definitions and config files can be added to deal with custom content types.
A form definition may look like this:
The form service delegates the rendition of a field to an associated control, basically a Freemarker template that generates the field’s html. Share has some 40 standard controls that can be found under share/WEB-INF/classes/alfresco/site-webscripts/org/alfresco/components/form/controls/. They range from something as simple as an html text input to something as complex as a node selector that pops-up in a dialog. There are controls to deal with workflow forms, too.
Picklist control example
One of Share’s standard controls (‘selectone.ftl’) is responsible for rendering picklists. The five picklist plugins introduce custom variations of selectone.ftl.
As an example let’s see customselectone.ftl from the Alfresco Listmanager plugin.
Acando.CustomSelectOne, this is necessary to ensure that the component is properly initialised when the form is rendered on the browser. But the really interesting stuff happens in the
onReady() method (lines 82-123) where the ajax call is made to retrieve the values from the repository.
Further examples and details
It would take too much time on my side and patience on your side to go through all the details of all the plugins, but if you’re curious here are a few pointers to the most relevant files in each plugins.
- The control template This plugin piggybacks on standard Alfresco constraints and for this reason works without invoking any webscripts.
Share UI customisation is one of the most difficult topics in Alfresco, requiring knowledge of the architecture, of the configurations, of server-side and client-side programming and, last but not least, of the YUI framework (and more recently of Dojo/Aikau). The code discussed in this post supports my point. But plugins are made of no more than ten key files each, so they provide bite-size examples of what can be done in larger projects.