Is it possible to customize TinyMCE HTML Editor?

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎09-12-2014 11:00 AM
The TinyMCE editor is the default for HTML fields. As TinyMCE is an Open Source project (TinyMCE - Develop) it looks like changes to the code are supported. I'm curious if anyone has made changes (to create custom buttons, for example, not just adding or removing existing buttons), and what the process would be to get the new code into ServiceNow, as TinyMCE is currently added as a plugin. I'm assuming Support would need to be involved.

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎09-12-2014 01:07 PM
I did find this article, which seems to still be an open discussion without a definitive answer other than a new workaround:I have seen that TinyMCE is
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎12-18-2014 03:22 PM
Hi Erik,
It doesn't seem as though this would be easy to accomplish with OOB HTML fields. Using custom widgets (Formatters and UI Macros) I am sure much more would be possible. ServiceNow's implementation of the TinyMCE editor is initialized in a self contained function in the render events. This makes it very difficult to hook into the init of the editor and of course TinyMCE is designed to make most meaningful changes at init, not dynamically. So unless ServiceNow gives us the ability to hook into some things or adds properties, we are left with either hacking into the editor or initializing our own separate editor (where we would presumably tie it to a normal text field).
There are some settings that can be changed and you can also wire into some of the events. So there are some changes you can make. But to add plugins and such, you would probably have to find a way to destroy the editor (easy: tinymce.EditorManager.editors[0].destroy()) and then reinitialize it (more complicated tinyMCE configuration + TinyMCETextAreaElement).
Hope this information is helpful.
Kind regards,
Travis

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎04-03-2017 10:37 AM
I wanted to remove the Source Code button from an HTML field on a Catalog Item:
So here's what I did to make it work: (Catalog Client Script (onLoad)):
var __sTO;
var __ticks = 0;
function onLoad()
{
__sTO = setTimeout(function(){ removeSourceCodeButton(); }, 100);
}
function removeSourceCodeButton()
{
__ticks++;
var cleared = false;
var divs = document.getElementsByTagName('div');
for (var i = 0; i < divs.length; i++)
{
if (divs[i].id && divs[i].id.indexOf('mceu_') == 0)
{
if (divs[i].outerHTML.indexOf('Source code') >= 0 && divs[i].outerHTML.indexOf('mce-i-code') >= 0)
{
if (divs[i].outerHTML.indexOf('Source code') >= 0 && divs[i].outerHTML.indexOf('mce-i-code') >= 0 && divs[i].innerHTML.indexOf('<button') == 0)
{
divs[i].parentNode.removeChild(divs[i]);
clearTimeout(__sTO);
cleared = true;
break;
}
}
}
}
if (!cleared)
{
clearTimeout(__sTO);
__sTO = setTimeout(function(){ removeSourceCodeButton(); }, 100);
}
// Safety
if (__ticks >= 50) // 5 seconds
{
console.debug("Safety Cleared __sTO");
clearTimeout(__sTO);
}
}

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎04-03-2017 12:04 PM
Oh, and here's a way you can do multiple buttons:
var __sTO;
var __ticks = 0;
var __verify = [];
function onLoad()
{
__sTO = setTimeout(function(){ removeUnwantedButtons(); }, 100);
}
function removeUnwantedButtons()
{
// Safety
if (++__ticks >= 50) // 5 seconds
{
console.debug("Safety Cleared __sTO");
clearTimeout(__sTO);
return;
}
var breakOut = false;
var btnsA = [];
btnsA.push({Name:'Source code', Class:'mce-i-code'},
{Name:'Insert/edit video', Class:'mce-i-media'},
{Name:'Insert/edit image', Class:'mce-i-image'},
{Name:'Insert/edit link', Class:'mce-i-link'},
{Name:'Remove link', Class:'mce-i-unlink'});
var divs = document.getElementsByTagName('div');
for (var i = 0; i < divs.length && !breakOut; i++)
{
if (divs[i].id && divs[i].id.indexOf('mceu_') == 0)
{
for (var a = 0; a < btnsA.length && !breakOut; a++)
{
if (divs[i].childNodes.length &&
divs[i].outerHTML.indexOf(btnsA[a].Name) >= 0 &&
divs[i].outerHTML.indexOf(btnsA[a].Class) >= 0 &&
divs[i].innerHTML.indexOf('<button') == 0 &&
divs[i].childNodes[0].innerHTML.indexOf(btnsA[a].Class) >= 1 &&
divs[i].childNodes[0].innerHTML.indexOf('<i') == 0)
{
__verify.push(btnsA[a].Name + '(' + divs[i].id.toString() + ')');
divs[i].parentNode.removeChild(divs[i]);
breakOut = true;
}
}
}
}
if (__verify.length == btnsA.length)
{
clearTimeout(__sTO);
for (var v = 0; v < __verify.length; v++)
{
console.debug('Button ' + __verify[v] + ' successfully removed.');
}
__verify = [];
return;
}
else
{
clearTimeout(__sTO);
__sTO = setTimeout(function(){ removeUnwantedButtons(); }, 100);
}
}