Tuesday, July 7, 2009

Looking at Alfresco Share 3.2 Community - Part 3 - Customizing forms

This blog will look at how to display custom types and aspects in Share in the edit metadata feature. The previous blog article showed how to associate content with predefined aspects and show them in the edit metadata form.

This example requires Alfresco 3.2 Labs (currently Preview).

Resources:
* Alfresco forms engine wiki page
* Alfresco forms engine examples wiki page

Also see my previous blog entries showing how forms are used in Alfresco Share 3.2

I will use the example project structure offered by Jeff Potts' great article - Extending the Alfresco Content model to extend the content model in Alfresco. For the share customization, I will base my project on the Share extension project example in my blog.

Creating the new Custom content type

For this example, I will create a custom content type and modify the edit metadata form shown in Alfresco Share. The content type I will create will center around a custom type called MarketingContent, with an additional Aspect called Brandable. This custom metadata will add the ability to identify the 'brand' to which the Marketing content should be associated, and will require a custom single-select drop down.

Step 1 - Setup the project to extend Alfresco with custom content

1. Download Jeff Potts' custom content example source
2. Import into Eclipse - assume you already downloaded the Alfresco SDK and imported SDK AlfrescoRemote
3. Fix project references as needed
4. Update build.properties for ant build (alfresco.sdk.remote.home and alfresco.web.root)

Step 2 - Modify project for new custom content model

Four files to modify:
* PROJECT_HOME/src/alfresco/extension/someco-model-content.xml
* PROJECT_HOME/src/alfresco/extension/scModel.xml
* PROJECT_HOME/src/alfresco/extension/web-client-config-custom.xml
* PROJECT_HOME/src/alfresco/extension/webclient.properties

someco-model-content.xml (renamed to 'orbitz-model-content.xml')
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE beans PUBLIC '-//SPRING//DTD BEAN//EN' 'http://www.springframework.org/dtd/spring-beans.dtd'>

<beans>
<!-- Registration of new models -->
<bean id="extension.dictionaryBootstrap" parent="dictionaryModelBootstrap" depends-on="dictionaryBootstrap">
<property name="models">
<list>
<value>alfresco/extension/orbModel.xml</value>
</list>
</property>
</bean>
</beans>

scModel.xml (renamed to 'orbModel.xml')
<?xml version="1.0" encoding="UTF-8"?>
<!-- Definition of new Model -->
<model name="orb:orbitzmodel" xmlns="http://www.alfresco.org/model/dictionary/1.0">

<!-- Optional meta-data about the model -->
<description>Orbitz Marketing Model</description>
<author>Ed Wentworth</author>
<version>1.0</version>

<!-- Imports are required to allow references to definitions in other models -->
<imports>
<!-- Import Alfresco Dictionary Definitions -->
<import uri="http://www.alfresco.org/model/dictionary/1.0" prefix="d" />
<!-- Import Alfresco Content Domain Model Definitions -->
<import uri="http://www.alfresco.org/model/content/1.0" prefix="cm" />
</imports>

<!-- Introduction of new namespaces defined by this model -->
<namespaces>
<namespace uri="http://www.orbitz.com/model/content/1.0" prefix="orb" />
</namespaces>
<constraints>
<constraint name="orb:brands" type="LIST">
<parameter name="allowedValues">
<list>
<value>Orbitz</value>
<value>CheapTickets</value>
<value>eBookers</value>
</list>
</parameter>
<parameter name="caseSensitive"><value>true</value></parameter>
</constraint>
</constraints>

<types>
<!-- Enterprise-wide generic document type -->
<type name="orb:doc">
<title>Orbitz Document</title>
<parent>cm:content</parent>
<mandatory-aspects>
<aspect>cm:generalclassifiable</aspect>
</mandatory-aspects>
</type>

<type name="orb:marketing_content">
<title>Orbitz Marketing Content</title>
<parent>orb:doc</parent>
<properties>
<property name="orb:effective_from">
<type>d:date</type>
</property>
<property name="orb:effective_to">
<type>d:date</type>
</property>
</properties>
</type>
</types>

<aspects>
<aspect name="orb:brandable">
<title>Orbitz Brandable</title>
<properties>
<property name="orb:brand">
<type>d:text</type>
<mandatory>true</mandatory>
<constraints>
<constraint ref="orb:brands"/>
</constraints>
</property>
</properties>
</aspect>

</aspects>
</model>

web-client-config-custom.xml
<alfresco-config>

<!-- add webable aspect properties to property sheet -->
<config evaluator="aspect-name" condition="orb:brandable">
<property-sheet>
<show-property name="orb:brand" display-label-id="brand" />
</property-sheet>
</config>

<!-- show related documents association on doc property sheet -->
<config evaluator="node-type" condition="orb:doc">
<property-sheet>
</property-sheet>
</config>

<!-- show related documents association on whitepaper property sheet -->
<config evaluator="node-type" condition="orb:marketing_content">
<property-sheet>
<show-property name="orb:effective_from" display-label-id="effective_from" />
<show-property name="orb:effective_to" display-label-id="effective_to" />
</property-sheet>
</config>

<!-- add orbitz types to add content list -->
<config evaluator="string-compare" condition="Content Wizards">
<content-types>
<type name="orb:doc" />
<type name="orb:marketing_content" />
</content-types>
</config>

<config evaluator="string-compare" condition="Action Wizards">
<!-- The list of aspects to show in the add/remove features action -->
<!-- and the has-aspect condition -->
<aspects>
<aspect name="orb:brandable"/>
</aspects>

<!-- The list of types shown in the is-subtype condition -->
<subtypes>
<type name="orb:doc" />
<type name="orb:marketing_content" />
</subtypes>

<!-- The list of content and/or folder types shown in the specialise-type action -->
<specialise-types>
<type name="orb:doc" />
<type name="orb:marketing_content" />
</specialise-types>
</config>

<config evaluator="string-compare" condition="Advanced Search">
<advanced-search>
<content-types>
<type name="orb:doc" />
<type name="orb:marketing_content" />
</content-types>
<custom-properties>
<meta-data aspect="orb:brandable" property="orb:brand" display-label-id="brand" />
</custom-properties>
</advanced-search>
</config>
</alfresco-config>

webclient.properties
#orb:marketing_content
effective_from=Effective From
effective_to=Effective To

#orb:brandable
brand=Brand


Step 3 - Deploy

Make sure that build.properties is properly configured

  1. Run ant deploy

Step 4 - Test Model
As a prerequisite, you should go to Share client and create a new site (i.e. 'Merchandising')
  1. In Alfresco Explorer client - Upload content as type 'Marketing Content'
  2. Apply 'Brandable' aspect
  3. Modify content propertis -- should look like picture below




In order for this form to render, we need to modify the forms configuration to let Share know how to render our custom type and aspect. For details on this, see the forms wiki and forms examples wiki pages.

Step 5: Configure share to render the orb:market_content type and orb:brandable aspect

Create a file named 'web-framework-config-custom.xml' and deploy it to the share/WEB-INF/classes/alfresco/web-extension directory with the contents:
<alfresco-config>

<config evaluator="node-type" condition="orb:marketing_content">
<forms>
<form>
<field-visibility>
<!-- inherited from cm:content -->
<show id="cm:name" />
<show id="cm:title" force="true" />
<show id="cm:description" force="true" />
<show id="mimetype" />
<show id="cm:author" force="true" />
<show id="size" for-mode="view" />
<show id="cm:creator" for-mode="view" />
<show id="cm:created" for-mode="view" />
<show id="cm:modifier" for-mode="view" />
<show id="cm:modified" for-mode="view" />

<!-- specific for orb:marketing_content -->
<show id="orb:effective_from" />
<show id="orb:effective_to" />

<!-- aspect orb:brandable -->
<show id="orb:brand" />

</field-visibility>
<appearance>
<field id="orb:effective_from" label="Effective From"/>
<field id="orb:effective_to" label="Effective To"/>
<field id="orb:brand" label="Brand">
<control template="controls/selectone.ftl">
<control-param name="options">Orbitz,CheapTickets,eBookers</control-param>
</control>
</field>
</appearance>
</form>
</forms>
</config>
</alfresco-config>


As we see here, we needed to copy all of the default properties from cm:content as well as add our unique properties for orb:marketing_content, and add the orb:brands aspect. This gives us very fine-grained control, but we can see there could be a lot of repeated configurations if we use types with aspects in complex ways.

Step 5: Run the example

Now we can go ahead and restart share and log in and select 'edit metadata' of our content previously checked in with the type orb:marketing_content and set with the orb:brandable aspect.

Now we should see the following:



We customized the selectone.ftl control template to provide our list of brands. One can consider an extension to this control would be to look up this list from a data web-script.

We should create our own selectone lookup from an external source in an ajax way. We will do so in a further blog article.