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.

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 .

Extending a rich-text element
import com.psddev.cms.db.RichTextElement;
import com.psddev.dari.db.Recordable;
import com.psddev.dari.util.StringUtils;

@Recordable.DisplayName("Pull Quote") 1
    @RichTextElement.Tag( 2
    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 3
    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();
    }

}
  • Specifies the rich-text element displays as a pull quote in the rich-text toolbar.
  • Specifies the presentation aspects of the rich-text element:
    • The theme’s data files use the value element for creating the view. In this snippet, the data files must provision the rich-text element using the identifier quote.
    • In the toolbar, the rich-text element appears under the menu item Enhancement.
    For information about the @RichTextElement.Tag annotation see @RichTextElement.Tag.
  • Overrides 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

Attach the rich-text element to the toolbar
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() { 1
        return Arrays.asList(
            RichTextToolbarStyle.BOLD,
            RichTextToolbarStyle.ITALIC,
            RichTextToolbarStyle.UNDERLINE
            RichTextToolbarStyle.ELEMENTS);
    }

}
  • Attaches all custom rich-text elements to the toolbar.

Step 3: Create theme files

Under your project’s styleguide / directory, create 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 theme’s 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 theme files corresponding to the class PullQuoteRichTextElement developed in Step 1.

Sample
./ 

└── <root> 

            ├── src |

                       └── main |

                                  └── java |

                                            └── brightspot |

                                                       └── content |

                                                                  └── article |

                                                                             └── PullQuoteRichTextElement.java 

             └── styleguide 

                        └── content  

                                   └── article 

                                              ├── PullQuoteRichTextElement.hbs 

                                              ├── PullQuoteRichTextElement.json 

                                              └── PullQuoteRichTextElement.less

For information about creating theming files, see Theme guide .

See also:

  • Rendering rich text
  • Rich-text toolbar

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.

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

Interaction between the rich-text element and the editing widget
import com.psddev.cms.db.RichTextElement;
import com.psddev.dari.util.CompactMap;
import com.psddev.dari.util.StringUtils;

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; 
    }
}
  • Declares a Link field that contains the attributes in an HTML <a> element.
  • Declares a field, getter, and setter for the link text (the text inside an HTML <a> element.
  • Populates the field Link Text in the editing widget, unescaping any escaped HTML entities that may have been received from the rich-text element.
  • Retrieves the value in the field Link Text, and uses it as the link text when constructing an HTML <a> element.
  • Reads the attribute map passed from the rich-text element and populates the Attributes list in the editing widget’s Advanced tab.
  • Reads the Attributes list in the editing widget’s Advanced tab, and uses it to construct the attributes in an HTML <a> element.

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

Storage of rich-text elements
{
  "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 view models that extract the elements and attributes from the database and populate the view.

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 .

Extending a rich-text element
import com.psddev.cms.db.RichTextElement;
import com.psddev.dari.db.Recordable;
import com.psddev.dari.util.StringUtils;

@Recordable.DisplayName("Pull Quote") 1
    @RichTextElement.Tag( 2
    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 3
    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();
    }

}
  • Specifies the rich-text element displays as a pull quote in the rich-text toolbar.
  • Specifies the presentation aspects of the rich-text element:
    • The theme’s data files use the value element for creating the view. In this snippet, the data files must provision the rich-text element using the identifier quote.
    • In the toolbar, the rich-text element appears under the menu item Enhancement.
    For information about the @RichTextElement.Tag annotation see @RichTextElement.Tag.
  • Overrides 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

Attach the rich-text element to the toolbar
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() { 1
        return Arrays.asList(
            RichTextToolbarStyle.BOLD,
            RichTextToolbarStyle.ITALIC,
            RichTextToolbarStyle.UNDERLINE
            RichTextToolbarStyle.ELEMENTS);
    }

}
  • Attaches all custom rich-text elements to the toolbar.

Step 3: Create theme files

Under your project’s styleguide / directory, create 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 theme’s 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 theme files corresponding to the class PullQuoteRichTextElement developed in Step 1.

Sample
./ 

└── <root> 

            ├── src |

                       └── main |

                                  └── java |

                                            └── brightspot |

                                                       └── content |

                                                                  └── article |

                                                                             └── PullQuoteRichTextElement.java 

             └── styleguide 

                        └── content  

                                   └── article 

                                              ├── PullQuoteRichTextElement.hbs 

                                              ├── PullQuoteRichTextElement.json 

                                              └── PullQuoteRichTextElement.less

For information about creating theming files, see Theme guide .

See also:

  • Rendering rich text
  • Rich-text toolbar

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.

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

Interaction between the rich-text element and the editing widget
import com.psddev.cms.db.RichTextElement;
import com.psddev.dari.util.CompactMap;
import com.psddev.dari.util.StringUtils;

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; 
    }
}
  • Declares a Link field that contains the attributes in an HTML <a> element.
  • Declares a field, getter, and setter for the link text (the text inside an HTML <a> element.
  • Populates the field Link Text in the editing widget, unescaping any escaped HTML entities that may have been received from the rich-text element.
  • Retrieves the value in the field Link Text, and uses it as the link text when constructing an HTML <a> element.
  • Reads the attribute map passed from the rich-text element and populates the Attributes list in the editing widget’s Advanced tab.
  • Reads the Attributes list in the editing widget’s Advanced tab, and uses it to construct the attributes in an HTML <a> element.

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

Storage of rich-text elements
{
  "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 view models that extract the elements and attributes from the database and populate the view.