Getting Multiple CSS Classes to work in the Sitecore Rich Text Editor

This is my RTE. There are many like it, but this one is mine!

Welcome to my first long post on here, and it’s a Sitecore one. A recent request I ran into provided a bit of a challenge to achieve on top of the CMS. Everyone likes a few styles in their Rich Text Editor, but normally it’s quite a small set of them to avoid overcomplicating it for the content editors, and to avoid unpredictable visual clashes. On this occasion though it was to be quite an expansive set of custom styles, covering the ability to have different styles of button applied to a link, and then have an entire set of applicable colours that could be added to each one.

In normal CSS classing, that’s a fairly simple concept as you can just chain up styles by listing them with spaces in an element’s class attribute – so you can have button-rounded, button-square then chain on the colours. When it comes to using the RTE Sitecore editor though, you hit a bit of a snag. You can select an element no problem and apply a class… but only the one class. So I was left with two options. Have a class for every possible button style with every colour, and watch that grow exponentially into an unmanageable dropdown of styles. Or find a way to apply multiple classes to a single element.

Sitecore’s Rich Text control is actually based upon Telerik’s RadEditor plugin which has been wrapped up inside the familiar Sitecore UI. Whilst there didn’t seem to be a huge number of people asking about this feature, some digging led to a very old discussion from 2011 where someone had posted up a conceptual way to add a ‘apply multiple classes’ element to the Rad interface.

http://www.telerik.com/support/code-library/enable-multiple-css-class-selection

Despite being 6 years old as a post now, it seemed worth giving a go at updating this and porting it in to something compatible with Sitecore 8.1, and thus follows the successful process:-

Inside sitecore\shell\Controls\Rich Text Editor
(Yes, I know we’re changing a core file, sorry!)

– MultiCss.aspx

This is a new file to create and the UI that will pop up in a separate window for selecting the styles. I worked off their original posted basic file above, just making it a little tidier and more intuitive. As this is a separate bit of HTML and javascript, and this does have access to the Jquery library, you could do even more with this if preferred, but this is a simple enough example.


<%@ Page Language="C#" AutoEventWireup="true" EnableViewState="false" %>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<style type="text/css">
    body
    {
        font-family: arial, helvetica, sans-serif;
        font-size: 11px;
    }
    h1
    {
        font-size: 14px;
        margin-bottom: 1em;
    }
     
    #AvailableClasses, #CssClasses { width:200px; }
    #btnAddClass, #btnClearClasses { margin:0; padding:0; }
</style>
<h1>Multiple CSS Class Editor:- <<span id="CurrentTag"></span>></h1>
<br />
<select name="AvailableClasses" id="AvailableClasses" size="10" multiple="multiple"></select> <input type="button" value="+" id="btnAddClass" /><br />
<input name="CssClasses" type="input" id="CssClasses" value=""> <input type="button" value="Clear" id="btnClearClasses" /><br />
<input type="button" onclick="javascript:insertLink();" value="Update Styling" />
<input type="button" onclick="javascript:cancel();" value="Cancel" />
<script type="text/javascript">
    if (window.attachEvent) {
        window.attachEvent("onload", initDialog);
    }
    else if (window.addEventListener) {
        window.addEventListener("load", initDialog, false);
    }
 
    var btn = null;
 
    function getRadWindow() {
        if (window.radWindow) {
            return window.radWindow;
        }
        if (window.frameElement && window.frameElement.radWindow) {
            return window.frameElement.radWindow;
        }
        return null;
    }
 
    function initDialog() {
        arguments = getRadWindow().ClientParameters; //return the arguments supplied from the parent page
        $("#CurrentTag").text($(arguments.elem).get(0).tagName);
        $("#CssClasses").val($(arguments.elem).attr("class"));
        
        $(arguments.classes).each(function(i,e)
        {
            var Option = "<option>" + e + "</option>";
            $("#AvailableClasses").append(Option);
        });
         
        $("#btnAddClass").click(function() { $("#AvailableClasses option:selected").each(function() { $("#CssClasses").val($("#CssClasses").val() + " " + $(this).val()); }) });
        $("#btnClearClasses").click(function() { $("#CssClasses").val(""); });
    }
 
    function insertLink() //fires when the Insert Link button is clicked
    {    
        btn = $("#CssClasses").val();
        getRadWindow().close(btn); //use the close function of the getRadWindow to close the dialog and pass the arguments from the dialog to the callback function on the main page.
    }
 
    function cancel() {
        getRadWindow().close();
    }
</script>

RichText Commands.js

This file is an existing one that needs updating to add the trigger for your new editor button. In the poster’s original idea they’d been able to assume Jquery would be present on the page the RTE sits on. Not particularly wanting to nest an additional Jquery call within the Sitecore back office, I migrated this to a purer JS solution. Be very careful to note the name of the method in the square brackets here as it is essential in the next step. Add the following to the file before the ‘Telerik.Web.UI.Editor .CommandList [“InsertSitecoreLink”] line.


Telerik.Web.UI.Editor.CommandList["MultiCss"] = function(commandName, editor, args) {
    {
        arguments = new Object();
        arguments.elem = editor.getSelectedElement();
        var CssArray = editor.getCssArray();
        var Classes = new Array();
        
        $(CssArray).forEach(function(classArray)
        {
            Classes.push(classArray[0]);
        });
         
        arguments.classes = Classes;

        var myCallbackFunction = function (sender, args) {
            var CssClasses = args;
            $(editor.getSelectedElement()).className = CssClasses;
        }
        
        if($(arguments.elem).nodeName != "BODY")
        {
        editor.showExternalDialog(
            '/sitecore/shell/Controls/Rich Text Editor/MultiCss.aspx',
            arguments,
            280,
            310,
            myCallbackFunction,
            null,
            'CSS Class Chooser',
            true,
            Telerik.Web.UI.WindowBehaviors.Close + Telerik.Web.UI.WindowBehaviors.Move,
            false,
            false);
        }
        else
        {
            alert("Please select an element first.");
        }
    };
};

Inside Sitecore’s Content Editor
– Switch to Core
– Create an additional button item in the Sitecore content tree. Where exactly this sits depends entirely upon what toolset you have configured to show the content editors. I did it under the Custom Profile (/sitecore/system/settings/Html Editor Profiles/Rich Text Custom/Toolbar 1). My suggestion is just to copy an existing ‘button’ one, for example the bold button and rename this.
– Edit your new item and ensure the ‘Click’ field inside of it points to the same name as the JS function you made above, in this example ‘MultiCss’. It’s very important for these to match!
– Save the new editor button. As you’re working in Core, you shouldn’t need to republish anything

After this, swap back out of the Core DB and do a hard refresh (and be aware, the browsers can be quite aggressive with caching this). When you next go to edit a field you should see your new button in the rich text editor toolbar. By default it’ll probably have a ? icon as the styling looks for a class named the same as the function name, and falls back to a ? icon when it can’t find one. If you really want to you could add your own icon class, although the lack of a graphic doesn’t affect the functionality of it.

Assuming all the caching has been correctly cleared (either the icon missing completely, or a JS error when you click the button are common signs something old is sticking), everything should now just work. Create an element as normal – for example a word you want to add 3 styles to. To make this an element, you may have to do something like add bold, or just use the normal single CSS dropdown first which will wrap it with a span. Then hit the new icon and up should pop your fresh window with the ability to choose multiple styles. Choose the two or three as needed, hit okay and it’ll callback to the main editor window with your chained set of multiple css styles applied.