Blog about tips & tricks for CMS enhancement

eric.petersson

Preview blocks and TinyMCE with your site styles


In this post I will just give a simple tip on how to approach an implementation on how to keep your editing preview in the edit mode similiar to your site styles in Episerver.

We will fix the sketchy TinyMCE styles from the iframe styles in Episerver:
not_same_styles_tinyMCE

Into this:
same_styles_tinyMCE

Custom CSS wrapper class

Patrick van Kleef showed how you may extend your TinyMCE editing of custom CSS styles when working in the iframed block preview in edit mode for XhtmlStrings. This has been changed by Episerver since then. The code below is the new way to achieve this:

using EPiServer.Cms.Shell.Extensions;
using EPiServer.Cms.Shell.UI.ObjectEditing;
using EPiServer.Cms.TinyMce.Core;
using EPiServer.Configuration;
using EPiServer.Core;
using EPiServer.Editor.TinyMCE;
using EPiServer.Shell.ObjectEditing;
using EPiServer.Shell.ObjectEditing.EditorDescriptors;
using EPiServer.UI;
using System;
using System.Collections.Generic;

namespace My.Webapplication
{
    [EditorDescriptorRegistration(TargetType = typeof(XhtmlString), UIHint = "my-custom-xhtmlstring")]
    public class CustomXhtmlStringEditorDescriptor : XhtmlStringEditorDescriptor
    {
        private readonly PropertySettingsRepositoryHelper _propertySettingsRepositoryHelper;

        private readonly Settings _configurationSettings;

        public CustomXhtmlStringEditorDescriptor() : base()
        {

        }

        public CustomXhtmlStringEditorDescriptor(PropertySettingsRepositoryHelper propertySettingsRepositoryHelper, Settings settings)
        {
            _propertySettingsRepositoryHelper = propertySettingsRepositoryHelper;
            _configurationSettings = settings;
        }

        public override void ModifyMetadata(ExtendedMetadata metadata, IEnumerable<Attribute> attributes)
        {
            base.ModifyMetadata(metadata, attributes);
            
            PropertyData propertyData = metadata.Model as PropertyData;
            Guid settingsID = (propertyData != null) ? propertyData.GetSettingsID() : Guid.Empty;
            TinyMCESettings tinyMCESettings = _propertySettingsRepositoryHelper.GetSettingsWrapper(settingsID, typeof(TinyMCESettings), attributes).PropertySettings as TinyMCESettings;
            ContentDataMetadata contentDataMetadata = metadata as ContentDataMetadata;

            ExtendedMetadata extendedMetadata = null;

            if (contentDataMetadata != null)
            {
                extendedMetadata = contentDataMetadata.FindTopMostContentMetadata();
            }

            IContent content = (extendedMetadata != null) ? (extendedMetadata.Model as IContent) : null;
            TinyMCEInitOptions tinyMCEInitOptions = new TinyMCEInitOptions(TinyMCEInitOptions.InitType.EditMode, tinyMCESettings, content);

            Dictionary<string, object> dictionary = new Dictionary<string, object>();
            object obj = tinyMCEInitOptions.InitOptions.ContainsKey("body_class") ? tinyMCEInitOptions.InitOptions["body_class"] : string.Empty;

            dictionary.Add("body_class", string.Join(" ", new object[]
             { "custom-wrapper-class", obj
             }).TrimEnd(Array.Empty<char>()));

            metadata.CustomEditorSettings["uiParams"] = new
            {
                inlineSettings = dictionary
            };
        }
    }
}

And in your property decoration add the UIHint of "my-custom-xhtmlstring":

[UIHint("my-custom-xhtmlstring")]
        [Display(
            GroupName = SystemTabNames.Content,
            Order = 30)]
        public virtual XhtmlString MainBody { get; set; }

Other approach with custom Editor stylesheet

If you did not have a styled wrapper class to fallback to you may end up with this solution instead. In my case, I needed to extend the base elements to be associated with the TinyMCE and had not a css class to fall back to. I ended up with associating the same styles in the Editor.css for the backend style formats.

As you can see, this is for the old TinyMCE extension (1.x.x) and not the new v.2.x.x which is accessible through Nuget. This works however the same way by associating your custom css stylesheet.

In my Editor.css, which is the provided css stylesheet to be loaded for the TinyMCE formats:

h1, h2, h3, h4, h5, h6 {
    font-family: "Open Sans", Helvetica, Arial, sans-serif;
    margin-bottom: 13;
    margin-left: 0px;
    margin-right: 0px;
    margin-top: 24px;
    line-height: 33px;
    letter-spacing: 0.35px;
    display: block;
}

p {
    font-family: "Open Sans", Helvetica, Arial, sans-serif;
    margin: 0 0 12px;
    font-size: 20px;
    font-weight: 400;
    line-height: 32px;
    letter-spacing: 0.35px;
    color: #000;
    display: block;
}

h2 {
    EditMenuTitle: Headlines;
    EditMenuName: Headline_2;
    font-size: 36px;
    font-weight: 600;
    line-height: 46.8px;
}

h3 {
    EditMenuName: Headline_3;
    font-size: 24px;
    font-weight: 600;
}

h4 {
    EditMenuName: Headline_4;
    font-size: 24px;
    font-weight: 600;
}

h5 {
    EditMenuName: Headline_5;
}

h6 {
    EditMenuName: Headline_6;
}

If you're working with Less or Sass and generate each file as a seperate CSS file, you may associate these instead of cluttering your Editor.css with the same behaviour as your site styles.

@import url("your_location_path_to_stylesheet");

h2 {
    EditMenuTitle: Headlines;
    EditMenuName: Headline_2;
}

h3 {
    EditMenuName: Headline_3;
}

h4 {
    EditMenuName: Headline_4;
}

h5 {
    EditMenuName: Headline_5;
}

h6 {
    EditMenuName: Headline_6;
}