eXo Platform 3.0

- Prev
- Next

## Chapter 4. Inside WCM Templates

## Content types

Overview

The templates are applied to a NodeType or a metadata MixinType. Two kinds of templates exist :

- dialogs : are html forms that allow to create node instances.

- views : are html fragments used to display nodes.

From the ECM admin portlet, Manage Template lists existing NodeTypes that have been associated to Dialog and/or View templates. These templates can be attached to permissions (in the usual membership:group_ form), so that a specific one is displayed according to the rights of the user (very useful in a content validation workflow activity).

DocumentType

1. checkbox allows to say if the NodeType should be considered as a DocumentType. File Explorer considers such nodes as user content and applies the following behavior :

- View template will be used to display the DocumentType nodes

- DocumentTypes nodes can created by the 'Add Document' action

- non DocumentType are hidden (unless 'Show non document types' option is checked)

Templates are written using Groovy Templates and will require some experience with JCR API and HTML notions.

### Dialog

Dialogs are groovy templates that generate forms by mixing static HTML fragments and groovy calls to the components responsible for building the UI at runtime. The result is a simple but powerful syntax.

#### Common parameters

These following parameters are common and can be used for every input fields.

Parameter | Type | Required | Description | Example
--- | --- | --- | --- | ---
jcrPath | `String` |  | relative path inside the current node | `jcrPath=/node/exo:title`
mixintype | `String` with comma `,` character |  | List of the mixin types you want to initialize when creating the content | `mixintype=mix:i18n` `mixintype=mix:votable,mix:commentable,mix:i18n`
validate | `String` with comma `,` character |  | List of the validators you want to apply to the input. Possible values are : `name`, `email`, `number`, `empty`, `null`, `datetime`, `length` OR validator classes | `validate=empty` `validate=empty,name` `validate=org.exoplatform.webui.form.validator.StringLengthValidator`
editable | `String` |  | The input will be editable only if the value of this parameter is `if-null` and the value of this input is null or blank | `editable=if-null`
multiValues | `Boolean` |  | Show a multi values component if true. Must be used only with corresponding multi-values properties. The default value of this parameter is `false` | `multiValues=true`
visible | `Boolean` |  | The input is visible if this value is `true` | `visible=true`

See also:

- Text field

- Hidden field

- Text area field

- Rich text field

- Calendar field

- Upload field

- Radio field

- Select box field

- Checkbox field

- Mixin field

- Action field

### Warning

Note that `mixintype` can be used only in the root node field (commonly known as the name field)

#### Text Field

##### Addition parameters

None

See also: Common parameters

##### Example

    <%
      String[] fieldTitle = ["jcrPath=/node/exo:title", "validate=empty"] ;
      uicomponent.addTextField("title", fieldTitle) ;
    %>

#### Hidden Field

##### Addition parameters

None

See also: Common parameters

##### Example

#### Text Area Field

##### Addition parameters

Parameter | Type | Required | Description | Example
--- | --- | --- | --- | ---
rows | `Number` |  | The initial textarea's number of rows. The value is `10` by default | `rows=20`
cols | `Number` |  | The initial textarea's number of cols. The value is `30` by default | `cols=50`

See also: Common parameters

##### Example

    <%
    	String[] fieldDescription = ["jcrPath=/node/exo:description", "validate=empty"] ;
    	uicomponent.addTextAreaField("description", fieldDescription)
    %>

#### Rich Text Field

##### Addition parameters

Parameter | Type | Required | Description | Example
--- | --- | --- | --- | ---
options | `String` with semicolon `;` character |  | Some options for CKEditor field: toolbar, width and height | `options=CompleteWCM;width:'100%';height:'200px';`

Parameter | Type | Required | Description | Example
--- | --- | --- | --- | ---
toolbar | `String` |  | The pre-define toolbar for CKEditor. The value can be: `Default`, `Basic`, `CompleteWCM`, `BasicWCM`, `SuperBasicWCM` | `options=CompleteWCM`
width | `String` |  | The width of CKEditor. The value can be the percent of pixel | `options=width:'100%'`
height | `String` |  | The height of CKEditor. The value can be the percent of pixel | `options=height:'200px'`

See also: Common parameters

##### Example

    <%
    	String[] fieldSummary = ["jcrPath=/node/exo:summary", "options=toolbar:CompleteWCM,width:'100%',height:'200px'", "validate=empty"] ;
    	uicomponent.addRichtextField("summary", fieldSummary) ;
    %>

#### Calendar Field

##### Addition parameters

Parameter | Type | Required | Description | Example
--- | --- | --- | --- | ---
options | `String` |  | An option for calendar field: Display time | `options=displaytime`

See also: Common parameters

##### Example

    <%
    	String[] fieldPublishedDate = ["jcrPath=/node/exo:publishedDate", "options=displaytime", "validate=datetime", "visible=true"] ;
    	uicomponent.addCalendarField("publishedDate", fieldPublishedDate) ;
    %>

#### Upload Field

##### Addition parameters

None

See also: Common parameters

##### Example

There are 2 main cases when create an upload form: You want to store the image as a property OR as a node.

- If you want to use property so you can do as follow:

    <%
    	String[] fieldMedia = ["jcrPath=/node/exo:image"] ;
    	uicomponent.addUploadField("media", fieldMedia) ;
    %>

- If you want to use node so you can do as follow:

    <%
    	String[] hiddenField1 = ["jcrPath=/node/exo:image", "nodetype=nt:resource", "visible=false"] ;
    	String[] hiddenField2 = ["jcrPath=/node/exo:image/jcr:encoding", "visible=false", "UTF-8"] ;
    	String[] hiddenField3 = ["jcrPath=/node/exo:image/jcr:lastModified", "visible=false"] ;
    	uicomponent.addHiddenField("hiddenInput1", hiddenField1) ;
    	uicomponent.addHiddenField("hiddenInput2", hiddenField2) ;
    	uicomponent.addHiddenField("hiddenInput3", hiddenField3) ;

    	String[] fieldMedia = ["jcrPath=/node/exo:image"] ;
    	uicomponent.addUploadField("media", fieldMedia) ;
    %>

- But, this code is not complete. If you want to display the upload field, the image must be blank, otherwise you can display the image and an action enables you to remove it. You can do as follows:

    <%
    	def image = "image";
    	// If you're trying to edit the document
    	if(uicomponent.isEditing()) {
    		def curNode = uicomponent.getNode();
    		// If the image existed
    		if (curNode.hasNode("exo:image")) {
    			def imageNode = curNode.getNode("exo:image") ;
    			// If the image existed and available
    			if (imageNode.getProperty("jcr:data").getStream().available() > 0 && (uicomponent.findComponentById(image) == null)) {
    				def imgSrc = uicomponent.getImage(curNode, "exo:image");
    				def actionLink = uicomponent.event("RemoveData", "/exo:image");
    				%>
    					<div>
    						<img src="$imgSrc" width="100px" height="80px"/>
    						<a href="$actionLink">
    							<img src="/eXoResources/skin/DefaultSkin/background/Blank.gif" alt="" class="ActionIcon Remove16x16Icon"/>
    						</a>
    					</div>
    				<%
    			} else {
    				String[] fieldImage = ["jcrPath=/node/exo:image/jcr:data"] ;
    				uicomponent.addUploadField(image, fieldImage) ;
    			}
    		} else {
    				String[] fieldImage = ["jcrPath=/node/exo:image/jcr:data"] ;
    				uicomponent.addUploadField(image, fieldImage) ;
    		}
    	}  else if(uicomponent.dataRemoved()) {
    		String[] fieldImage = ["jcrPath=/node/exo:image/jcr:data"] ;
    		uicomponent.addUploadField(image, fieldImage) ;
    	} else {
    		String[] fieldImage = ["jcrPath=/node/exo:image/jcr:data"] ;
    		uicomponent.addUploadField(image, fieldImage) ;
    	}
    %>

#### Radio Field

##### Addition parameters

Parameter | Type | Required | Description | Example
--- | --- | --- | --- | ---
options | `String` with comma `,` characters |  | Some radio values | `options=radio1,radio2,radio3`

See also: Common parameters

##### Example

    <%
    	String[] fieldDeep = ["jcrPath=/node/exo:isDeep", "defaultValues=true", "options=radio1,radio2,radio3"];
    	uicomponent.addRadioBoxField("isDeep", fieldDeep);
    %>

#### SelectBox Field

Parameter | Type | Required | Description | Example
--- | --- | --- | --- | ---
options | `String` with comma `,` characters |  | Some option values | `options=option1,option2,option3`

See also: Common parameters

##### Example

    <%
    	String[] fieldDeep = ["jcrPath=/node/exo:isDeep", "defaultValues=true", "options=checkbox1,checkbox2,checkbox3"];
    	uicomponent.addCheckBoxField("isDeep", fieldDeep);
    %>

#### CheckBox Field

##### Addition parameters

Parameter | Type | Required | Description | Example
--- | --- | --- | --- | ---
options | `String` with comma `,` characters |  | Some checkbox values | `options=checkbox1,checkbox2,checkbox3`

See also: Common parameters

##### Example

    <%
    	String[] fieldDeep = ["jcrPath=/node/exo:isDeep", "defaultValues=true", "options=checkbox1,checkbox2,checkbox3"];
    	uicomponent.addCheckBoxField("isDeep", fieldDeep);
    %>

#### Mixin Field

##### Addition parameters

None

See also: Common parameters

##### Example

    <%
    	String[] fieldId = ["jcrPath=/node", "editable=false", "visible=if-not-null"] ;
    	uicomponent.addMixinField("id", fieldId) ;
    %>

#### Action Field

##### Addition parameters

Parameter | Type | Required | Description | Example
--- | --- | --- | --- | ---
selectorClass | `String` |  | The component to display | `selectorClass=org.exoplatform.ecm.webui.tree.selectone.UIOneNodePathSelector`
selectorIcon | `String` |  | The action icon | `selectorIcon=SelectPath24x24Icon`

Depends on the `selectorClass`, some other parameters can be added For example The component `org.exoplatform.ecm.webui.tree.selectone.UIOneNodePathSelector` need these parameters

Parameter | Type | Required | Description | Example
--- | --- | --- | --- | ---
workspaceField | `String` |  | The field which allow to select a workspace | `workspaceField=targetWorkspace`

The component `org.exoplatform.ecm.webui.selector.UIPermissionSelector` does not need any special parameters.

See also: Common parameters

##### Example

    <%
    	String[] fieldPath = ["jcrPath=/node/exo:targetPath", "selectorClass=org.exoplatform.ecm.webui.tree.selectone.UIOneNodePathSelector", "workspaceField=targetWorkspace", "selectorIcon=SelectPath24x24Icon"] ;
    	uicomponent.addActionField("targetPath", fieldPath)  ;
    %>

#### Interceptors

To add an intercepter into a dialog, we can use this method `uicomponent.addInterceptor(String scriptPath, String type)`

|  | Parameters
--- | --- | ---
scriptPath | `String` | The relative path to the script file
type | `String` | The type of intercepter: `prev` or `post`

##### Example

    <%
    	uicomponent.addInterceptor("ecm-explorer/interceptor/PreNodeSaveInterceptor.groovy", "prev");
    %>

#### How to add new ECM template with tabs.

To avoid refreshing the first tab for every action execution, we add a new private function to the template with tabs. In the template, we must insert new piece of code like the following:

    private String getDisplayTab(String selectedTab) {
    	if ((uicomponent.getSelectedTab() == null && selectedTab.equals("mainWebcontent"))
    			|| selectedTab.equals(uicomponent.getSelectedTab())) {
    		return "display:block";
    	}
    	return "display:none";
    }

    private String getSelectedTab(String selectedTab) {
    	if (getDisplayTab(selectedTab).equals("display:block")) {
    		return "SelectedTab";
    	}
    	return "NormalTab";
    }

Changing in every event of onclick is have to be done like this :

            <div class="UITab NormalTabStyle">
    		<div class="<%=getSelectedTab("mainWebcontent")%>">
    			<div class="LeftTab">
    				<div class="RightTab">
    					<div class="MiddleTab" onClick="<%=uicomponent.event("ChangeTab", "mainWebcontent")%>"><%=_ctx.appRes("WebContent.dialog.label.MainContent")%></div>
    				</div>
    			</div>
    		</div>
    	</div>

    	<div class="UITab NormalTabStyle">
    		<div class="<%=getSelectedTab("illustrationWebcontent")%>">
    			<div class="LeftTab">
    				<div class="RightTab">
    					<div class="MiddleTab" onClick="<%=uicomponent.event("ChangeTab", "illustrationWebcontent")%>"><%=_ctx.appRes("WebContent.dialog.label.Illustration")%></div>
    				</div>
    			</div>
    		</div>
    	</div>

    	<div class="UITab NormalTabStyle">
    		<div class="<%= getSelectedTab("contentCSSWebcontent")%>">
    			<div class="LeftTab">
    				<div class="RightTab">
    					<div class="MiddleTab" onClick="<%=uicomponent.event("ChangeTab", "contentCSSWebcontent")%>"><%=_ctx.appRes("WebContent.dialog.label.Advanced")%></div>
    				</div>
    			</div>
    		</div>
    	</div>

Finally, to display the selected tab, we will add it into the style of UITabContent class.

    <div class="UITabContent" style="<%=getDisplayTab("mainWebcontent")%>">

### View

    <%
    	def node = uicomponent.getNode() ;
    	def originalNode = uicomponent.getOriginalNode()
    %>

    <%=node.getName()%>

    <%if(node.hasProperty("exo:title")) {%>
      <%=node.getProperty("exo:title").getString()%>
    <%}%>

    <%
    	import java.text.SimpleDateFormat ;
    	SimpleDateFormat dateFormat = new SimpleDateFormat() ;
    %>
    ...

    <%if(node.hasProperty("exo:date")) {
      dateFormat.applyPattern("MMMMM dd yyyy") ;
    %>
      <%=dateFormat.format(node.getProperty("exo:date").getDate().getTime())%>
    <%}%>

    <%=_ctx.appRes("Sample.view.label.node-name")%>

## List of Contents

### Folder based Template

### Category tree Template

- Prev
- Up
- Home
- Next