Context based CSS in WYSIWYG TinyMCE editor for EPiServer multisite

In multisite scenarios or when you use optimization libraries you’ll need to set the TinyMCE editor css dynamically from the code.

icon of user profile

tinymce

Normally you register the editor CSS thru the web configuration:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
 <episerver>
  <applicationSettings uiEditorCssPaths=”/Content/bootstrap.css, /Content/site.css” />
 </episerver>
</configuration>

But sometimes in scenarios where you are using a optimization library like Combres to pack the CSS:s you’ll need to set the CSS programmatically. If you have a multisite scenario you’ll need different CSS for each site.  Thanks to other blogposts I’ve made a variation of a descriptor that works for my solution.

Since I use bootstrap.css I had to put some classes like “container” in the tinyMCE editors body to make bootstrap work. I also put the site name in the body class and the property name. Finally I add a tinymce.css where I can put custom editor css and editor styles, styleswith help of EditMenuTitle and EditMenuName (which won’t work if you don’t have a stop “;”)

Because the WYSIWYG uses an iframe, be aware of the column widths will not work, since the editor width is smaller.

namespace EPiServerXhtmlStringSettings.Business.EditorDescriptors
{
    [EditorDescriptorRegistration(TargetType = typeof(XhtmlString), EditorDescriptorBehavior = EditorDescriptorBehavior.PlaceLast)]
    public class CustomXhtmlStringEditorDescriptor : EditorDescriptor
    {
        public override void ModifyMetadata(EPiServer.Shell.ObjectEditing.ExtendedMetadata metadata,
            IEnumerable<Attribute> attributes)
        {
            if (metadata.CustomEditorSettings.ContainsKey("uiParams")) {
                object data = metadata.CustomEditorSettings["uiParams"];
                var dictionary = (Dictionary<string, object>)data.GetType().GetProperty("inlineSettings").GetValue(data, null);
                dictionary["body_class"] = dictionary["body_class"] + " " + metadata.PropertyName + " PageText container contentpage " + EPiServer.Web.SiteDefinition.Current.Name;
            }

            if (SiteDefinition.Current.Name.ToLower().Equals("name1"))
                EPiServer.Configuration.Settings.Instance.UIEditorCssPaths = "/content/bootstrap.min.css, " + Combres.WebExtensions.CombresUrl("Name1SiteCss") + "fake.css, /Templates/Public/Styles/Common/tinymce.css";
            else if (SiteDefinition.Current.Name.ToLower().Equals("name2"))
                EPiServer.Configuration.Settings.Instance.UIEditorCssPaths = "/content/bootstrap.min.css, " + Combres.WebExtensions.CombresUrl("Name2SiteCss") + "fake.css, /Templates/Public/Styles/Common/tinymce.css";
            else
                EPiServer.Configuration.Settings.Instance.UIEditorCssPaths = "/content/bootstrap.min.css, " + Combres.WebExtensions.CombresUrl("DefaultSiteCss") + "fake.css, /Templates/Public/Styles/Common/tinymce.css";
        }
    }
 }

Because I want to use this custom change globally i do use EditorDescriptorBehavior.PlaceLast and inherit EditorDescriptor.

The result: Body tag with custom CSS and head with your context based CSS styles.
The result: Body tag with custom CSS and head with your context based CSS styles.

Limitations in UIEditorCssPaths: You can’t have absolute urls nor non file urls (eg not without a file extention)

More reading: