Customizing the HTML editor

HTML may be entered in a field using the TinyMCE wysiwyg editor. Sometimes you may want to customize the behaviour of the editor.

HTML editor configuration

Before you do anything, please check the documentation on the HTML editor we use https://www.tiny.cloud/docs/. Here you can read all about how the editor can be customized. Remember that when you start customizing, the editor may stop working. It is your own responsibility to test it properly. Also keep in mind that customization may, or may not work with particular versions of the HTML editor. However, the HTML editor version used does remain stable within the user interface version of your application.

Note the examples below are valid only for user interfaces from 4.0 and up. We use TinyMCE 5 from UI version 4.0 and up. Before UI 4.0 we used tinyMCE 4. If you are migrating to UI 4.x and have a custom HTML editor configuration, make sure that it is working with TinyMCE 5.

Default configuration

Properties are passed to the editor as a JSON object. Our default configuration looks like this:

{
    "branding": false,
    "entity_encoding": "named",
    "content_css": "default",
    "menu": {
        "edit": {
            "title": "Edit",
            "items": "undo redo | cut copy paste pastetext | selectall | searchreplace"
        },
        "insert": {
            "title": "Insert",
            "items": "media image link | charmap hr anchor insertdatetime"
        },
        "view": {
            "title": "View",
            "items": "visualblocks visualaid | preview fullscreen"
        },
        "format": {
            "title": "Format",
            "items": "bold italic underline strikethrough superscript subscript cx_formatcode | formats | removeformat"    
        },
        "table": {
            "title": "Table",
            "items": "inserttable tableprops deletetable | cell row column"
        },
        "tools": {
            "title": "Tools",
            "items": "code cxhelp"
        }
    },        
    "width": "100%",
    "resize": "both",
    "visual": true,
    "paste_as_text": true,
    "relative_urls": false,
    "valid_children": "+body[style]",
    "convert_urls": false,
    "plugins": "cx_tab_paste noneditable advlist autolink lists link image imagetools charmap preview anchor searchreplace visualblocks code fullscreen insertdatetime media table paste hr crossmarx save wordcount",
    "toolbar": "undo redo | bold italic | forecolor backcolor | bullist numlist outdent indent | alignleft aligncenter alignright alignjustify | link objectfinder | image imagefinder | cx_formatcode",
    "element_format": "html",
    "extended_valid_elements": "span[class|style],img[class|src|border=0|alt|title|hspace|vspace|width|height|align|onmouseover|onmouseout|name|obj|param|embed|style],iframe[align<bottom?left?middle?right?top|class|frameborder|height|id|longdesc|marginheight|marginwidth|name|allowfullscreen|scrolling<auto?no?yes|src|style|title|width],ol[start|style]",
    "table_default_styles": {
        "width": "200px"
    }
}

Left out of the code above is the 'setup' property. This property has a function that sets the form as modified when the editor is not selected anymore. It submits the form if the form requires an auto-submit. The code is a bit too extensive to be shown here. The 'language' property is also left out above. It gets the value of the language set in html element lang attribute.

No custom properties are required to get the HTML editor with default configuration. It will look like this:

Adding or overriding properties

Using the HTML editor configuration field it is possible to add or override properties of the HTML editor. To do this, you will need to use the same property syntax as documented in the TinyMCE documentation. The properties are passed as a JSON object. Any property that doesn't exist yet in the default configuration will be added to the full final configuration. If the property already exists it will be replaced. For example if you want  a HTML editor with limited options in a particular field you can use the following JSON object:

{
    "menubar": false,
    "toolbar": "bold italic underline",
    "valid_elements": "strong,em,span[!style=text-decoration: underline;],br",
    "extended_valid_elements": "",
    "forced_root_block": false,
    "plugins": ""
}

The menu will not be shown and the toolbar is limited to the three buttons in this configuration. The editor only accepts the elements strong, em, span (only if it has text-decoration underline style) and br. We do not want to force root blocks, else you will get a wrapping p element and enters will result in new p elements. Now enters will insert line breaks with the br element.  With this custom configuration the editor will look like this:

Content CSS

In the next example we specifiy a CSS file that will be used to style the content of the HTML editor:

{ 
    "content_css" : "/mijn/content.css"

The file /mijn/content.css looks like this:

h1 {
    color: red;
}
ul {
    list-style-type: none;
    padding-left: 20px;
}
li::before {
    content: "\2764";
    margin-right: 5px;
    color: red;
    -webkit-text-stroke: 1px black;
}

This custom styling makes headings red and shows hearts instead of bullets in front of unordered list items.

We might use this field as the content for a web page. The styling in the editor can be the same (or similar) as the final web page. This way we make the most of the WYSIWYG (What You See Is What You Get) capacities of the HTML editor.

External plugins

If you want to have custom buttons or specific behaviour in the editor, you can make an external plugin. Below is an example of an external plugin, that inserts a HTML fragment into the editor. We specify the following:

{
    "external_plugins": {
        "app_custom_html_fragments": "/tinymce_plugins/app_custom_html_fragments.js"
    },
    "toolbar": "app_fragment"
}

This uses the file /tinymce_plugins/app_custom_html_fragments.js to add the plugin "app_custom_html_fragments" to the tinymce PluginManager. 

tinymce.PluginManager.add('app_custom_html_fragments', function(editor) {
     
    /* Add the fragment */
    function addHTMLFragment(fragment, inline) {
        var range = editor.selection.getRng();
        var nextSiblingElement = range.startContainer.nextElementSibling;
        if (inline) {
            // do not add a <p> after inline elements    
        } else if (!nextSiblingElement) {
            fragment += '<p></p>'; // if there is no next element add <p> to break free
        }
        editor.execCommand('mceInsertContent', false, fragment);
    } 
        
    /* Add Toolbar button */
    editor.ui.registry.addButton('app_fragment', {
        text: 'insert html fragment',
        onAction: function () {
            addHTMLFragment("<b>Some custom HTML</b>");
        }
    });            
});

In the file we add the button inserthtmlfragment to the registry. This is the button that will be shown in the toolbar. It has a text property that will be shown on the button. It has a onAction property with a function that is triggered when the button is pressed. In this case it will run the addHTMLFragment function to insert the fragment in the HTML editor.