Rich-Text Elements

Brightspot’s rich-text editor accommodates custom rich-text elements, such as embedded videos, image galleries, or pull quotes. For example, the following illustration is an example of a rich-text element rendered as a pull quote. The element contains typeface, alignment, and a left border.

../../../_images/rich-text-element.png

Deploying a Rich-Text Element

The following steps outline how to design rich-text elements and attach them to the rich-text editor’s toolbar. Although the steps are specific to pull quotes, you can apply them to any custom rich-text element.

Step 1: Extend a Rich-Text Element

All custom rich-text elements extend from RichTextElement.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
package content.article;

import com.psddev.cms.db.RichTextElement;
import com.psddev.dari.db.Recordable;
import com.psddev.dari.util.StringUtils;
import java.util.Map;

@Recordable.DisplayName("Pull Quote")
@RichTextElement.Tag(
    value = "quote",
    preview = true,
    block = false,
    root = true,
    menu = "Enhancement")
public class PullQuoteRichTextElement extends RichTextElement {

    @Required
    private String quote;

    public String getQuote() {
        return quote;
    }

    public void setQuote(String quote) {
        this.quote = quote;
    }

    @Override
    public Map<String, String> toAttributes() {
        return null;
    }

    @Override
    public void fromAttributes(Map<String, String> attributes) {
    }

    @Override
    public void fromBody(String body) {
        setQuote(StringUtils.unescapeHtml(body));
    }

    @Override
    public String toBody() {
        return getQuote();
    }

}

In the previous snippet—

  • Line 8 specifies that the rich-text element appears as Pull Quote in the rich-text toolbar.

  • Lines 9–14 specify presentation aspects of the rich-text element:

    • The Styleguide files use the value element for creating the View. In this snippet, the Styleguide files must provision the rich-text element using the identifier quote.

    • In the toolbar, the rich-text element appears under the menu item Enhancement.

      ../../../_images/pull-quote-menu-button.png

      Quote Element Under Enhancement Toolbar Menu

    For information about the @RichTextElement.Tag annotation, see @RichTextElement.Tag.

  • Lines 28–45 override the methods toAttributes, fromAttributes, fromBody, and toBody. These methods provide the interface between the rich-text element and the associated editing widget. For details, see Editing Lifecycle of Rich-Text Elements.

Step 2: Attach Rich-Text Element to Toolbar

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
package content.article;

import java.util.Arrays;
import java.util.List;

import com.psddev.cms.rte.RichTextToolbar;
import com.psddev.cms.rte.RichTextToolbarItem;
import com.psddev.cms.rte.RichTextToolbarStyle;

public class CustomRichTextToolbar implements RichTextToolbar {

    @Override
    public List<RichTextToolbarItem> getItems() {
        return Arrays.asList(
            RichTextToolbarStyle.BOLD,
            RichTextToolbarStyle.ITALIC,
            RichTextToolbarStyle.UNDERLINE
            RichTextToolbarStyle.ELEMENTS);
    }

}

In the previous snippet, line 18 attaches all custom rich-text elements to the toolbar. See the illustration Quote Element Under Enhancement Toolbar Menu.

Step 3: Create Styleguide Files

Under your project’s styleguide/ directory, create Styleguide files for each field appearing in the rich-text element. For example, if a field body is typed as a rich-text field, then the Styleguide files must provide the template, data file, and styling for the field body. As a best practice, ensure each file’s path and base name correspond to the rich-text element’s class. The following example provides an illustration for Styleguide files corresponding to the class PullQuoteRichTextElement developed in Step 1.

└── <root>
    ├── src
    |   └── main
    |       └── java
    |           └── brightspot
    |               └── content
    |                   └── article
    |                       └── PullQuoteRichTextElement.java
    └── styleguide
        └── content
            └── article
                ├── PullQuoteRichTextElement.hbs
                ├── PullQuoteRichTextElement.json
                └── PullQuoteRichTextElement.less

For information about creating Styleguide files, see Introduction to Styleguide.

See also:

Editing Lifecycle of Rich-Text Elements

Subclasses of RichTextElement can implement the callbacks required for editing rich-text elements.

  • Inside the rich-text editor, clicking Edit fires two callbacks:
    • RichTextElement#fromBody to populate the editing widget’s Link Text field and the Main tab of the Link field.
    • RichTextElement#fromAttributes to populate the editing widget’s Attributes field in the Advanced tab.
  • Inside the editing widget, clicking Save & Close fires two callbacks to create a traditional HTML link of the form <a href="value" otherattribute="othervalue">link text</a>:
    • RichTextElement#toBody to retrieve the link text from the editing widget’s Link Text field.
    • RichTextElement#toAttributes to retrieve the link’s attributes from the editing widget’s Attributes field in the Advanced tab.
../../../_images/to-from-body.png

The following snippet describes the interaction between the rich-text element and the editing widget.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
package brightspot.core.link;

import com.psddev.cms.db.RichTextElement;
import com.psddev.dari.util.CompactMap;
import com.psddev.dari.util.StringUtils;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class AnotherLinkRichTextElement extends RichTextElement {

    @Required
    private Link link;

    private String linkText;

    public String getLinkText() {
        return linkText;
    }

    public void setLinkText(String linkText) {
        this.linkText = linkText;
    }

    @Override
    public void fromBody(String body) {
        setLinkText(StringUtils.unescapeHtml(body));
    }

    @Override
    public String toBody() {
        return getLinkText();
    }

    @Override
    public void fromAttributes(Map<String, String> attributes) {
        List<Attribute> createdAttributes = attributes.keySet()
                .stream()
                .map(key -> {
                    Attribute attribute = new Attribute();
                    attribute.setName(key);
                    attribute.setValue(attributes.get(key));

                    return attribute;

                })
                .collect(Collectors.toList());

        link.setAttributes(createdAttributes);
    }

    @Override
    public Map<String, String> toAttributes() {
        Map<String, String> htmlAttributes = new CompactMap<>();
        link.getAttributes()
                .forEach(attribute -> htmlAttributes.put(attribute.getName(), attribute.getValue()));
        return htmlAttributes;
    }
}

In the previous snippet—

  • Lines 13–14 declare a Link field that contains the attributes in an HTML <a> element.
  • Lines 16–24 declare a field, getter, and setter for the link text (the text inside an HTML <a> element).
  • Lines 26–29 populate the field Link Text in the editing widget, unescaping any escaped HTML entities that may have been received from the rich-text element.
  • Lines 31–34 retrieve the value in the field Link Text, and use it as the link text when constructing an HTML <a> element.
  • Lines 36–51 read the attribute map passed from the rich-text element and populate the Attributes list in the editing widget’s Advanced tab.
  • Lines 53–59 read the Attributes list in the editing widget’s Advanced tab, and use it to construct the attributes in an HTML <a> element.

Storage of Rich-Text Elements

Brightspot stores rich-text elements in XML format, similar to the following:

{
  "caption": "Here is a link <a href=\"http://www.brightspot.com/\" target=\"_blank\" cursor=\"wait\" type=\"text/html\" >Brightspot</a>."
}

The element and attribute names you can use in a custom rich-text element are arbitrary, so you can design rich-text elements to fit your publishing needs. You then implement runtime parsers in ViewModels that extract the elements and attributes from the database and populate the View.