The content element above is showing a teaser. The resource type of the teaser component is
composum/pages/components/element/teaser
The base implementation shipped as part of the Composum Pages Components is located in the /libs
resource resolver root. The component declaration here
<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:cpp="http://sling.composum.com/pages/1.0"
xmlns:jcr="http://www.jcp.org/jcr/1.0"
xmlns:nt="http://www.jcp.org/jcr/nt/1.0"
xmlns:sling="http://sling.apache.org/jcr/sling/1.0"
jcr:primaryType="cpp:Component"
sling:resourceSuperType="composum/pages/components/element"
jcr:description="a teaser to guide to another page"
jcr:title="Teaser"
category="[Teaser,General,Blueprint]">
<jcr:content
jcr:primaryType="nt:unstructured">
<properties
jcr:primaryType="nt:unstructured">
<variation
jcr:primaryType="nt:unstructured"/>
<title
jcr:primaryType="nt:unstructured"
i18n="{Boolean}true"
text="plain"/>
<subtitle
jcr:primaryType="nt:unstructured"
i18n="{Boolean}true"
text="plain"/>
<text
jcr:primaryType="nt:unstructured"
i18n="{Boolean}true"
required="{Boolean}true"
text="rich"/>
<link
jcr:primaryType="nt:unstructured"/>
<linkTitle
jcr:primaryType="nt:unstructured"
i18n="{Boolean}true"
text="plain"/>
<linkTarget
jcr:primaryType="nt:unstructured"/>
<icon
jcr:primaryType="nt:unstructured"/>
</properties>
<elements
jcr:primaryType="nt:unstructured">
<image
jcr:primaryType="nt:unstructured"
type="composum/pages/components/element/image"/>
<video
jcr:primaryType="nt:unstructured"
type="composum/pages/components/element/video"/>
<links
jcr:primaryType="nt:unstructured"
type="composum/pages/components/element/link/set"/>
</elements>
</jcr:content>
</jcr:root>
defines a placable component (cpp:Component
primary type). Such a Sling component is registered by the Pages Component Manager automatically and offered in the various component type selector widgets for insertion into a container of a content page.
Teaser Scripting
<%@page session="false" pageEncoding="UTF-8" %>
<%@taglib prefix="cpp" uri="http://sling.composum.com/cppl/1.0" %>
<cpp:defineObjects/>
<cpp:model var="teaser" type="com.composum.pages.components.model.teaser.Teaser">
<cpp:include test="${teaser.valid}" replaceSelectors="${teaser.variation}"/>
</cpp:model>
This looks very simple because the main template is delegation the rendering to the teasers variation declared by a property of the teaser. This property 'defined' in the teasers edit dialog.
Edit Dialog
<%@page session="false" pageEncoding="utf-8" %>
<%@taglib prefix="cpp" uri="http://sling.composum.com/cppl/1.0" %>
<cpp:defineFrameObjects/>
<cpp:editDialog title="@{dialog.selector=='create'?'Create a Teaser':'Edit Teaser'}">
<cpp:editDialogTab tabId="teaser" label="Properties">
<div class="row">
<div class="col col-xs-8">
<cpp:widget label="Teaser Title" property="title" type="textfield" i18n="true"/>
</div>
<div class="col col-xs-4">
<cpp:widget label="Variation" property="variation" type="select" hint="render type"
options="default,bgimage,bgvideo,symbol" default="default"/>
</div>
</div>
<cpp:widget label="Subtitle" property="subtitle" type="textfield" i18n="true"/>
<cpp:widget label="Text" property="text" type="richtext" i18n="true" required="true"
height="120px"/>
<cpp:include resourceType="composum/pages/components/element/link" subtype="edit/dialog"
replaceSelectors="embedded"/>
</cpp:editDialogTab>
<cpp:editDialogTab tabId="image" label="Image">
<cpp:include path="image" resourceType="composum/pages/components/element/image" subtype="edit/dialog"
replaceSelectors="embedded"/>
</cpp:editDialogTab>
<cpp:editDialogTab tabId="video" label="Video">
<cpp:include path="video" resourceType="composum/pages/components/element/video" subtype="edit/dialog"
replaceSelectors="embedded"/>
</cpp:editDialogTab>
<cpp:editDialogTab tabId="icon" label="Icon">
<div class="row">
<div class="col col-xs-7">
<cpp:widget type="static"
value="Alternative to a teaser image or video a symbol can be used. The chosen symbol is not used if an image or video is referenced."/>
</div>
<div class="col col-xs-5">
<cpp:widget label="Symbol" property="icon" type="iconcombobox"
hint="<a href='https://fontawesome.com/v4.7.0/icons/' target='_blank'>'FontAwesome'</a> icon key"
options="at,asterisk,bookmark-o:bookmark,check,exclamation,eye,info-circle:info,lightbulb-o:lightbulb,question-circle-o:qestion,search,warning,wrench"
typeahead="/bin/cpm/core/system.typeahead.json/libs/fonts/awesome/4.7.0/font-awesome-keys.txt"/>
</div>
</div>
</cpp:editDialogTab>
</cpp:editDialog>
The Model Class
/*
* copyright (c) 2015ff IST GmbH Dresden, Germany - https://www.ist-software.com
*
* This software may be modified and distributed under the terms of the MIT license.
*/
package com.composum.pages.components.model.teaser;
import com.composum.pages.components.model.ImageRelatedElement;
import org.apache.commons.lang3.StringUtils;
import org.apache.sling.api.resource.Resource;
import static com.composum.pages.components.model.text.Text.PROP_TEXT;
public class Teaser extends ImageRelatedElement {
public static final String PROP_VARIATION = "variation";
public static final String DEFAULT_VARIATION = "default";
public static final String PROP_LINK = "link";
public static final String PROP_LINK_TITLE = "linkTitle";
public static final String PROP_SUBTITLE = "subtitle";
public static final String NODE_IMAGE = "image";
public static final String PROP_IMAGE_REF = NODE_IMAGE + "/imageRef";
public static final String NODE_VIDEO = "video";
public static final String PROP_VIDEO_REF = NODE_VIDEO + "/videoRef";
public static final String PROP_ICON = "icon";
public static final String NODE_LINKS = "links";
public static final String SELECTOR_LINK_SET = NODE_LINKS;
public static final String SELECTOR_TEXTBLOCK = "textblock";
public static final String SELECTOR_PLACEHOLDER = "placeholder";
private transient String variation;
private transient String subtitle;
private transient String text;
private transient String icon;
public String getVariation() {
if (variation == null) {
variation = getProperty(PROP_VARIATION, DEFAULT_VARIATION);
if (isHasLinkSet()) {
variation += "-" + SELECTOR_LINK_SET;
}
}
return variation;
}
public String getShape() {
return isUseVideo() ? "video" : isUseImage() ? "image" : isUseIcon() ? "symbol" : "text";
}
public boolean isNoAsset() {
return !isUseVideo() && !isUseImage();
}
public boolean isUseVideo() {
return StringUtils.isNotBlank(getProperty(PROP_VIDEO_REF, ""));
}
public boolean isUseImage() {
return !isUseVideo() && StringUtils.isNotBlank(getProperty(PROP_IMAGE_REF, ""));
}
public boolean isUseIcon() {
return !isUseImage() && StringUtils.isNotBlank(getIcon());
}
public boolean isHasIcon() {
return StringUtils.isNotBlank(getIcon());
}
public String getIcon() {
if (icon == null) {
icon = getProperty(PROP_ICON, "");
}
return icon;
}
public String getSubtitle() {
if (subtitle == null) {
subtitle = getProperty(PROP_SUBTITLE, "");
}
return subtitle;
}
public String getText() {
if (text == null) {
text = getProperty(PROP_TEXT, "");
}
return text;
}
public boolean isTextValid() {
return StringUtils.isNotBlank(getTitle())
|| StringUtils.isNotBlank(getSubtitle())
|| StringUtils.isNotBlank(getText());
}
public boolean isHasLinkSet() {
Resource links = getResource().getChild(NODE_LINKS);
return links != null && links.hasChildren();
}
public String getTextSelector() {
return isTextValid() ? SELECTOR_TEXTBLOCK : SELECTOR_PLACEHOLDER;
}
}
This looks very simple because the main template is delegation the rendering to the teasers variation declared by a property of the teaser. This property 'defined' in the teasers edit dialog.
the default teaser variation
<%@page session="false" pageEncoding="UTF-8" %>
<%@taglib prefix="cpn" uri="http://sling.composum.com/cpnl/1.0" %>
<%@taglib prefix="cpp" uri="http://sling.composum.com/cppl/1.0" %>
<cpp:defineObjects/>
<cpp:element var="teaser" type="com.composum.pages.components.model.teaser.Teaser"
cssAdd="@{teaserCSS}_variation_default @{teaserCSS}_@{teaser.shape}">
<cpn:link test="${teaser.hasLink}" body="true" class="${teaserCSS}_link"
href="${teaser.linkUrl}" target="${teaser.linkTarget}" title="${teaser.linkTitle}">
<cpn:div test="${teaser.useImage||teaser.useVideo||teaser.authorMode}" class="${teaserCSS}_asset">
<cpn:div test="${teaser.useImage||teaser.authorMode}" class="${teaserCSS}_image">
<cpp:include path="image" resourceType="composum/pages/components/element/image"/>
</cpn:div>
<cpn:div test="${teaser.useVideo||teaser.authorMode}" class="${teaserCSS}_video">
<cpp:include path="video" resourceType="composum/pages/components/element/video"/>
</cpn:div>
</cpn:div>
<cpn:div test="${teaser.useIcon}" class="${teaserCSS}_icon"><i
class="fa fa-${teaser.icon}"></i></cpn:div>
<div class="${teaserCSS}_content">
<cpp:include replaceSelectors="${teaser.textSelector}"/>
<cpp:include path="links" resourceType="composum/pages/components/element/link/set"/>
</div>
</cpn:link>
</cpp:element>
the other teaser variations
'bgimage' teaser
<%@page session="false" pageEncoding="UTF-8" %>
<%@taglib prefix="cpn" uri="http://sling.composum.com/cpnl/1.0" %>
<%@taglib prefix="cpp" uri="http://sling.composum.com/cppl/1.0" %>
<cpp:defineObjects/>
<cpp:element var="teaser" type="com.composum.pages.components.model.teaser.Teaser"
cssAdd="@{teaserCSS}_variation_bg-image"
style="background-image:url(@{teaser.imageUrl})">
<cpp:dropZone property="image/imageRef" filter="asset:image">
<cpn:link test="${teaser.hasLink}" body="true" class="${teaserCSS}_link"
href="${teaser.linkUrl}" target="${teaser.linkTarget}" title="${teaser.linkTitle}">
<cpn:div test="${teaser.hasIcon}" class="${teaserCSS}_icon"><i
class="fa fa-${teaser.icon}"></i></cpn:div>
<div class="${teaserCSS}_content">
<cpp:include replaceSelectors="${teaser.textSelector}"/>
</div>
</cpn:link>
</cpp:dropZone>
</cpp:element>
'bgvideo' teaser
<%@page session="false" pageEncoding="UTF-8" %>
<%@taglib prefix="cpn" uri="http://sling.composum.com/cpnl/1.0" %>
<%@taglib prefix="cpp" uri="http://sling.composum.com/cppl/1.0" %>
<cpp:defineObjects/>
<cpp:element var="teaser" type="com.composum.pages.components.model.teaser.Teaser"
cssAdd="@{teaserCSS}_variation_bg-video">
<cpp:include path="video" resourceType="composum/pages/components/element/video/background" mode="none"/>
</cpp:element>