Try our conversational search powered by Generative AI!

How to trigger content save from custom TinyMCE button (old version)?



I've created a custom button for the TinyMCE editor in Episerver v10 (and therefore using the old verison of TinyMCE). When adding an event handler for the Changed-event, I can see that the modification performed by my button to the contents is seend by TinyMCE. But Episerver doesn't respond to the change (by giving me the possiblity to publish the contents).

The custom button inserts an input-field in the XhtmlString. I use the TinyMCE command mceInsertContent to perform the update. In addition I call ed.undoManager.add() after the update has been completed.

Any ideas on how to make Episerver react on the change?


Bjørn Terje Svennes

Sep 19, 2019 12:56


I can see we do have a hook to TinyMCE's onChange event and then we trigger a save of the new value to the database.

And we also use editor.execCommand('mceInsertContent', false, "stuff") and it works fine.

Are you sure your code looks something like this:

(function (tinymce, $) {
    tinymce.create('tinymce.plugins.epilink', {
        init: function (ed, url) {                        
            ed.addCommand('mceEPiLink', function () {
                ed.execCommand("mceInsertContent", false, "<input type='number' value='123' />");
            ed.addButton('epilink', {
                title: 'epilink.desc',
                cmd: 'mceEPiLink',
                "class": "mce_epilink"
    tinymce.PluginManager.add('epilink', tinymce.plugins.epilink);
}(tinymce, epiJQuery));
Sep 23, 2019 11:58

Hi Bartosz!

Thank you for replying. Below you will find the complete source code. The "special" case with this is that we show an overlay which gives the user some options (for the time beeing it looks awful, but we will fix this later). This might be what causes the issue. 

(function (tinymce) {

    tinymce.create('tinymce.plugins.ContractGeneratorButton', {

        init: function (ed, url) {

            var containerId = 'ContractGenerator_Container';
            var contentId = 'ContractGenerator_Container_Content';
            var insertTextBtnId = 'ContractGenerator_Container_Content_InsertText_Button';
            var insertTextPlaceholderId = 'ContractGenerator_Container_Content_InsertText_Placeholder';
            var insertNumberBtnId = 'ContractGenerator_Container_Content_InsertNumber_Button';
            var insertNumberPlaceholderId = 'ContractGenerator_Container_Content_InsertNumber_Placeholder';
            var insertDateBtnId = 'ContractGenerator_Container_Content_InsertDate_Button';
            var insertDatePlaceholderId = 'ContractGenerator_Container_Content_InsertDate_Placeholder';
            var closeBtnId = 'ContractGenerator_Container_Close';

            ed.onChange.add(function (ed) {

            ed.addCommand('contractGeneratorPluginCmd', function () {

                function uuidv4() {
                    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
                        var v = c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4;
                        return v.toString(16);

                function onContentChanged() {

                function insertContent(content) {
                    ed.execCommand('mceInsertContent', false, content);

                function createElementId(guid) {
                    return 'generator_' + + "_" + guid;

                function createElementName(guid) {
                    return 'generator.' + + "." + guid;

                function constructSelectionDialog() {
                    var root = document.body;

                    var div = document.createElement('div');
                    div.setAttribute('id', containerId);
                    div.setAttribute('style', 'display: block; position: fixed; z-index: 9999;width: 100%;height: 100%;text-align: center;top: 0;left: 0;background: black;background: rgba(0,0,0,0.8);padding-top:120px;');

                    var innerContainer = document.createElement('div');
                    innerContainer.setAttribute('style', 'width: 45%;height: 55%;margin: 0 auto; position: relative;');

                    var content = document.createElement('div');
                    content.setAttribute('style', 'width: 100%;height: 100%;background: white;text-align: left;');
                    content.setAttribute('id', contentId);

                    var textContainer = document.createElement('div');

                    var insertTextPlaceholder = document.createElement('input');
                    insertTextPlaceholder.setAttribute('id', insertTextPlaceholderId);
                    insertTextPlaceholder.setAttribute('type', 'text');
                    insertTextPlaceholder.setAttribute('placeholder', 'Tipstekst');

                    var insertTextBtn = document.createElement('button');
                    insertTextBtn.setAttribute('id', insertTextBtnId);
                    insertTextBtn.innerHTML = 'Text';
                    insertTextBtn.onclick = function () {
                        var guid = uuidv4();
                        insertContent('<input id="' + createElementId(guid) + '" name="' + createElementName(guid) + '" type="text" class="input-inline editor-added" placeholder="' + insertTextPlaceholder.value + '" />');


                    var numberContainer = document.createElement('div');

                    var insertNumberPlaceholder = document.createElement('input');
                    insertNumberPlaceholder.setAttribute('id', insertNumberPlaceholderId);
                    insertNumberPlaceholder.setAttribute('type', 'text');

                    var insertNumberBtn = document.createElement('button');
                    insertNumberBtn.setAttribute('id', insertNumberBtnId);
                    insertNumberBtn.innerHTML = 'Number';
                    insertNumberBtn.onclick = function () {
                        var guid = uuidv4();
                        insertContent('<input id="' + createElementId(guid) + '" name="' + createElementName(guid) + '" type="number" class="input-inline editor-added" placeholder="' + insertNumberPlaceholder.value + '" />');


                    var dateContainer = document.createElement('div');

                    var insertDatePlaceholder = document.createElement('input');
                    insertDatePlaceholder.setAttribute('id', insertDatePlaceholderId);
                    insertDatePlaceholder.setAttribute('type', 'text');
                    insertDatePlaceholder.setAttribute('placeholder', '');
                    insertDatePlaceholder.setAttribute('value', '');

                    var insertDateBtn = document.createElement('button');
                    insertDateBtn.setAttribute('id', insertDateBtnId);
                    insertDateBtn.innerHTML = 'Date';
                    insertDateBtn.onclick = function () {
                        var guid = uuidv4();
                        insertContent('<input id="' + createElementId(guid) + '" name="' + createElementName(guid) + '" type="date" class="input-inline editor-added js-datepicker" placeholder="' + insertDatePlaceholder.value + '" />');



                    var closeBtn = document.createElement('img');
                    closeBtn.setAttribute('src', '/Util/Editor/tinymce/plugins/ContractGeneratorPlugin/images/close-icon.png');
                    closeBtn.setAttribute('id', closeBtnId);
                    closeBtn.setAttribute('style', 'display: block;position: absolute; z-index: 9999;width: 48px;height: 48px; right: -26px;top: -26px;cursor: pointer; ');
                    closeBtn.onclick = function () {



                function unloadFrame() {
                    var root = document.getElementById(containerId);


            ed.addButton('insertContractGeneratorButton', {
                title: 'Insert field',
                cmd: 'contractGeneratorPluginCmd',
                image: '/Util/Editor/tinymce/plugins/ContractGeneratorPlugin/images/cgInsert.png'

    tinymce.PluginManager.add('ContractGeneratorPlugin', tinymce.plugins.ContractGeneratorButton);

Sep 23, 2019 12:35

By replacing the overlay generated by JavaScript with a template using, Episerver finally detected the changes. Not sure why the overlay didn't work, but at least the problem is solved.

Sep 26, 2019 8:25

Yes, for sure you need to use tinymce's windowManager for showing child dialogs. 

I think the problem with your approach was that episerver actually does not support explicit save, instead the save is usually triggered by the 'blur' event on the editor widget.

Adding a custom child dialog, not backed by tinymce's windowManager might have caused issues with focus and the lack of 'blur' event.

Great that you were able to find it out :)

Sep 26, 2019 12:13
This topic was created over six months ago and has been resolved. If you have a similar question, please create a new topic and refer to this one.
* You are NOT allowed to include any hyperlinks in the post because your account hasn't associated to your company. User profile should be updated.