Custom Action UI

cancel
Showing results for 
Search instead for 
Did you mean: 

Custom Action UI

resplin
Intermediate
0 0 5,826

Obsolete Pages{{Obsolete}}

The official documentation is at: http://docs.alfresco.com



Web Client Customization


Introduction


This example shows how to incorporate a rule based action into the UI. The first part of the example will show how simple it is to add a no-parameter action to the web client. The second part of the example will add parameters to the action and show what needs to be customised in the client to prompt users for the parameter value. This example is also included as the TaggingSample in the SDK.

If you are looking for the older examples for releases prior to 1.3 please go here.

Please note: This example is for Alfresco Explorer. If you want to create a custom action for Alfresco Share go to this page.


Overview


In the first part of this example we are going to add a Web 2.0 style tagging feature to the web client. We'll define a taggable aspect which will be applied via the tag action in the repository. We'll then configure the web client to show the taggable aspect in it's property sheet, create a rule that uses the new action and add some content.

The second part of the example will build on the first. We'll add a parameter to the action in the repository and then show how to add a custom JSP to the web client that can be used to capture the tags. Finally, we'll update the rule to add some tags and add some more content.


Part One


Defining the taggable aspect


We need to define an aspect with a 'tags' property to hold all the user assigned tags, this will be achieved using a custom model. The file containing the model can have any name, we'll call our tagsModel.xml. Create the file and place it in the alfresco.extension package. The model will use a prefix of tag, the aspect will be called taggable and the property will be called tags.

Once defined the model should look like the following:



<model name='tag:tagsmodel' xmlns='http://www.alfresco.org/model/dictionary/1.0'>

   <description>Tagging Model</description>
   <author>Gavin Cornwell</author>
   <version>1.0</version>

   <imports>
      <import uri='http://www.alfresco.org/model/dictionary/1.0' prefix='d'/>
      <import uri='http://www.alfresco.org/model/content/1.0' prefix='cm'/>
   </imports>

   <namespaces>
      <namespace uri='extension.tags' prefix='tag'/>
   </namespaces>
 
    <aspects>
     
      <aspect name='tag:taggable'>
         <title>Taggable</title>
         <properties>
            <property name='tag:tags'>
               <title>Tags</title>
               <type>d:text</type>
               <multiple>true</multiple>
            </property>
         </properties>
      </aspect>
     
   </aspects>
  
</model>

Registering the model


The next step is to register the model with the repository. This is done via a Spring config file, all files ending -context.xml in the alfresco.extension package are automatically loaded, see Repository Configuration for more details.

Create a file called tagging-context.xml and place it in the alfresco.extension package. To register the model you'll need the following XML in your Spring config file:



<bean id='tags.dictionaryBootstrap' parent='dictionaryModelBootstrap' depends-on='dictionaryBootstrap'>
     <property name='models'>
         <list>
             <value>alfresco/extension/tagsModel.xml</value>
         </list>
     </property>
</bean>

Implementing the action


Please refer to the repository Custom Actions guide for full details on creating a custom action.

Our action will have a name of 'tag' and initially will not have any parameters. The action will need the node service injected so that the taggable aspect can be added. Create a Java class called TagActionExecuter in the org.alfresco.sample package and have it extend org.alfresco.repo.action.executer.ActionExecuterAbstractBase.

The executeImpl() method will simply add the aspect to the item if it is not already applied. The body of your TagActionExecuter class should be as follows:



public class TagActionExecuter extends ActionExecuterAbstractBase
{
   public static final String NAME = 'tag';

   private NodeService nodeService;

   public void setNodeService(NodeService nodeService)
   {
      this.nodeService = nodeService;
   }
  
   protected void executeImpl(Action action, NodeRef actionedUponNodeRef)
   {
      if (this.nodeService.exists(actionedUponNodeRef) == true)
      {
         // add the aspect if it is not already present on the node
         QName tagAspect = QName.createQName('extension.tags', 'taggable');
         if (this.nodeService.hasAspect(actionedUponNodeRef, tagAspect) == false)
         {
            this.nodeService.addAspect(actionedUponNodeRef, tagAspect, null);
         }
      }
  }
  
   @Override
   protected void addParameterDefinitions(List<ParameterDefinition> paramList)
   {
      // there are no parameters
   }
}

Registering the action


Registering the action is also done via Spring, we can therefore use the same file we created earlier, tagging-context.xml.

To define the bean that represents the tag action, add the following XML to tagging-context.xml:



<bean id='tag' class='org.alfresco.sample.TagActionExecuter' parent='action-executer' >
   <property name='nodeService'>
      <ref bean='nodeService' />
   </property>
</bean>

The title and description of the action must be specified in a properties file (to allow for localisation), these get used by the UI to describe to the user what the action does. Create a file called tag-action-messages.properties, place it in the org.alfresco.sample package and add the following properties to the file:

tag.title=Add tags to item
tag.description=This action adds tags to the matched item

Once again, this file has to be registered via Spring, add the following XML to tagging-context.xml to ensure the properties file gets read in during the server startup.



<bean id='tag-action-messages' parent='actionResourceBundles'>
   <property name='resourceBundles'>
      <list>
         <value>org.alfresco.sample.tag-action-messages</value>
      </list>
   </property>
</bean>

Configuring the property sheet


That's all we need to do to have the action show up in the Run Action and Create Rule Wizards as you can see in the screenshot below:

Custom-action.gif

It's not much use though having the aspect applied and not being able to add any tags! We therefore need to configure the property sheet for the taggable aspect so that nodes having the taggable aspect will show a multi value editor when editing properties.

Create a file called web-client-config-custom.xml and place it in the alfresco.extension package. Add the following XML to the file to display the tags property from the taggable aspect:



<config evaluator='aspect-name' condition='tag:taggable'>
   <property-sheet>
      <show-property name='tag:tags' />
   </property-sheet>
</config>

Packaging and deploying


Refer to the Packaging And Deploying Extensions guide for instructions on packaging and deploying your extension.

Once deployed, you can create a rule for a space that applies the taggable aspect to any new item. Then if you create or add content in that space the properties page will appear with the editable tags property. An example of this is shown in the screenshot below:

Custom-action-props.gif


Part Two


The goal of part 2 of this example is to add a parameter to the repository tag action to allow the rule administrator to apply some default tags.


Adding a parameter to the action


All we need to do in the TagActionExecuter class is to register a parameter definition. This simply means adding an extra line of code to the addParameterDefintions() method. Change the method as follows:



protected void addParameterDefinitions(List<ParameterDefinition> paramList)
{
   paramList.add(new ParameterDefinitionImpl('tags',
         DataTypeDefinition.TEXT, true, getParamDisplayLabel('tags')));
}

Obviously the tag action also needs to handle any parameters passed to it. The executeImpl() method will now retrieve the comma separated list of tags (if present), build a List of Strings and set the tags property on the node being actioned upon.

The executeImpl() method in your file should now look like:



protected void executeImpl(Action action, NodeRef actionedUponNodeRef)
{
   if (this.nodeService.exists(actionedUponNodeRef) == true)
   {
      // add the aspect if it is not already present on the node
      QName tagAspect = QName.createQName('extension.tags', 'taggable');
      if (this.nodeService.hasAspect(actionedUponNodeRef, tagAspect) == false)
      {
         this.nodeService.addAspect(actionedUponNodeRef, tagAspect, null);
      }
     
      // create the tags as a list
      String tags = (String)action.getParameterValue('tags');
      List<String> tagsList = new ArrayList<String>();
      if (tags != null && tags.length() > 0)
      {
         StringTokenizer tokenizer = new StringTokenizer(tags, ',');
         while (tokenizer.hasMoreTokens())
         {
            tagsList.add(tokenizer.nextToken().trim());
         }
      }
     
      // set the tags property
      QName tagsProp = QName.createQName('extension.tags', 'tags');
      this.nodeService.setProperty(actionedUponNodeRef, tagsProp, (Serializable)tagsList);
   }
}

The final step is to define a display label for the parameter, this is done in the tag-action-messages.properties file, simply add the following line:



tag.param_tags.display-label=Tags

Creating the JSP


Although the action wizards have been converted to the new Wizard Framework the JSPs that collect parameters for actions and conditions are still fully fledged JSPs as they are not displayed with the wizard container. This means you have to have the whole page structure in your action JSP, the easiest thing to do therefore, is to copy an existing one.

For our example, copying /jsp/actions/add-features.jsp is a good start as we only need to replace the drop down list with a text field and change a few labels i.e. the page title

Copy add-features.jsp to /jsp/extension and rename it to tag.jsp. Once you have made the changes mentioned above the key parts of the page should like the following:



<r:page titleId='title_action_tag'>

<f:view>
  
   <f:loadBundle basename='alfresco.messages.webclient' var='msg'/>
   <f:loadBundle basename='alfresco.extension.webclient' var='customMsg'/>
  
   <h:form acceptCharset='UTF-8' id='tag-action'>

   ......

   <tr>
      <td><nobr><h:outputText value='#{customMsg.tags}:'/></nobr>
      <td width='95%'>
         <h:inputText value='#{WizardManager.bean.actionProperties.tags}'
                      size='50' maxlength='1024' />
     
  

   ......

Implementing the action handler


To integrate the action into the action based wizards i.e. the Run Action, Create Rule and Edit Rule Wizards an action handler is required. This class, which typically extends org.alfresco.web.bean.actions.handlers.BaseActionHandler, is responsible for directing the wizard to the page to collect the parameters and marshalling the parameters between the wizard and the repository.

If the page collecting the parameters requires some default setup the setupUIDefaults() method can be overridden, for example, to populate drop downs for a selection box.  In this example we don't need to do this. Create a Java class called TagActionHandler and place it in the org.alfresco.sample package.

The getJSPPath() method should return the path to our JSP i.e. /jsp/extension/tag.jsp. The prepareForSave() method places the tags the user entered into the repository properties map passed in. Conversely, the prepareForEdit() method takes the tags stored in the action and places them in the properties map for the wizard. Finally, the generateSummary() method is used to generate a summary string for the action, this typically includes the parameters added by the user.

The body of your TagActionHandler.java file should look like the following:



public class TagActionHandler extends BaseActionHandler
{
   public static final String PROP_TAGS = 'tags';
  
   public String getJSPPath()
   {
      return '/jsp/extension/tag.jsp';
   }

   public void prepareForSave(Map<String, Serializable> actionProps,
         Map<String, Serializable> repoProps)
   {
      repoProps.put(TagActionExecuter.PARAM_TAGS, (String)actionProps.get(PROP_TAGS));
   }

   public void prepareForEdit(Map<String, Serializable> actionProps,
         Map<String, Serializable> repoProps)
   {
      actionProps.put(PROP_TAGS, (String)repoProps.get(TagActionExecuter.PARAM_TAGS));
   }

   public String generateSummary(FacesContext context, IWizardBean wizard,
         Map<String, Serializable> actionProps)
   {
      String tags = (String)actionProps.get(PROP_TAGS);
      if (tags == null)
      {
         tags = '';
      }
     
      return MessageFormat.format(Application.getMessage(context, 'add_tags'),
            new Object[] {tags});
   }
}

As you can see, to generate the summary we use a new string id, add_tags. This should be defined in our custom webclient.properties file as follows:



add_tags=Add tags {0}

Registering the action handler


The final step is to register the new action handler with the action wizards. This is done via the configuration for the 'Action Wizards' section.

The following XML should be added to our web-client-config-custom.xml



<config evaluator='string-compare' condition='Action Wizards'>
   <action-handlers>
      <handler name='tag' class='org.alfresco.sample.TagActionHandler' />
   </action-handlers>
</config>

Packaging and deploying


Refer to the Packaging And Deploying Extensions guide for instructions on packaging and deploying your extension.

Alternatively, you can download the SDK from sourceforge or get the latest code from SVN where you'll find a prepared  TaggingSample sample.