4.1. Content form

eXo Platform comes with a bunch of content forms (Web Content, Illustrated Web Content, File and more). For some reasons, you may want to create your own content form. To do that, follow either of the following ways:

This tutorial instructs you to create your own content form named "Article" by using a custom extension. This custom extension requires a jar and a war, so make sure you are aware of creating and deploying these files into eXo Platform.

Below are steps for the war. In this context, the webapp name is custom-form that needs to be configured properly in the jar.

Step 1. Creating a new content type named "exo:article"

  1. Edit custom-form.war!/WEB-INF/conf/mycustom-conf/nodetypes/nodetype-configuration.xml. This file contains the full definition of the content type, for example:

    
    <nodeTypes xmlns:nt="http://www.jcp.org/jcr/nt/1.0" xmlns:mix="http://www.jcp.org/jcr/mix/1.0"
      xmlns:jcr="http://www.jcp.org/jcr/1.0">
      <nodeType name="exo:article" isMixin="false" hasOrderableChildNodes="false" primaryItemName="">
        <supertypes>
            <supertype>nt:base</supertype>
            <supertype>mix:referenceable</supertype>
            <supertype>exo:rss-enable</supertype>
        </supertypes>
        <propertyDefinitions>
            <propertyDefinition name="exo:text" requiredType="String" autoCreated="false" mandatory="false"
                                onParentVersion="COPY"
                                protected="false" multiple="false">
                <valueConstraints/>
            </propertyDefinition>
        </propertyDefinitions>
        <childNodeDefinitions>
            <childNodeDefinition name="*" defaultPrimaryType="nt:file" autoCreated="false" mandatory="false"
                                 onParentVersion="COPY" protected="false" sameNameSiblings="true">
                <requiredPrimaryTypes>
                    <requiredPrimaryType>nt:file</requiredPrimaryType>
                </requiredPrimaryTypes>
            </childNodeDefinition>
        </childNodeDefinitions>
      </nodeType>
    </nodeTypes>

    By defining a supertype, you can reuse other content types and extend them with more properties (just like inheritance in Object Oriented Programming).

  2. Register the content type into custom-form.war!/WEB-INF/conf/mycustom-conf/jcr/jcr-configuration.xml.

    
    <?xml version="1.0" encoding="ISO-8859-1"?>
    <configuration
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.exoplatform.org/xml/ns/kernel_1_2.xsd http://www.exoplatform.org/xml/ns/kernel_1_2.xsd"
       xmlns="http://www.exoplatform.org/xml/ns/kernel_1_2.xsd">

      <external-component-plugins>
          <target-component>org.exoplatform.services.jcr.RepositoryService</target-component>
          <component-plugin>
            <name>add.nodeType</name>
            <set-method>addPlugin</set-method>
            <type>org.exoplatform.services.jcr.impl.AddNodeTypePlugin</type>
            <init-params>
              <values-param>
                <name>autoCreatedInNewRepository</name>
                <description>Node types configuration file</description>
                <value>war:/conf/mycustom-conf/nodetypes/nodetype-configuration.xml</value>
              </values-param>
            </init-params>
          </component-plugin>
        </external-component-plugins>
        
    </configuration>
  3. Import jcr-configuration.xml inside custom-form.war!/WEB-INF/conf/configuration.xml.

    
    <?xml version="1.0" encoding="ISO-8859-1"?>
    <configuration
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.exoplatform.org/xml/ns/kernel_1_2.xsd http://www.exoplatform.org/xml/ns/kernel_1_2.xsd"
       xmlns="http://www.exoplatform.org/xml/ns/kernel_1_2.xsd">
       
        <import>war:/conf/mycustom-conf/jcr/jcr-configuration.xml</import>
    </configuration>

To view this content type through UI, you also need to create templates linked to it, as described in Step 2. Creating a content template for the content type.

Step 2. Creating a content template for the content type

There are three of templates applied to a content type:

This tutorial only instructs how to create Dialog and View templates that are mandatory. If you want to add CSS for your content type, create Stylesheet.css under custom-form.war!/WEB-INF/conf/mycustom-conf/nodetypes/artifacts/article/css. You can use CSS templates to embed into the View template. See the CSS section for how to create a CSS template.

  1. Edit the Dialog template for the exo:article content type under custom-form.war!/WEB-INF/conf/mycustom-conf/nodetypes/artifacts/article/dialogs/dialog1.gtmpl. This step is mandatory.

    
    <div class="UIForm FormLayout FormScrollLayout">
    <%
    uiform.begin()
    %>
    <%/* start render action*/%>
    <if (uiform.isShowActionsOnTop()) {
        uiform.processRenderAction()
    }
    %>
    <%/* end render action*/%>
    <div class="HorizontalLayout">
        <table class="UIFormGrid">
            <tr>
                <td class="FieldLabel">
                    <label for="title">Title</label>
                </td>
                <td class="FieldComponent">
                    <%
                    String[] fieldTitle = ["jcrPath=/node/exo:title""options=noSanitization""validate=empty"] ;
                    uicomponent.addTextField("title"fieldTitle) ;
                    %>
                </td>
            </tr>
            <tr>
                <td class="FieldLabel">
                    <label for="name">Name</label>
                </td>
                <td class="FieldComponent">
                    <%
                    String[] fieldName = ["jcrPath=/node""options=noSanitization",
                    "mixintype=mix:votable,mix:commentable,mix:i18n,mix:versionable""editable=if-null",
                    "validate=empty,name"] ;
                    uicomponent.addTextField("name"fieldName) ;
                    %>
                    <script type="text/javascript">
                        titleField = document.getElementById("title");
                        titleField.onchange = function() { eXo.ecm.SELocalization.cleanName(this.value, "name"); } ;
                    </script>
                </td>
            </tr>
            <tr>
                <td class="FieldLabel">
                    <label for="content-lang">Language</label>
                </td>
                <td class="FieldComponent">
                    <%
                    String lang = org.exoplatform.portal.webui.util.Util.getPortalRequestContext().getLocale().toString();
                    String[] fieldLang = ["jcrPath=/node/exo:language",
                    "script=ecm-explorer/widget/FillSelectBoxWithLanguage.groovy"lang] ;
                    uicomponent.addSelectBoxField("content-lang"fieldLang) ;
                    %>
                </td>
            </tr>
            <tr>
                <td class="FieldLabel">
                    <label for="summary">Summary</label>
                </td>
                <td class="FieldComponent">
                    <div class="UIFCKEditor">
                        <%
                        String[] fieldSummary = ["jcrPath=/node/exo:summary""options=Basic"""] ;
                        uicomponent.addRichtextField("summary"fieldSummary) ;
                        %>
                    </div>
                </td>
            </tr>
            <tr>
                <td class="FieldLabel">
                    <label for="content">Content</label>
                </td>
                <td class="FieldComponent">
                    <div class="UIFCKEditor">
                        <%
                        String[] fieldContent = ["jcrPath=/node/exo:text",
                        "options=toolbar:CompleteWCM,'height:410px',noSanitization"""] ;
                        uicomponent.addRichtextField("content"fieldContent) ;
                        %>
                    </div>
                </td>
            </tr>
        </table>

    </div>

    <if (!uiform.isShowActionsOnTop()) {
    uiform.processRenderAction()
    }
    %>
    <%uiform.end()%>
    </div>

    To create a Dialog template, you first need to understand the dialog syntaxes. See here for its basic syntaxes.

  2. Edit the View template for the exo:article content type under custom-form.war!/WEB-INF/conf/mycustom-conf/nodetypes/artifacts/article/views/view1.gtmpl. This step is mandatory.

    
    <%
      import org.exoplatform.ecm.webui.utils.Utils ;
    %>
    <style>
      <_ctx.include(uicomponent.getTemplateSkin("exo:article""Stylesheet")); %>
    </style>
    <div id="$uicomponent.id">
        <%
         def node = uicomponent.getNode() ;     
         %>
         <p>Title: <%=Utils.getTitle(node)%></p>
         <p>Summary: <%=node.getProperty("exo:summary").getString()%></p>
         <p>Content: <%=node.getProperty("exo:text").getString()%></p>
        <
        try{
           _ctx.include(uicomponent.getViewTemplate("mix:votable""view1"));
           }catch (Exception e) {}
           
        try
          _ctx.include(uicomponent.getViewTemplate("exo:comments""view1"));
        } catch (Exception e) {}
        %>
      
    </div>

    See the View section for details. Also, you can see the full configuration of the view1.gtmpl here.

  3. Register the created templates (and CSS if any) with TemplateService under custom-form.war!/WEB-INF/conf/mycustom-conf/nodetypes/nodetype-templates-configuration.xml, then declare template files into the system via the template plugin.

    
    <?xml version="1.0" encoding="ISO-8859-1"?>

    <configuration
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.exoplatform.org/xml/ns/kernel_1_2.xsd http://www.exoplatform.org/xml/ns/kernel_1_2.xsd"
       xmlns="http://www.exoplatform.org/xml/ns/kernel_1_2.xsd">

      <external-component-plugins>
        <target-component>org.exoplatform.services.cms.templates.TemplateService</target-component>
        <component-plugin>
          <name>addTemplates</name>
          <set-method>addTemplates</set-method>
          <type>org.exoplatform.services.cms.templates.impl.TemplatePlugin</type>
          <init-params>
            <value-param>
              <name>autoCreateInNewRepository</name>
              <value>true</value>
            </value-param>
            <value-param>
              <name>storedLocation</name>
              <value>war:/conf/mycustom-conf/nodetypes/artifacts</value>
            </value-param>
            <object-param>
              <name>template.configuration</name>
              <description>configuration for the localtion of nodetypes templates to inject in jcr</description>
              <object type="org.exoplatform.services.cms.templates.impl.TemplateConfig">
                <field name="nodeTypes">
                  <collection type="java.util.ArrayList">
                    <value>
                      <object type="org.exoplatform.services.cms.templates.impl.TemplateConfig$NodeType">
                        <field name="nodetypeName">
                          <string>exo:article</string>
                        </field>
                        <field name="documentTemplate">
                          <boolean>true</boolean>
                        </field>
                        <field name="label">
                          <string>Article</string>
                        </field>
                        <field name="referencedView">
                          <collection type="java.util.ArrayList">
                            <value>
                              <object type="org.exoplatform.services.cms.templates.impl.TemplateConfig$Template">
                                <field name="templateFile">
                                  <string>/article/views/view1.gtmpl</string>
                                </field>
                                <field name="roles">
                                  <string>*</string>
                                </field>
                              </object>
                            </value>
                          </collection>
                        </field>
                        <field name="referencedDialog">
                          <collection type="java.util.ArrayList">
                            <value>
                              <object type="org.exoplatform.services.cms.templates.impl.TemplateConfig$Template">
                                <field name="templateFile">
                                  <string>/article/dialogs/dialog1.gtmpl</string>
                                </field>
                                <field name="roles">
                                  <string>*:/platform/web-contributors</string>
                                </field>
                              </object>
                            </value>
                          </collection>
                        </field>
                      </object>
                    </value>
                  </collection>
                </field>
              </object>
            </object-param>
          </init-params>
        </component-plugin>
      </external-component-plugins>

    </configuration>

    Note

    To further understand the template plugin, you can refer to the Template section.

  4. Import nodetype-templates-configuration.xml inside custom-extension.war!/WEB-INF/conf/configuration.xml. This file now looks like:

    
    <?xml version="1.0" encoding="ISO-8859-1"?>
    <configuration
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.exoplatform.org/xml/ns/kernel_1_2.xsd http://www.exoplatform.org/xml/ns/kernel_1_2.xsd"
       xmlns="http://www.exoplatform.org/xml/ns/kernel_1_2.xsd">
       
        <import>war:/conf/mycustom-conf/jcr/jcr-configuration.xml</import>
        <import>war:/conf/mycustom-conf/nodetypes/nodetype-templates-configuration.xml</import>
    </configuration>

After following the above steps, you also need to edit custom-form.war!/WEB-INF/web.xml.


<?xml version="1.0" encoding="UTF-8"?>

<web-app version="3.0" metadata-complete="true"
    xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
  
   <display-name>custom-form</display-name>
   
  <!-- ================================================================== -->
  <!--           LISTENER                                                 -->
  <!-- ================================================================== -->
  <listener>
    <listener-class>org.exoplatform.container.web.PortalContainerConfigOwner</listener-class>
  </listener>

</web-app>

Testing the content form "Article"

Now, deploy your custom extension into eXo Platform by putting custom-form.war in the webapps folder and custom-form-config.jar in the lib folder of eXo Platform. See here for more details. Restart the server, and go to AdministrationContentSites Explorer. Here, click New Content. You will see your newly content form "Article" in the list of content forms.

Basic syntaxes of Dialog templates

See the following basic syntaxes which are often used for creating a Dialog template.

To further understand how to use the Dialog syntax, see the Dialogs section. Now, you can easily create a Dialog template.

Note

By default, JavaScript is disabled for any fields of some content templates to prevent the XSS attacks in eXo Platform. You can specify whether JavaScript is allowed to run on a field of the content template or not by using the "option" parameter as the example below:

String [] htmlArguments = ["jcrPath = / node / default.html / JCR: content / JCR: data",
                "options = toolbar: CompleteWCM, height: '410px ', noSanitization" htmlContent];
            

Interceptors

By adding interceptors to your template, you will be able to execute a Groovy script just before or just after saving the node. Pre-save interceptors are mostly used to validate input values and their overall meaning while the post-save interceptor can be used to do some manipulations or references for the newly created node, such as binding it to a forum discussion or Wiki space.

To add an interceptor, insert the following fragment anywhere in your template:

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

The first argument is the path of the interceptor class that you have created. All the interceptors are created in ecm-explorer/interceptor/. The second argument can have the prev value which executes the interceptor before saving the content or the post value which executes the interceptor after having saved the content.

There are two ways to declare an interceptor Groovy script:

The interceptor Groovy scripts must implement the CmsScript interface. Pre-save interceptors obtain input values within the context:

public class PreNodeSaveInterceptor implements CmsScript {


  public PreNodeSaveInterceptor() {
  }
  public void execute(Object context) {
    Map inputValues = (Map) context;
    Set keys = inputValues.keySet();
    for(String key : keys) {
      JcrInputProperty prop = (JcrInputProperty) inputValues.get(key);
      println("   --> "+prop.getJcrPath());
    }
  }
  public void setParams(String[] params) {
  }
}

Whereas the post-save interceptor is passed the path of the saved node in the context:

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


public class PostNodeSaveInterceptor implements CmsScript {
  public PostNodeSaveInterceptor() {
  }
  public void execute(Object context) {
    String path = (String) context;
    println("Post node save interceptor, created node: "+path);
  }
  public void setParams(String[] params) {
  }
}

See also

Copyright ©. All rights reserved. eXo Platform SAS
blog comments powered byDisqus