Adding custom valid child tags to EPiServer TinyMCE

In an attempt to prevent TinyMCE from splitting up the p-tags when dropping an EPiServer block into an XHtml property field in edit mode, I tried adding div as a valid child to p within the editor. As we have added custom rendering of your blocks for JSON output (see article React and EPiServer – Custom rendering of EPiServer block in XhtmlString field without partial block controller) it makes sense, I promise. However, it did not quite work as I expected. Here are my findings.

tl;dr It doesn’t work. Not if you want to make invalid markup anyway. It’s probably for the best as it prevents us from getting a solution that never felt right to begin with.

TinyMCE paragraph tags are split into two when dropping an EPiServer block into it

The problem is that when you’re dropping an EPiServer block into an XHtml field, it turns into a div element. So instead of getting the desired, but totally invalid HTML:

<p>aaaa aaaa <div>bbbb</div> cccc cccc</p>

Which the JOS Serializer and our custom implementation would sort out, TinyMCE interferes and we get:

<p>aaaa aaaa</p>
<div>bbbb</div>
<p>cccc cccc</p>

So when the markup is processed and poured into our JSON blob as per the mentioned article, we would get something like this:

<p>aaaa aaaa</p>
<a href="/some/url/">bbbb</a>
<p>cccc cccc</p>

Allowing tags as valid child elements to other tags in EPiServer TinyMCE

So there is some initial configurations which you may pass to TinyMCE that could have sorted this. Either valid_child_elements (before version 3.4 or TinyMCE), or valid_children (from 3.4 and later).

{valid_child_elements:'p[div]'}
{valid_children:'+p[div]'}

Since our version of EPiServer (11 something) uses a version later than 3.4, we would need to use the latter example.

Injecting initial configurations into EPiServer’s TinyMCE editor

This part is easy, just do as you normally do when building plugins to the TinyMCE editor in EPiServer. Add a TinyMCEPluginNonVisual attribute to a class in your solution.

[TinyMCEPluginNonVisual(
  PlugInName = "TinyMceValidChildElements",
  ServerSideOnly = true,
  AlwaysEnabled = true,
  EditorInitConfigurationOptions = "{valid_children:'+p[div]'}")]
public class TinyMceValidChildElements
{
}

The ServerSideOnly option will prevent EPiServer from attempting to access client resources for this plugin, as it won’t have any. In earlier times, you would have to do some work-arounds like adding a custom handler to prevent a 404 response, or other similar stuff.

Set the plugin to AlwaysEnabled and add the desired configurations to the EditorInitConfigurationOptions parameter. When you start EPiServer’s edit mode the config will be injected into TinyMCE.

However, this will not work. You will not be allowed to mess up your markup in a way that would make it invalid, and a div inside a p is invalid. If you would do the same thing for a custom tag like mytag it would work:

{valid_children:'+p[mytag]'}

Would result in:

<p>aaaa aaaa <mytag>bbbb</mytag> cccc cccc</p>

Web.config EPiServer section’s tinyMCE element

There are a lot of articles describing how to add a tinyMCE element to the episerver section of web.config, along with a mergedConfigurationProperties attribute.

<tinyMCE mergedConfigurationProperties="valid_elements, extended_valid_elements, invalid_elements, valid_child_elements" />

This works in EPiServer 10.10.4 (the only assembly I bothered to disassemble while looking for it.

// EPiServer.Configuration.EPiServerSection
[ConfigurationProperty("tinyMCE", IsRequired = false)]
public TinyMCEElement TinyMCESettings
{
  get
  {
    return (TinyMCEElement)base["tinyMCE"];
  }
}

In our version of EPiServer (still 11 something) it has been removed, and you would get the usual unrecognized element exception if you attempt to add it.

Configuration Error

Description: An error occurred during the processing of a configuration file required to service this request. Please review the specific error details below and modify your configuration file appropriately.

Parser Error Message: Unrecognized element 'tinyMCE'.