3.3Handle text with TinyRichtextParts
The richtext in a document is stored in a property of type text. The text property value is a String beeing almost normal HTML that could be processed by a DOM parser. Only links and components are not standard HTML and have to be transformed into either standard HTML for a website or other formats for other content types.
The href attribute of the A (anchor) tag has encoded either an external URL or a document ID as link target. Also a link type and optional additional parameters can be found there. From the document ID the Generator can produce an URL.
TinyRichtextParts
The app.cmsworks.util.text.tiny.TinyRichtextParts provide a lightweight but powerful way of handling various text manipulations.
Constructor
After giving the the text into the constructor the TinyRichtextParts creates a list of TinyRichtextPart objects representing a text part, a tag part (opening or closing) or a text component part.
The structure is not a tree, just a list referencing the different text parts in order. This list is not to be changed by removing, adding or exchanging elements.
An opening tag part is referencing it's closing part, contains a level.
Common functions of all TinyRichtextPart types
setText(String)
To replace the origin text simply set a new text to be produced in the final product
setTextBefore(String), setTextAfter(String), addTextBefore(String), addTextAfter(String)
Add some text before/after a text part.
setDoProduce(boolean)
To ignore this text part for the final product call setDoProduce(false). In this case also before and after Strings of this part will not be produced.
TinyRichtextTextPart
It does not add any functionality to the common functions.
TinyRichtextTagPart
- It contains the state if it's the opening or closing tag part or for example in case of a BR tag beeing both at the same time.
- If it's the opening part it references its closing part
- It contains a level info about the depth in the hierarchy of tags
- It manages an Attribute list.
getName()
Returns the tag name
setName(String)
For setting a new tag name
isNamed(String)
Helper for searching tags with special names
isOpeningTagPart(), isClosingTagPart(), getLevel()
Returning the state
setDoProduce(boolean)
not only for this tag part but also for the closing tag part if it is referenced
getClosingTagPart()
Returns the closing text part or null if not existing
getAttributeNames(), getAttribute(String), setAttribute(String, String), removeAttribute(String)
Managing attributes of the tag
TinyRichtextComponentPart
getDocumentId()
If a component is to be rendered from a Document
getPosition()
The positioning of the component in the text (left/right/inline/centered)
setText(String)
After producing the component the component code (HTML in most cases) is inserted into the text here.
TinyRichtextParts
getTextParts()
Returns the full list of text parts as TinyRichtextPart objects.
getTextParts(TinyRichtextPart)
returns a sublist of this text part. If the given TinyRichtextPart is actually an opening TinyRichtextTagPart all text parts are returned beginning at the opening tag and ending at the closing tag.
build(), build(TinyRichtextPart), build(idxStart, idxEnd)
Joining the text parts to a new text as a result after handling links, text components and any other creative text manipulations.
getUnTaggedText(), getUnTaggedText(idxStart, idxEnd)
It returns the collected text from each TinyRichtextPartText making sure that a space is added between block element texts.
hasOnlyEmptyText()
It tests if a tag has no visible text - whitespaces including are ignored.
To use the TinyRichtextParts for website texts more text handling is necessary especially to handle links created from the Generator. In this case a sub class is created for example in a util-textparts.jsf.
<%@page import="
app.cmsworks.cms.document.DocumentModel,
app.cmsworks.util.text.tiny.TinyRichtextParts,
app.cmsworks.util.text.tiny.TinyRichtextPart,
app.cmsworks.util.text.tiny.TinyRichtextTagPart,
app.cmsworks.util.text.tiny.TinyRichtextTextPart,
app.cmsworks.util.text.tiny.TinyRichtextComponentPart,
app.cmsworks.util.text.tiny.TinyRichtextLinkTransformerHTML,
java.util.ArrayList
"
pageEncoding="UTF-8"
%><%!
/** The subclass of TinyRichtextParts will handle links and components
*/
public class MyTinyRichtextParts extends TinyRichtextParts {
/** Constructor parsing the given text
*/
public MyTinyRichtextParts(String text) {
super(text);
}
/** Find all p elements with no component and no text inside to deaktivate them
*/
public void deleteEmptyP() {
// for each opening tag part named p
for (TinyRichtextTagPart trpTag : getOpeningTagsNamed("p")) {
// having no class attribute
if (trpTag.getAttribute("class") == null) {
// having no component and no text
if (hasNoComponentAndOnlyEmptyText(trpTag)) {
// set doProduce=false for this tag and all content text parts
removeAll(trpTag);
}
}
}
}
/** Collecting and returning the component parts of the text
*/
public TinyRichtextComponentPart[] getComponentParts() {
// create a list to collect the component parts in
ArrayList<TinyRichtextComponentPart> list = new ArrayList<TinyRichtextComponentPart>();
// for each text part
for (TinyRichtextPart trp : getTextParts()) {
// if the text part is still to be produced
if (trp.doProduce()) {
// if the text part is a component part
if (trp instanceof TinyRichtextComponentPart) {
// add it into the list
list.add((TinyRichtextComponentPart) trp);
}
}
}
// return the array from the list
return list.toArray(new TinyRichtextComponentPart[list.size()]);
}
/** Working the links of the text
*/
public void handleLinks(DocumentModel dmAny) throws Exception {
// for each link
for (TinyRichtextTagPart trpA : getOpeningTagsNamed("a")) {
// create a Transformer
TinyRichtextLinkTransformerHTML tran = new TinyRichtextLinkTransformerHTML(trpA);
// set a resolved URL if it's an internal link
tran.resolveUrl(dmAny.getUrlCreator());
// do produce the link in propert HTML coding
tran.transform();
}
}
}
%>Exteding the TinyRichtextParts to handle links, removing empty lines and provide access to text components.
Within a page-xxx.jsp the MyRichtextParts can be used to render text into a HTML page.
<%@page import="
app.cmsworks.cms.document.ErrorView,
app.cmsworks.cms.document.HTMLErrorView,
app.cmsworks.util.uilink.UILink,
app.cmsworks.cms.document.ContentInclude
"
session="false"
contentType="text/html;charset=UTF-8"
%><%@include file="includes/documentmodel.jsf"
%><%@include file="includes/util-texthandler.jsf"
%><%
ErrorView errors = new HTMLErrorView();
DocumentModel dmPage = null;
UILink uiLink = new UILink(request);
String htmlText = "";
// fetch the sensible data
try {
// get the DocumentModel from request
dmPage = new DocumentModel(request, new Types());
// init the errorview
errors.setPreview(dmPage);
// use the created MyTinyRichtextParts with the text to render
MyTinyRichtextParts textPartsText = new MyTinyRichtextParts(dmPage.getString(Types.PT_TEXT));
// transform the links
textPartsText.handleLinks(dmPage);
// remove empty lines
textPartsText.deleteEmptyP();
// fill components
for (TinyRichtextComponentPart compPart : textPartsText.getComponentParts()) {
DocumentModel mrComponent = new DocumentModel(compPart.getDocumentId(), dmPage);
ContentInclude include = null;
if (mrComponent.isType(Types.RT_MEDIUM)) {
include = new ContentInclude(dmPage, mrComponent, "cmp-medium.jsp", errors);
}
else if (mrComponent.isType(Types.RT_INFOBOX)) {
include = new ContentInclude(dmPage, mrComponent, "cmp-infobox.jsp", errors);
}
...
String htmlComponent = null;
if (include != null) {
htmlComponent = include.getIncludeContent();
}
// if the include has errors or was not assigned by the conditions before the compPart will simply
// be deactivated
if (htmlComponent != null) {
htmlComponent = "<span class=\"txtcomp " + compPart.getPosition() + "\">" + htmlComponent + "</span>";
compPart.setText(htmlComponent);
}
else {
compPart.setDoProduce(false);
errors.add(errors.asUILink(mrComponent) + "This document is not usable as text component.");
}
}
htmlText = textPartsText.build();
}
catch (Throwable t) {
if (errors.exit(response, t, dmPage, this.getClass().getName())) {
return;
}
}
//now start the HTML-Output
%><!DOCTYPE html>
<html>
<head>
...
<%= uiLink.getIncludes() %>
</head>
<body>
...
<!-- placing the text and editable markers into the html code -->
<div class="richtext"><%= htmlText %></div>
...
<%= errors.render() %>
</body>
</html>Using MyRichtextParts to render richtext into the HTML page.
