How to prevent additional HTML elements for containers - BloomReach Experience - Open Source CMS

How to prevent additional HTML elements for containers

When you use the channel manager / template composer for your website, by default, the HST injects extra HTML elements that are used to identify to and from which area(s) these HST components can be dropped on and/or modified.

The kind of HTML elements that are added by default depends on the xtype, see Template Composer Configuration. Assuming you have the following hst:containercomponent with one child hst:containercomponentitem :

+ hst:workspace
  + hst:containers
    + homepage
      + main [hst:containercomponent]
        - hst:xtype = HST.vBox
        + list1 [hst:containercomponentitem]
        | - hst:xtype = HST.Item
        + list2 [hst:containercomponentitem]
          - hst:xtype = HST.Item

In the above configuration, the hst:containercomponent main does not define an hst:template, hence the default HST built-in renderer for HST.vBox is used. The defaults for all xtypes are:

xtype default renderer
HST.vBox /org/hippoecm/hst/pagecomposer/builtin/components/vbox.ftl
HST.Table /org/hippoecm/hst/pagecomposer/builtin/components/table.ftl
HST.UnorderedList /org/hippoecm/hst/pagecomposer/builtin/components/ul.ftl
HST.OrderedList /org/hippoecm/hst/pagecomposer/builtin/components/ol.ftl
HST.Span /org/hippoecm/hst/pagecomposer/builtin/components/span.ftl
Using a different renderer than the built-in one for your hst:componentcontainer can be done simply by adding an hst:template, just like you are used to for any other hst:component.

Added HTML elements by the default renderers

Since the template composer identifies container and container-item elements by a predefined CSS classname, the built-in renderers inject these for you by default. For example, the built-in renderer for HST.vBox looks like this (please note this is a simplified version for readability purposes, see vbox.ftl for the exact details)

<#assign hst=JspTaglibs["http://www.hippoecm.org/jsp/hst/core"]>
<@hst.defineObjects/>
<div class="hst-container">
  <#list hstResponse.childContentNames as childContentName>
  <div class="hst-container-item">
    <@hst.include ref="${childContentName}"/>
  </div>
  </#list>
</div>

Thus, a container with xtype=HST.vBox renders a <div class="hst-container"> wrapper element and every child component is wrapped in <div class="hst-container-item"> elements. The resulting HTML is shown below where the ... represents the output of the child components.

<div class="hst-container">
  <div class="hst-container-item">
     ...
  </div>
  <div class="hst-container-item">
     ...
  </div>
</div> 

Gracefully integrate your HTML design with the template composer

Assuming the HTML is designed using Twitter's Bootstrap 2.x fluid grid system, the HTML might looks as follows:

<div class="row-fluid">
  <div class="span4">
    ...  
  </div>
  <div class="span4">
    ...
  </div>
</div> 

Furthermore, let's assume that the div element with span4 must contain the drag-droppable container items (the items themselves do not add the span4, they are contained in it! See below for more on this). This means that the <div class="row-fluid"> must be the container. The HST built-in renderers do not have these classes. Hence, you have to define your own renderer on your hst:containercomponent. The following steps are all there is:

Step 1: Define an hst:template on your hst:containercomponent

+ hst:workspace
| + hst:containers
|  + homepage
|    + main [hst:containercomponent]
|      - hst:xtype = HST.vBox
|      - hst:template = vbox.row.fluid
|      + list1 [hst:containercomponentitem]
|      | - hst:xtype = HST.Item
|      + list2 [hst:containercomponentitem]
|        - hst:xtype = HST.Item
+ hst:templates
  + vbox-row-fluid
    - hst:renderpath = jsp/containers/vbox_row_fluid.jsp

Note that the example here uses a jsp, but using a freemarker template is very similar.

Step 2: Add the container renderer to your project

Depending on the exact html of the designer, vbox_row_fluid.jsp looks something like:

<%@ include file="/WEB-INF/jspf/htmlTags.jspf" %>
<hst:defineObjects/>
<div class="row-fluid hst-container">
  <c:forEach var="childContentName" items="${hstResponseChildContentNames}">
    <div class="span4 hst-container-item">
        <hst:include ref="${childContentName}"/>
    </div>
  </c:forEach>
</div> 

The above results in the following HTML output:

<div class="row-fluid hst-container">
  <div class="span4 hst-container-item">
     ...
  </div>
  <div class="span4 hst-container-item">
     ...
  </div>
</div>

This works in the channel manager / template composer and complies to the bootstrap HTML that the designers gave you. (Note that the HTML works in the template composer since version hippo-addon-channel-manager 2.24.05 / CMS 7.8.5)

Step 3: Optionally get rid of hst-container and hst-container-item in HTML outside the channel manager

Although pretty harmless, you might not want to expose the css classes hst-container and hst-container-item to visitors on your live website. The css classes are only needed in the channel manager / template composer. Getting rid of them on the live website can be achieved by making the inclusion of these css classes conditional in the jsp of freemarker template. For example, in JSP it can be done by changing vbox_row_fluid.jsp into:

<%@ include file="/WEB-INF/jspf/htmlTags.jspf" %>
<hst:defineObjects/>
<c:if test="${hstRequestContext.cmsRequest}">
  <c:set var="containerClassName" value="hst-container"/>
  <c:set var="containerItemClassName" value="hst-container-item"/>
</c:if>
<div class="row-fluid ${containerClassName}">
  <c:forEach var="childContentName" items="${hstResponseChildContentNames}">
    <div class="span4 ${containerItemClassName}">
        <hst:include ref="${childContentName}"/>
    </div>
  </c:forEach>
</div>

A freemarker template that does the same looks as follows:

<#assign hst=JspTaglibs["http://www.hippoecm.org/jsp/hst/core"]>
<@hst.defineObjects/>
<#if hstRequestContext.cmsRequest>
    <#assign containerClass = "hst-container">
    <#assign containerItemClass = "hst-container-item">
<#else>
    <#assign containerClass = "">
    <#assign containerItemClass = "">
</#if>
<div class="row-fluid ${containerClass}">
  <#list hstResponseChildContentNames as childContentName>
  <div class="span4 ${containerItemClass}>
    <@hst.include ref="${childContentName}"/>
  </div>
  </#list>
</div>
From HST 2.26.06 and higher, the css classes hst-container and hst-container-item are only added to the HTML only when viewing the site in the channel manager

How to make your container renderer flexible

Let's continue with our new template vbox_row_fluid.jsp for your container. It contains the following part:

JSP

<c:forEach var="childContentName" items="${hstResponse.childContentNames}">
  <div class="span4 ${containerItemClass}">
      <hst:include ref="${childContentName}"/>
  </div>
</c:forEach>

Freemarker

<#list hstResponse.childContentNames as childContentName>
  <div class="span4 ${containerItemClass}">
      <@hst.include ref="${childContentName}"/>
  </div>
</#list>

This time however, you have some containers that must contain span6 items, some span9 and some span4. This can be achieved by creating different templates for each case, e.g. vbox_row_fluid_span6.jsp, vbox_row_fluid_span9.jsp, etc. However, you can also define your own hst:componentclassname on the hst:containercomponent that takes an hst parameter and sets this on the request as a variable.

Note that if you do not define an explicit hst:componentclassname on the hst:containercomponent, by default the component class org.hippoecm.hst.pagecomposer.builtin.components.StandardContainerComponent will be used. The standard container component will just render one of the default templates based on the value of the hst:xtype property, unless an explicit template is configured via the hst:template property. Use a custom HST component (that extends either  org.hippoecm.hst.pagecomposer.builtin.components.StandardContainerComponent or org.hippoecm.hst.core.component.GenericHstComponent) if your container should perform additional business logic.

How to have a css classname per component item instead of one defined by the container

In the previous examples, the hst:containercomponent renderer contained code like:

JSP

<c:forEach var="childContentName" items="${hstResponse.childContentNames}">
    <div class="span4 ${containerItemClassName}">
        <hst:include ref="${childContentName}"/>
    </div>
</c:forEach>

Freemarker

<#list hstResponse.childContentNames as childContentName>
    <div class="span4 ${containerItemClassName}">
        <@hst.include ref="${childContentName}"/>
    </div>
</#list>

Now  every container item will get the  <div class="span4"> wrapper element. However, assume you want your container to be some big area in which webmasters should be able to drop items of variable width. For example, your container can contain elements up to width span9. Assume you want webmasters to be able to create HTML something like

<div class="row-fluid">
  <div class="span3">
    ...
  </div>
  <div class="span3">
    ...
  </div>
  <div class="span3">
    ...
  </div>
  <div class="span9">
    ...
  </div>
  <div class="span6">
    ...
  </div>
  <div class="span3">
    ...
  </div>
</div>

So above, first  3 items of  span3, then one of  span9. and then one of  span6 and  span3. The above can only be achieved if you make the  <div class="spanX"> part of the renderer of the  containeritem! This means that the containercomponent renderer must get the  <div class="span4 ${containerItemClassName}"> removed. The containeritem renders must from then on be wrapper by:

JSP

<%@ include file="/WEB-INF/jspf/htmlTags.jspf" %>
<hst:defineObjects/>
<c:if test="${hstRequest.requestContext.cmsRequest}">
  <c:set var="containerItemClassName" value="hst-container-item"/>
</c:if>
<div class="span3 ${containerItemClassName}">
   // rest of containeritem renderer
</div>

Freemarker

<#include "/WEB-INF/freemarker/include/imports.ftl">
<@hst.defineObjects/>
<#if hstRequest.requestContext.cmsRequest>
  <#assign containerItemClassName="hst-container-item"/>
</#if>
<div class="span3 ${containerItemClassName}">
   // rest of containeritem renderer
</div>
Note that if you follow this approach, a containeritem might get  tied to its container. For example, if you have a container of  xtype = HST.Table, and you move the  <tr class="hst-container-item"><td> to the containeritem renderer, then the containeritem gets tied to table markup.
Did you find this page helpful?
How could this documentation serve you better?
On this page
    Did you find this page helpful?
    How could this documentation serve you better?