Creating components

The Process development kit lets improving EasySite by giving you the possibility to develop your own components.

The components are unit elements that can be added to a page,a block,a page template or a block template. They correspond to the smaller element handled in EasySite.

A component is at least composed of this group of elements:

  • Definition: component XML description;
  • Translation file: translation XML file of the character strings;
  • Controller: events render management;
  • Extension of properties editing: setting management;
  • Render mode: the supported display types are the Process screens and the JSP pages.

Every file assigned to a component should be placed under the WEB-INF/storage/custom/components/project/package root. The JSP files should be placed in a sub-level « views ».

Component XML definition

The components’ definition file must be named components.xml. This file enables in fact to define several components. Every component defined in the XML file will be put together inside a same package and will be displayed as the same menu option in the WYSIWYG design tool.

In this XML file, each component is represented by a tag element. Under the tag element is the component definition.

  • <controller>: Java Class branched off the BaseComponentController enabling to position the values of the bookmarks accessible for the JSP renders.
  • <extension>: Java Class branched off the BaseEditorExtension enabling to handle the group of properties present in the tag section.
  • <depends>: enables to specify the dependencies to JavaScript or CSS files.
  • <navigation>: the « navigation » tag enables to associate a Process screen to the developed component. Use the “screen” attribute with, as value the concatenation of the screen and the action name separated by a comma.
  • <view>: enables to define a JSP page that will display the graphical render of the component.
  • <alternateView>: enables to define the intermediate render when the page is displayed in “design” mode. You may declare either a render JSP page, either a sequence of field names surrounded by the $ character.
  • <configuration>: holds two sections: properties and advancedProperties enabling to configure the developed component. Each section has field tags whose description is very similar to the one you can find in the Process screens. The preview attribute enables to indicate that the field value will be displayed in “tool tip” on the intermediate render of the component.

Example of an XML File

This example shows how to define a component inside a package. Please note the tags project, package, component will be replaced respectively by the project system name, the package system name and the component system name. These names correspond to the folders created under the /custom/components root too.

<?xml version="1.0" encoding="UTF-8"?>
<package name="<project>.<package>" provider="education.com" version="1.0">
    <runtime/>
    <depends/>
    <components>
        <element name="<project>.<package>.dummy">
            <def>
                <controller className="com.vdocsoftware.<project>.components.<package>.dummy.SimpleController"/>
                <extension type="editor" className="com.vdocsoftware.<project>.components.<package>.dummy.SimpleEditorExtension"/>
                <navigation screen="dummy.edit"/>
                <alternateView>$fldTextBox$</alternateView>
                <depends>
                    <ref type="javascript" value="/resources/external/js/beautiful.js"/>
                    <ref type="stylesheet" value="/resources/external/css/lovely.css"/>
                </depends>
                <configuration>
                    <section name="properties">
                        <fields>
                            <field name="fldTextBox" ctrl="text" width="long" mandatory="true"/>
                            <field name="fldTextArea" ctrl="textarea" width="long" cssclass="textarea" preview="true"/>
                            <field name="fldCheckBox" ctrl="checkbox" boolean-value="true"/>
                        </fields>
                    </section>
                    <section name="advancedProperties">
                        <fields/>
                    </section>
                </configuration>
            </def>
        </element>
    </components>
</package>

Translation file

The translation XML file concerning the developed components must be named strings.xml and placed under the root of the package (/custom/components/project/package).

This file must contain all the strings useful for the components defined in the definition XML file (components.xml).

Example of the translation XML file

In this example, the system name used for the “value” attribute is important. It is composed of the following elements separated by dots :

  • the compulsory system prefix “ezs.component”;
  • the project name;
  • the package name;
  • the component name.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<res>
    <id value="ezs.component.<project>.<package>.label">
        <lang value="fr">Mon composant</lang>
        <lang value="en">My component</lang>
    </id>
    <id value="ezs.component.<project>.<package>.description">
        <lang value="fr">Description de mon composant</lang>
        <lang value="en">My component description</lang>
    </id>
    <id value="ezs.component.<project>.<package>.<component>.label">
        <lang value="fr">Mon élément</lang>
        <lang value="en">My element</lang>
    </id>
    <id value="ezs.component.<project>.<package>.<component>.description">
        <lang value="fr">Description de mon élément</lang>
        <lang value="en">My element description</lang>
    </id>
</res>

In the case of using section fields, the strings should follow the following rule:

<id value="ezs.component.<project>.<package>.<component>.<field>.label">
	<lang value="fr">Mon champ</lang>
	<lang value="en">My field</lang>
</id>
<id value="ezs.component.<project>.<package>.<component>.<field>.description">
	<lang value="fr">Description de mon champ</lang>
	<lang value="en">My field description</lang>
</id>

Component controller

Each component may be associated to a controller which aims to receipt and process the events and to position the bookmarks values.

To implement a component controller, you just have to create a Java class which extends the class named BaseComponentController. This class must be defined in the controller tag of the components’ definition XML file (components.xml).

The full name of the basic class is: com.axemble.vdoc.sdk.impl.base.BaseComponentController.

Method of the basis class BaseComponentController

This basic class gives access to the site module that itself enables to handle the whole site API and the execution context.

public abstract class BaseComponentController implements IComponentController {
	final protected ISiteModule getSiteModule();
	final public IComponent getComponent();
	final public Map getComponentContext();

	protected abstract void prepareModel( IRenderModel model ) throws Exception;
	protected abstract void processEvent( String eventName, String eventValue ) throws Exception;
}

Example of component controller implementation

The following example shows how to position and to recover values from the current component context and how to manipulate the render template.

public class SimpleController extends BaseComponentController {

	protected void processEvent( String eventName, String eventValue ) throws Exception {
		// check the incoming event
		if ( eventName.equals( "refresh" ) && eventValue.equals( "true" ) ) {
			// store an information into the component context
			this.getComponentContext().put( "forceRefresh", "true" );
		}
	}
	
	protected void prepareModel( IRenderModel model ) throws Exception {
		// retrieve the information from the component context
		if ( this.getComponentContext().get( "forceRefresh" ).equals( "true" ) ) {
			// set a value into the render model
			model.setValue( "executeRefresh", Boolean.TRUE );
		} else {
			model.setValue( "executeRefresh", Boolean.FALSE );
		}
	}
}

Properties edition extension

An extension class of component properties enables to process the dynamic aspect display of the properties present in the component definition XML file.

To implement a component properties’ extension class, you just have to branch off the BaseEditorExtension class. This class must be defined in the component definition XML file (components.xml).

The full name of the class is: com.axemble.vdoc.sdk.document.extensions.BaseEditorExtension.

Method of the BaseEditorExtension base class

This base class recovers the documentary base classes: BaseDocumentExtension and BaseResourceExtension. It gives access to the site and workflow modules, provides methods to access the information assigned to the current page. And it enables to manipulate the document assigned to the properties and to the graphical component representing the properties edition form (CtlAbstractForm).

public abstract class BaseEditorExtension implements IEditorExtension {
	// initialization
	public void init()
	
	// events
	public boolean onBeforeLoad()
	public boolean onAfterLoad()
	public boolean onBeforeSave()
	public boolean onAfterSave()
	public boolean onBeforeRemove()
	public boolean onAfterRemove()
	
	// validate event
	public boolean validate()
	
	// document access
	final public AbstractDocument getDocument()
	final public boolean isCreation()
	
	// graphical elements access
	final public CtlAbstractForm getForm()
	final public IResourceController getResourceController()
	
	// site elements
	final public IContentContainer getContentContainer()
	final public IContent getContent()
	final public IContentComponent getContentComponent()
	final public IBlock getRootBlock()
	final public IBlock getParentBlock()
	final public String getComponentName()
	
	// modules
	final public IBaseWorkflowModule getWorkflowModule()
	final public IBaseSiteModule getSiteModule()
}

Render mode

The Process development kit offers two render modes of EasySite components:

  • in the form of Process screens: define a Process screen as associated to the component;
  • using JSP pages: define a group of JSP pages that must be present in the « views » component folder;

However we recommend the developments based on the Process screens.

“Process Screens” mode

The Process screen mode is activated if you use the “navigation” tag in the component definition XML description. Then you just have to fill-in the “screen” attributes with the concatenation of the name and the action screen separated by a dot.

<navigation screen="dummy.edit" />

“JSP Page” mode

The JSP Page mode is activated if you use the “view” tag in the component definition XML description. The tag view enables to define a JSP page that will make the graphical render.

<view>default.jsp</view>

Example

This example displays the using of new tags available in the Process development kit:

  1. recipientMessage: enables to send message to a recipient;
  2. event: enables to trigger an event;
  3. resource: enables to translate a string identifier.
<%@ taglib uri='http://www.vdocsoftware.com/enhancement' prefix='sdk' %>

<button type="button" name="sendAMessage" onclick="<sdk:recipientMessage recipient="basket" eventType="2" eventBody="-1" class="button2">
	<span>
		<sdk:resource id="send.a.message" />
	</span>
</button>

<button type="button" name="fireAnEvent" onclick="<sdk:event name="basket" value="2" />" class="button2">
	<span>
		<sdk:resource id="fire.an.event" />
	</span>
</button>

Notion d’héritage

Dans la conception de composants dédiés aux sites WEB Easysite, il est possible de construire une notion d’héritage.

Soit 20 composants disposant chacun du besoin de renseigner les mêmes champs dans leur configuration.

Au lieu de réaliser un copier-coller, il est possible de définir ces champs dans un composant “père” dont les 20 composants vont hériter.

Exemple

Soit un groupe de composants dans lesquels il faut saisir les champs de configuration suivants :

  • Champ1
  • Champ2
  • Champ3
  • Champ4

De plus, tous les composants ont une dépendance vers les mêmes CSS et JS externes.

Enfin, une classe d’extension d’éditeur se chargera de gérer les champs (alimentation des listes, valeurs par défaut, évènement onChange, …).

Conception d’un composant abstrait

La logique d’un composant “abstrait” reprend la même notion d’abstraction que la notion “objets”.

Un composant “abstrait” ne sera pas directement disponible sur le site WEB; cependant, d’autres composants pourront en hériter et sont disponibles sur le site WEB.

Voici à quoi pourrait ressembler la définition de du composant abstrait (abstract="true") :

<element name="dev.floor.MyAbstractComponent">
    <def abstract="true">
        <controller className=""/>
        <extension type="editor" className="com.vdoc.dev.floor.MyAbstractComponentEditorExtension" />
        <navigation screen=""/>
        <alternateView/>
        <depends>
          <ref type="javascript" value="/resources/MyAbstractComponent/MyAbstractComponent.js" />
          <ref type="stylesheet" value="/resources/MyAbstractComponent/MyAbstractComponent.css" />
        </depends>
        <configuration>
          <section name="properties">
            <fields>
              <field name="Champ1" ctrl="text" mandatory="true" />
              <field name="Champ2" ctrl="text" mandatory="true" />
	      <field name="Champ3" ctrl="text" mandatory="true" />
	      <field name="Champ4" ctrl="text" mandatory="true" />
            </fields>
          </section>
          <section name="advancedProperties">
            <fields>
	    </fields>
	  </section>
        </configuration>
    </def>
</element>

Création d’un composant fils avec ajout de nouvelles configurations

Ce composant hérite du composant abstrait, il doit donc proposer les champs “Champ1, Champ2, Champ3, Champ4”.

Deux nouveaux champs “Champ5, Champ6” sont ajoutés et sont spécifiques à ce composant.

On utilise la syntaxe : extends="dev.floor.MyAbstractComponent"

<element name="dev.floor.Component1">
    <def extends="dev.floor.MyAbstractComponent">
	<configuration>
          <section name="properties">
            <fields>
              <field name="Champ5" ctrl="text" mandatory="true" />
            </fields>
          </section>
          <section name="advancedProperties">
            <fields>
	      <field name="Champ6" ctrl="text" mandatory="true" />
	    </fields>
	  </section>
	</configuration>
    </def>
</element>

La surcharge peut se faire en déclarant de nouveaux composants. Tout ce qui sera défini ou redéfini dans les composants fils restera, le reste prendra sa source dans le composant abstrait.

Il s’agit ici d’exmples avec les “fields”, mais on pourrait fait la même chose pour déclarer un “Controller” différent ou encore une “navigation” ou une “JSP” différente pour le rendu.

Création d’un composant fils simple avec suppression de configurations héritées

Dans ce deuxième composant, le composant hérité doit être présent pas le champ “Champ4”; il faut donc retirer ce noeud de l’héritage avec l’instruction override="delete".

<element name="dev.floor.Component2">
    <def extends="dev.floor.MyAbstractComponent">
	<configuration>
          <section name="properties">
            <fields>
              <field name="Champ4" override="delete" />
            </fields>
          </section>
          <section name="advancedProperties">
            <fields>
	    </fields>
	  </section>
	</configuration>
    </def>
</element>

Source : https://wiki.myvdoc.net/xwiki/bin/view/Dev+Floor/HowToBuildExtendedSiteComponents